multilib mode
[wxWidgets.git] / src / cocoa / window.mm
CommitLineData
fb896a32
DE
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/cocoa/window.mm
3// Purpose: wxWindowCocoa
4// Author: David Elliott
5// Modified by:
6// Created: 2002/12/26
7// RCS-ID: $Id:
8// Copyright: (c) 2002 David Elliott
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/window.h"
13#include "wx/log.h"
14
7fc77f30
DE
15#include "wx/cocoa/autorelease.h"
16
fb896a32 17#import <Appkit/NSView.h>
69dbb709 18#import <AppKit/NSEvent.h>
fb896a32
DE
19
20// normally the base classes aren't included, but wxWindow is special
21#ifdef __WXUNIVERSAL__
22IMPLEMENT_ABSTRACT_CLASS(wxWindowCocoa, wxWindowBase)
23#else
24IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
25#endif
26
27BEGIN_EVENT_TABLE(wxWindowCocoa, wxWindowBase)
28END_EVENT_TABLE()
29
b9505233
DE
30wxWindow *wxWindowCocoa::sm_capturedWindow = NULL;
31
fb896a32
DE
32// Constructor
33void wxWindowCocoa::Init()
34{
35 InitBase();
36
37 m_cocoaNSView = NULL;
38 m_dummyNSView = NULL;
39 m_isBeingDeleted = FALSE;
55c5be5e 40 m_isInPaint = FALSE;
fb896a32
DE
41}
42
43// Constructor
44bool wxWindow::Create(wxWindow *parent, wxWindowID winid,
45 const wxPoint& pos,
46 const wxSize& size,
47 long style,
48 const wxString& name)
49{
50 if(!CreateBase(parent,winid,pos,size,style,wxDefaultValidator,name))
51 return false;
52
53 // TODO: create the window
54 NSRect cocoaRect = NSMakeRect(10,10,20,20);
55 m_cocoaNSView = NULL;
56 SetNSView([[NSView alloc] initWithFrame: cocoaRect]);
57 [m_cocoaNSView release];
58
59 if (m_parent)
60 {
61 m_parent->AddChild(this);
62 m_parent->CocoaAddChild(this);
63 }
64
65 return TRUE;
66}
67
68// Destructor
69wxWindow::~wxWindow()
70{
7fc77f30 71 wxAutoNSAutoreleasePool pool;
fb896a32
DE
72 DestroyChildren();
73
74 if(m_parent)
75 m_parent->RemoveChild(this);
76
77 CocoaRemoveFromParent();
78 SetNSView(NULL);
79}
80
81void wxWindowCocoa::CocoaAddChild(wxWindowCocoa *child)
82{
83 [child->m_cocoaNSView retain];
84 // NOTE: addSubView takes ownership of, but does not retain the subview
85 // Upon a removeFromView or closing the super view, the child WILL be
86 // released!!! I think the idea here is that normally you would alloc
87 // the subview and add it to the superview and this way you don't have
88 // to release what you just alloced. Unfortunately, that doesn't
89 // make sense for wxCocoa, so we do this instead.
90 [m_cocoaNSView addSubview: child->m_cocoaNSView];
91 wxASSERT(!child->m_dummyNSView);
92 child->m_isShown = true;
93}
94
95void wxWindowCocoa::CocoaRemoveFromParent(void)
96{
fb896a32
DE
97 if(m_dummyNSView)
98 {
c1f7d193 99 wxASSERT(m_cocoaNSView);
fb896a32
DE
100 // balances the alloc
101 [m_dummyNSView removeFromSuperview];
102 // But since we also retained it ourselves
103 [m_dummyNSView release];
104 m_dummyNSView = nil;
105 // m_cocoaNSView has of course already been removed by virtue of
106 // replaceSubview: m_cocoaNSView with: m_dummyNSView
107 }
108 else
109 [m_cocoaNSView removeFromSuperview];
110}
111
112void wxWindowCocoa::SetNSView(WX_NSView cocoaNSView)
113{
114 bool need_debug = cocoaNSView || m_cocoaNSView;
115 if(need_debug) wxLogDebug("wxWindowCocoa=%p::SetNSView [m_cocoaNSView=%p retainCount]=%d",this,m_cocoaNSView,[m_cocoaNSView retainCount]);
bac6f234 116 DisassociateNSView(m_cocoaNSView);
fb896a32
DE
117 [cocoaNSView retain];
118 [m_cocoaNSView release];
119 m_cocoaNSView = cocoaNSView;
bac6f234 120 AssociateNSView(m_cocoaNSView);
fb896a32
DE
121 if(need_debug) wxLogDebug("wxWindowCocoa=%p::SetNSView [cocoaNSView=%p retainCount]=%d",this,cocoaNSView,[cocoaNSView retainCount]);
122}
123
8ea5271e
DE
124bool wxWindowCocoa::Cocoa_drawRect(const NSRect &rect)
125{
126 wxLogDebug("Cocoa_drawRect");
55c5be5e
DE
127 // Recursion can happen if the event loop runs from within the paint
128 // handler. For instance, if an assertion dialog is shown.
129 // FIXME: This seems less than ideal.
130 if(m_isInPaint)
131 {
132 wxLogDebug("Paint event recursion!");
133 return false;
134 }
8ea5271e 135 //FIXME: should probably turn that rect into the update region
55c5be5e 136 m_isInPaint = TRUE;
8ea5271e
DE
137 wxPaintEvent event(m_windowId);
138 event.SetEventObject(this);
55c5be5e
DE
139 bool ret = GetEventHandler()->ProcessEvent(event);
140 m_isInPaint = FALSE;
141 return ret;
8ea5271e
DE
142}
143
69dbb709
DE
144void wxWindowCocoa::InitMouseEvent(wxMouseEvent& event, WX_NSEvent cocoaEvent)
145{
146 NSView *nsview = m_dummyNSView?m_dummyNSView:m_cocoaNSView;
147 wxASSERT_MSG([nsview window]==[cocoaEvent window],"Mouse event for different NSWindow");
148 NSPoint cocoaPoint = [nsview convertPoint:[(NSEvent*)cocoaEvent locationInWindow] fromView:nil];
149 NSRect cocoaRect = [nsview frame];
150 const wxPoint &clientorigin = GetClientAreaOrigin();
151 event.m_x = (wxCoord)cocoaPoint.x - clientorigin.x;
152 event.m_y = (wxCoord)(cocoaRect.size.height - cocoaPoint.y) - clientorigin.y;
153
154 event.m_shiftDown = [cocoaEvent modifierFlags] & NSShiftKeyMask;
155 event.m_controlDown = [cocoaEvent modifierFlags] & NSControlKeyMask;
156 event.m_altDown = [cocoaEvent modifierFlags] & NSAlternateKeyMask;
157 event.m_metaDown = [cocoaEvent modifierFlags] & NSCommandKeyMask;
158
159 // TODO: set timestamp?
160 event.SetEventObject(this);
161 event.SetId(GetId());
162}
163
164bool wxWindowCocoa::Cocoa_mouseMoved(WX_NSEvent theEvent)
165{
166 wxMouseEvent event(wxEVT_MOTION);
167 InitMouseEvent(event,theEvent);
168 wxLogDebug("Mouse Drag @%d,%d",event.m_x,event.m_y);
169 return GetEventHandler()->ProcessEvent(event);
170}
171
172bool wxWindowCocoa::Cocoa_mouseEntered(WX_NSEvent theEvent)
173{
174 return false;
175}
176
177bool wxWindowCocoa::Cocoa_mouseExited(WX_NSEvent theEvent)
178{
179 return false;
180}
181
182bool wxWindowCocoa::Cocoa_mouseDown(WX_NSEvent theEvent)
183{
184 wxMouseEvent event([theEvent clickCount]<2?wxEVT_LEFT_DOWN:wxEVT_LEFT_DCLICK);
185 InitMouseEvent(event,theEvent);
186 wxLogDebug("Mouse Down @%d,%d num clicks=%d",event.m_x,event.m_y,[theEvent clickCount]);
187 return GetEventHandler()->ProcessEvent(event);
188}
189
190bool wxWindowCocoa::Cocoa_mouseDragged(WX_NSEvent theEvent)
191{
192 wxMouseEvent event(wxEVT_MOTION);
193 InitMouseEvent(event,theEvent);
194 event.m_leftDown = true;
195 wxLogDebug("Mouse Drag @%d,%d",event.m_x,event.m_y);
196 return GetEventHandler()->ProcessEvent(event);
197}
198
199bool wxWindowCocoa::Cocoa_mouseUp(WX_NSEvent theEvent)
200{
201 wxMouseEvent event(wxEVT_LEFT_UP);
202 InitMouseEvent(event,theEvent);
203 wxLogDebug("Mouse Up @%d,%d",event.m_x,event.m_y);
204 return GetEventHandler()->ProcessEvent(event);
205}
206
207bool wxWindowCocoa::Cocoa_rightMouseDown(WX_NSEvent theEvent)
208{
209 return false;
210}
211
212bool wxWindowCocoa::Cocoa_rightMouseDragged(WX_NSEvent theEvent)
213{
214 return false;
215}
216
217bool wxWindowCocoa::Cocoa_rightMouseUp(WX_NSEvent theEvent)
218{
219 return false;
220}
221
222bool wxWindowCocoa::Cocoa_otherMouseDown(WX_NSEvent theEvent)
223{
224 return false;
225}
226
227bool wxWindowCocoa::Cocoa_otherMouseDragged(WX_NSEvent theEvent)
228{
229 return false;
230}
231
232bool wxWindowCocoa::Cocoa_otherMouseUp(WX_NSEvent theEvent)
233{
234 return false;
235}
236
fb896a32
DE
237void wxWindowCocoa::Cocoa_FrameChanged(void)
238{
239 wxLogDebug("Cocoa_FrameChanged");
240 wxSizeEvent event(GetSize(), m_windowId);
241 event.SetEventObject(this);
242 GetEventHandler()->ProcessEvent(event);
243}
244
245bool wxWindow::Close(bool force)
246{
247 return false;
248}
249
250bool wxWindow::Show(bool show)
251{
7fc77f30 252 wxAutoNSAutoreleasePool pool;
fb896a32
DE
253 // If the window is marked as visible, then it shouldn't have a dummy view
254 // If the window is marked hidden, then it should have a dummy view
addbdd29
DE
255 // wxSpinCtrl (generic) abuses m_isShown, don't use it for any logic
256// wxASSERT_MSG( (m_isShown && !m_dummyNSView) || (!m_isShown && m_dummyNSView),"wxWindow: m_isShown does not agree with m_dummyNSView");
fb896a32
DE
257 // Return false if there isn't a window to show or hide
258 if(!m_cocoaNSView)
259 return false;
fb896a32
DE
260 if(show)
261 {
addbdd29
DE
262 // If state isn't changing, return false
263 if(!m_dummyNSView)
264 return false;
fb896a32
DE
265 // replaceSubView releases m_dummyNSView, balancing the alloc
266 [m_cocoaNSView retain];
267 [[m_dummyNSView superview] replaceSubview:m_dummyNSView with:m_cocoaNSView];
268 // But since we also retained it ourselves
69dbb709 269 wxASSERT(![m_dummyNSView superview]);
fb896a32
DE
270 [m_dummyNSView release];
271 m_dummyNSView = nil;
69dbb709 272 wxASSERT([m_cocoaNSView superview]);
fb896a32
DE
273 }
274 else
275 {
addbdd29
DE
276 // If state isn't changing, return false
277 if(m_dummyNSView)
278 return false;
fb896a32
DE
279 m_dummyNSView = [[NSView alloc] initWithFrame: [m_cocoaNSView frame]];
280 [m_dummyNSView retain];
281 // NOTE: replaceSubView will cause m_cocaNSView to be released
282 [[m_cocoaNSView superview] replaceSubview:m_cocoaNSView with:m_dummyNSView];
283 // m_coocaNSView is now only retained by us
69dbb709
DE
284 wxASSERT([m_dummyNSView superview]);
285 wxASSERT(![m_cocoaNSView superview]);
fb896a32 286 }
a6b4ff2e
DE
287 m_isShown = show;
288 return true;
fb896a32
DE
289}
290
291void wxWindowCocoa::DoSetSize(int x, int y, int width, int height, int sizeFlags)
292{
ddf7346a 293// wxLogDebug("wxWindow=%p::DoSetSizeWindow(%d,%d,%d,%d,Auto: %s%s)",this,x,y,width,height,(sizeFlags&wxSIZE_AUTO_WIDTH)?"W":".",sizeFlags&wxSIZE_AUTO_HEIGHT?"H":".");
fb896a32
DE
294 int currentX, currentY;
295 int currentW, currentH;
296 DoGetPosition(&currentX, &currentY);
297 DoGetSize(&currentW, &currentH);
298 if((x==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
299 x=currentX;
300 if((y==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
301 y=currentY;
302
303 AdjustForParentClientOrigin(x,y,sizeFlags);
304
305 wxSize size(-1,-1);
306
307 if((width==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
308 {
309 if(sizeFlags&wxSIZE_AUTO_WIDTH)
310 {
311 size=DoGetBestSize();
312 width=size.x;
313 }
314 else
315 width=currentW;
316 }
317 if((height==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
318 {
319 if(sizeFlags&wxSIZE_AUTO_HEIGHT)
320 {
321 if(size.x==-1)
322 size=DoGetBestSize();
323 height=size.y;
324 }
325 else
326 height=currentH;
327 }
328 DoMoveWindow(x,y,width,height);
329}
330
331void wxWindowCocoa::DoMoveWindow(int x, int y, int width, int height)
332{
ddf7346a 333// wxLogDebug("wxWindow=%p::DoMoveWindow(%d,%d,%d,%d)",this,x,y,width,height);
fb896a32 334
d449cf47
DE
335 NSView *nsview = m_dummyNSView?m_dummyNSView:m_cocoaNSView;
336 NSView *superview = [nsview superview];
fb896a32
DE
337 wxCHECK_RET(superview,"NSView does not have a superview");
338 NSRect parentRect = [superview frame];
339
340 NSRect cocoaRect = NSMakeRect(x,parentRect.size.height-(y+height),width,height);
341 [m_cocoaNSView setFrame: cocoaRect];
342 // Also change the dummy's size
343 if(m_dummyNSView)
344 [m_dummyNSView setFrame: cocoaRect];
345}
346
347// Get total size
348void wxWindow::DoGetSize(int *w, int *h) const
349{
350 NSRect cocoaRect = [m_cocoaNSView frame];
351 if(w)
352 *w=(int)cocoaRect.size.width;
353 if(h)
354 *h=(int)cocoaRect.size.height;
ddf7346a 355// wxLogDebug("wxWindow=%p::DoGetSize = (%d,%d)",this,(int)cocoaRect.size.width,(int)cocoaRect.size.height);
fb896a32
DE
356}
357
358void wxWindow::DoGetPosition(int *x, int *y) const
359{
576a1544
DE
360 NSView *nsview = m_dummyNSView?m_dummyNSView:m_cocoaNSView;
361 NSView *superview = [nsview superview];
fb896a32
DE
362 wxCHECK_RET(superview,"NSView does not have a superview");
363 NSRect parentRect = [superview frame];
364
576a1544 365 NSRect cocoaRect = [nsview frame];
fb896a32
DE
366 if(x)
367 *x=(int)cocoaRect.origin.x;
368 if(y)
369 *y=(int)(parentRect.size.height-(cocoaRect.origin.y+cocoaRect.size.height));
ddf7346a 370// wxLogDebug("wxWindow=%p::DoGetPosition = (%d,%d)",this,(int)cocoaRect.origin.x,(int)cocoaRect.origin.y);
fb896a32
DE
371}
372
373WXWidget wxWindow::GetHandle() const
374{
375 return m_cocoaNSView;
376}
377
ddf7346a
DE
378void wxWindow::Refresh(bool eraseBack, const wxRect *rect)
379{
380 [m_cocoaNSView setNeedsDisplay:YES];
381}
382
fb896a32
DE
383void wxWindow::SetFocus()
384{
385 // TODO
386}
387
388void wxWindow::DoCaptureMouse()
389{
390 // TODO
b9505233 391 sm_capturedWindow = this;
fb896a32
DE
392}
393
394void wxWindow::DoReleaseMouse()
395{
396 // TODO
b9505233 397 sm_capturedWindow = NULL;
fb896a32
DE
398}
399
400void wxWindow::DoScreenToClient(int *x, int *y) const
401{
402 // TODO
403}
404
405void wxWindow::DoClientToScreen(int *x, int *y) const
406{
407 // TODO
408}
409
410// Get size *available for subwindows* i.e. excluding menu bar etc.
411void wxWindow::DoGetClientSize(int *x, int *y) const
412{
413 wxLogDebug("DoGetClientSize:");
414 wxWindowCocoa::DoGetSize(x,y);
415 // TODO: Actually account for menubar, borders, etc...
416}
417
418void wxWindow::DoSetClientSize(int width, int height)
419{
420 wxLogDebug("DoSetClientSize=(%d,%d)",width,height);
421 // TODO
422}
423
424int wxWindow::GetCharHeight() const
425{
426 // TODO
427 return 0;
428}
429
430int wxWindow::GetCharWidth() const
431{
432 // TODO
433 return 0;
434}
435
436void wxWindow::GetTextExtent(const wxString& string, int *x, int *y,
437 int *descent, int *externalLeading, const wxFont *theFont) const
438{
439 // TODO
440}
441
fb896a32
DE
442// Coordinates relative to the window
443void wxWindow::WarpPointer (int x_pos, int y_pos)
444{
445 // TODO
446}
447
448int wxWindow::GetScrollPos(int orient) const
449{
450 // TODO
451 return 0;
452}
453
454// This now returns the whole range, not just the number
455// of positions that we can scroll.
456int wxWindow::GetScrollRange(int orient) const
457{
458 // TODO
459 return 0;
460}
461
462int wxWindow::GetScrollThumb(int orient) const
463{
464 // TODO
465 return 0;
466}
467
468void wxWindow::SetScrollPos(int orient, int pos, bool refresh)
469{
470 // TODO
471}
472
473// New function that will replace some of the above.
474void wxWindow::SetScrollbar(int orient, int pos, int thumbVisible,
475 int range, bool refresh)
476{
477 // TODO
478}
479
480// Does a physical scroll
481void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect)
482{
483 // TODO
484}
485
486bool wxWindow::SetFont(const wxFont& font)
487{
488 // TODO
489 return TRUE;
490}
491
492void wxWindow::Clear()
493{
494 // TODO
495}
496
497// Raise the window to the top of the Z order
498void wxWindow::Raise()
499{
7fc77f30 500 wxAutoNSAutoreleasePool pool;
d5ca6629
DE
501 NSView *nsview = m_dummyNSView?m_dummyNSView:m_cocoaNSView;
502 NSView *superview = [nsview superview];
503 [nsview retain];
504 [nsview removeFromSuperview];
505 [superview addSubview:nsview];
fb896a32
DE
506}
507
508// Lower the window to the bottom of the Z order
509void wxWindow::Lower()
510{
511 // TODO
512}
513
514bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
515{
516 return FALSE;
517}
518
519// Get the window with the focus
520wxWindow *wxWindowBase::FindFocus()
521{
522 // TODO
523 return NULL;
524}
525
526/* static */ wxWindow *wxWindowBase::GetCapture()
527{
528 // TODO
b9505233 529 return wxWindowCocoa::sm_capturedWindow;
fb896a32
DE
530}
531
532wxWindow *wxGetActiveWindow()
533{
534 // TODO
535 return NULL;
536}
537
7c9428ab
DE
538wxPoint wxGetMousePosition()
539{
540 // TODO
541 return wxDefaultPosition;
542}
543
544wxWindow* wxFindWindowAtPointer(wxPoint& pt)
545{
546 pt = wxGetMousePosition();
547 return NULL;
548}
549