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