going private for m_peer to give a foundation for better encapsulation
[wxWidgets.git] / src / osx / nonownedwnd_osx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/nonownedwnd_osx.cpp
3 // Purpose: implementation of wxNonOwnedWindow
4 // Author: Stefan Csomor
5 // Created: 2008-03-24
6 // RCS-ID: $Id$
7 // Copyright: (c) Stefan Csomor 2008
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #ifndef WX_PRECOMP
15 #include "wx/app.h"
16 #include "wx/log.h"
17 #endif // WX_PRECOMP
18
19 #include "wx/hashmap.h"
20 #include "wx/evtloop.h"
21 #include "wx/tooltip.h"
22 #include "wx/nonownedwnd.h"
23
24 #include "wx/osx/private.h"
25 #include "wx/settings.h"
26 #include "wx/frame.h"
27
28 #if wxUSE_SYSTEM_OPTIONS
29 #include "wx/sysopt.h"
30 #endif
31
32 // ----------------------------------------------------------------------------
33 // constants
34 // ----------------------------------------------------------------------------
35
36 // trace mask for activation tracing messages
37 #define TRACE_ACTIVATE "activation"
38
39 wxWindow* g_MacLastWindow = NULL ;
40
41 // unified title and toolbar constant - not in Tiger headers, so we duplicate it here
42 #define kWindowUnifiedTitleAndToolbarAttribute (1 << 7)
43
44 // ---------------------------------------------------------------------------
45 // wxWindowMac utility functions
46 // ---------------------------------------------------------------------------
47
48 WX_DECLARE_HASH_MAP(WXWindow, wxNonOwnedWindowImpl*, wxPointerHash, wxPointerEqual, MacWindowMap);
49
50 static MacWindowMap wxWinMacWindowList;
51
52 wxNonOwnedWindow* wxNonOwnedWindow::GetFromWXWindow( WXWindow win )
53 {
54 wxNonOwnedWindowImpl* impl = wxNonOwnedWindowImpl::FindFromWXWindow(win);
55
56 return ( impl != NULL ? impl->GetWXPeer() : NULL ) ;
57 }
58
59 wxNonOwnedWindowImpl* wxNonOwnedWindowImpl::FindFromWXWindow (WXWindow window)
60 {
61 MacWindowMap::iterator node = wxWinMacWindowList.find(window);
62
63 return (node == wxWinMacWindowList.end()) ? NULL : node->second;
64 }
65
66 void wxNonOwnedWindowImpl::RemoveAssociations( wxNonOwnedWindowImpl* impl)
67 {
68 MacWindowMap::iterator it;
69 for ( it = wxWinMacWindowList.begin(); it != wxWinMacWindowList.end(); ++it )
70 {
71 if ( it->second == impl )
72 {
73 wxWinMacWindowList.erase(it);
74 break;
75 }
76 }
77 }
78
79 void wxNonOwnedWindowImpl::Associate( WXWindow window, wxNonOwnedWindowImpl *impl )
80 {
81 // adding NULL WindowRef is (first) surely a result of an error and
82 // nothing else :-)
83 wxCHECK_RET( window != (WXWindow) NULL, wxT("attempt to add a NULL WindowRef to window list") );
84
85 wxWinMacWindowList[window] = impl;
86 }
87
88 // ----------------------------------------------------------------------------
89 // wxNonOwnedWindow creation
90 // ----------------------------------------------------------------------------
91
92 IMPLEMENT_ABSTRACT_CLASS( wxNonOwnedWindowImpl , wxObject )
93
94 wxNonOwnedWindow *wxNonOwnedWindow::s_macDeactivateWindow = NULL;
95
96 void wxNonOwnedWindow::Init()
97 {
98 m_nowpeer = NULL;
99 m_isNativeWindowWrapper = false;
100 }
101
102 bool wxNonOwnedWindow::Create(wxWindow *parent,
103 wxWindowID id,
104 const wxPoint& posOrig,
105 const wxSize& sizeOrig,
106 long style,
107 const wxString& name)
108 {
109 m_windowStyle = style;
110
111 SetName( name );
112
113 m_windowId = id == -1 ? NewControlId() : id;
114 m_windowStyle = style;
115 m_isShown = false;
116
117 // use the appropriate defaults for the position and size if necessary
118 wxSize size(sizeOrig);
119 if ( !size.IsFullySpecified() )
120 size.SetDefaults(wxTopLevelWindow::GetDefaultSize());
121
122 wxPoint pos(posOrig);
123 if ( !pos.IsFullySpecified() )
124 {
125 wxRect rectWin = wxRect(size).CentreIn(wxGetClientDisplayRect());
126
127 // The size of the window is often not really known yet, TLWs are often
128 // created with some small initial size and later are fitted to contain
129 // their children so centering the window will show it too much to the
130 // right and bottom, adjust for it by putting it more to the left and
131 // center.
132 rectWin.x /= 2;
133 rectWin.y /= 2;
134
135 pos.SetDefaults(rectWin.GetPosition());
136 }
137
138 // create frame.
139 m_nowpeer = wxNonOwnedWindowImpl::CreateNonOwnedWindow
140 (
141 this, parent,
142 pos , size,
143 style, GetExtraStyle(),
144 name
145 );
146 wxNonOwnedWindowImpl::Associate( m_nowpeer->GetWXWindow() , m_nowpeer ) ;
147 SetPeer(wxWidgetImpl::CreateContentView(this));
148
149 DoSetWindowVariant( m_windowVariant ) ;
150
151 wxWindowCreateEvent event(this);
152 HandleWindowEvent(event);
153
154 SetBackgroundColour(wxSystemSettings::GetColour( wxSYS_COLOUR_3DFACE ));
155
156 if ( parent )
157 parent->AddChild(this);
158
159 return true;
160 }
161
162 bool wxNonOwnedWindow::Create(wxWindow *parent, WXWindow nativeWindow)
163 {
164 if ( parent )
165 parent->AddChild(this);
166
167 SubclassWin(nativeWindow);
168
169 return true;
170 }
171
172 void wxNonOwnedWindow::SubclassWin(WXWindow nativeWindow)
173 {
174 wxASSERT_MSG( !m_isNativeWindowWrapper, wxT("subclassing window twice?") );
175 wxASSERT_MSG( m_nowpeer == NULL, wxT("window already was created") );
176
177 m_nowpeer = wxNonOwnedWindowImpl::CreateNonOwnedWindow(this, GetParent(), nativeWindow );
178 m_isNativeWindowWrapper = true;
179 wxNonOwnedWindowImpl::Associate( m_nowpeer->GetWXWindow() , m_nowpeer ) ;
180 SetPeer(wxWidgetImpl::CreateContentView(this));
181 }
182
183 void wxNonOwnedWindow::UnsubclassWin()
184 {
185 wxASSERT_MSG( m_isNativeWindowWrapper, wxT("window was not subclassed") );
186
187 if ( GetParent() )
188 GetParent()->RemoveChild(this);
189
190 wxNonOwnedWindowImpl::RemoveAssociations(m_nowpeer) ;
191 wxDELETE(m_nowpeer);
192 SetPeer(NULL);
193 m_isNativeWindowWrapper = false;
194 }
195
196
197 wxNonOwnedWindow::~wxNonOwnedWindow()
198 {
199 SendDestroyEvent();
200
201 wxNonOwnedWindowImpl::RemoveAssociations(m_nowpeer) ;
202
203 DestroyChildren();
204
205 wxDELETE(m_nowpeer);
206
207 // avoid dangling refs
208 if ( s_macDeactivateWindow == this )
209 s_macDeactivateWindow = NULL;
210 }
211
212 bool wxNonOwnedWindow::Destroy()
213 {
214 WillBeDestroyed();
215
216 return wxWindow::Destroy();
217 }
218
219 void wxNonOwnedWindow::WillBeDestroyed()
220 {
221 if ( m_nowpeer )
222 m_nowpeer->WillBeDestroyed();
223 }
224
225 // ----------------------------------------------------------------------------
226 // wxNonOwnedWindow misc
227 // ----------------------------------------------------------------------------
228
229 bool wxNonOwnedWindow::OSXShowWithEffect(bool show,
230 wxShowEffect effect,
231 unsigned timeout)
232 {
233 // Cocoa code needs to manage window visibility on its own and so calls
234 // wxWindow::Show() as needed but if we already changed the internal
235 // visibility flag here, Show() would do nothing, so avoid doing it
236 #if wxOSX_USE_CARBON
237 if ( !wxWindow::Show(show) )
238 return false;
239 #endif // Carbon
240
241 if ( effect == wxSHOW_EFFECT_NONE ||
242 !m_nowpeer || !m_nowpeer->ShowWithEffect(show, effect, timeout) )
243 return Show(show);
244
245 if ( show )
246 {
247 // as apps expect a size event to occur when the window is shown,
248 // generate one when it is shown with effect too
249 wxSizeEvent event(GetSize(), m_windowId);
250 event.SetEventObject(this);
251 HandleWindowEvent(event);
252 }
253
254 return true;
255 }
256
257 wxPoint wxNonOwnedWindow::GetClientAreaOrigin() const
258 {
259 int left, top, width, height;
260 m_nowpeer->GetContentArea(left, top, width, height);
261 return wxPoint(left, top);
262 }
263
264 bool wxNonOwnedWindow::SetBackgroundColour(const wxColour& c )
265 {
266 if ( !wxWindow::SetBackgroundColour(c) && m_hasBgCol )
267 return false ;
268
269 if ( GetBackgroundStyle() != wxBG_STYLE_CUSTOM )
270 {
271 if ( m_nowpeer )
272 return m_nowpeer->SetBackgroundColour(c);
273 }
274 return true;
275 }
276
277 void wxNonOwnedWindow::SetWindowStyleFlag(long flags)
278 {
279 if (flags == GetWindowStyleFlag())
280 return;
281
282 wxWindow::SetWindowStyleFlag(flags);
283
284 if (m_nowpeer)
285 m_nowpeer->SetWindowStyleFlag(flags);
286 }
287
288 // Raise the window to the top of the Z order
289 void wxNonOwnedWindow::Raise()
290 {
291 m_nowpeer->Raise();
292 }
293
294 // Lower the window to the bottom of the Z order
295 void wxNonOwnedWindow::Lower()
296 {
297 m_nowpeer->Lower();
298 }
299
300 void wxNonOwnedWindow::HandleActivated( double timestampsec, bool didActivate )
301 {
302 MacActivate( (int) (timestampsec * 1000) , didActivate);
303 wxActivateEvent wxevent(wxEVT_ACTIVATE, didActivate , GetId());
304 wxevent.SetTimestamp( (int) (timestampsec * 1000) );
305 wxevent.SetEventObject(this);
306 HandleWindowEvent(wxevent);
307 }
308
309 void wxNonOwnedWindow::HandleResized( double timestampsec )
310 {
311 wxSizeEvent wxevent( GetSize() , GetId());
312 wxevent.SetTimestamp( (int) (timestampsec * 1000) );
313 wxevent.SetEventObject( this );
314 HandleWindowEvent(wxevent);
315 // we have to inform some controls that have to reset things
316 // relative to the toplevel window (e.g. OpenGL buffers)
317 wxWindowMac::MacSuperChangedPosition() ; // like this only children will be notified
318 }
319
320 void wxNonOwnedWindow::HandleResizing( double WXUNUSED(timestampsec), wxRect* rect )
321 {
322 wxRect r = *rect ;
323
324 // this is a EVT_SIZING not a EVT_SIZE type !
325 wxSizeEvent wxevent( r , GetId() ) ;
326 wxevent.SetEventObject( this ) ;
327 if ( HandleWindowEvent(wxevent) )
328 r = wxevent.GetRect() ;
329
330 if ( GetMaxWidth() != -1 && r.GetWidth() > GetMaxWidth() )
331 r.SetWidth( GetMaxWidth() ) ;
332 if ( GetMaxHeight() != -1 && r.GetHeight() > GetMaxHeight() )
333 r.SetHeight( GetMaxHeight() ) ;
334 if ( GetMinWidth() != -1 && r.GetWidth() < GetMinWidth() )
335 r.SetWidth( GetMinWidth() ) ;
336 if ( GetMinHeight() != -1 && r.GetHeight() < GetMinHeight() )
337 r.SetHeight( GetMinHeight() ) ;
338
339 *rect = r;
340 // TODO actuall this is too early, in case the window extents are adjusted
341 wxWindowMac::MacSuperChangedPosition() ; // like this only children will be notified
342 }
343
344 void wxNonOwnedWindow::HandleMoved( double timestampsec )
345 {
346 wxMoveEvent wxevent( GetPosition() , GetId());
347 wxevent.SetTimestamp( (int) (timestampsec * 1000) );
348 wxevent.SetEventObject( this );
349 HandleWindowEvent(wxevent);
350 }
351
352 void wxNonOwnedWindow::MacDelayedDeactivation(long timestamp)
353 {
354 if (s_macDeactivateWindow)
355 {
356 wxLogTrace(TRACE_ACTIVATE,
357 wxT("Doing delayed deactivation of %p"),
358 s_macDeactivateWindow);
359
360 s_macDeactivateWindow->MacActivate(timestamp, false);
361 }
362 }
363
364 void wxNonOwnedWindow::MacActivate( long timestamp , bool WXUNUSED(inIsActivating) )
365 {
366 wxLogTrace(TRACE_ACTIVATE, wxT("TopLevel=%p::MacActivate"), this);
367
368 if (s_macDeactivateWindow == this)
369 s_macDeactivateWindow = NULL;
370
371 MacDelayedDeactivation(timestamp);
372 }
373
374 bool wxNonOwnedWindow::Show(bool show)
375 {
376 if ( !wxWindow::Show(show) )
377 return false;
378
379 if ( m_nowpeer )
380 m_nowpeer->Show(show);
381
382 if ( show )
383 {
384 // because apps expect a size event to occur at this moment
385 wxSizeEvent event(GetSize() , m_windowId);
386 event.SetEventObject(this);
387 HandleWindowEvent(event);
388 }
389
390 return true ;
391 }
392
393 bool wxNonOwnedWindow::SetTransparent(wxByte alpha)
394 {
395 return m_nowpeer->SetTransparent(alpha);
396 }
397
398
399 bool wxNonOwnedWindow::CanSetTransparent()
400 {
401 return m_nowpeer->CanSetTransparent();
402 }
403
404
405 void wxNonOwnedWindow::SetExtraStyle(long exStyle)
406 {
407 if ( GetExtraStyle() == exStyle )
408 return ;
409
410 wxWindow::SetExtraStyle( exStyle ) ;
411
412 if ( m_nowpeer )
413 m_nowpeer->SetExtraStyle(exStyle);
414 }
415
416 bool wxNonOwnedWindow::SetBackgroundStyle(wxBackgroundStyle style)
417 {
418 if ( !wxWindow::SetBackgroundStyle(style) )
419 return false ;
420
421 return m_nowpeer ? m_nowpeer->SetBackgroundStyle(style) : true;
422 }
423
424 void wxNonOwnedWindow::DoMoveWindow(int x, int y, int width, int height)
425 {
426 if ( m_nowpeer == NULL )
427 return;
428
429 m_cachedClippedRectValid = false ;
430
431 m_nowpeer->MoveWindow(x, y, width, height);
432 wxWindowMac::MacSuperChangedPosition() ; // like this only children will be notified
433 }
434
435 void wxNonOwnedWindow::DoGetPosition( int *x, int *y ) const
436 {
437 if ( m_nowpeer == NULL )
438 return;
439
440 int x1,y1 ;
441 m_nowpeer->GetPosition(x1, y1);
442
443 if (x)
444 *x = x1 ;
445 if (y)
446 *y = y1 ;
447 }
448
449 void wxNonOwnedWindow::DoGetSize( int *width, int *height ) const
450 {
451 if ( m_nowpeer == NULL )
452 return;
453
454 int w,h;
455
456 m_nowpeer->GetSize(w, h);
457
458 if (width)
459 *width = w ;
460 if (height)
461 *height = h ;
462 }
463
464 void wxNonOwnedWindow::DoGetClientSize( int *width, int *height ) const
465 {
466 if ( m_nowpeer == NULL )
467 return;
468
469 int left, top, w, h;
470 // under iphone with a translucent status bar the m_nowpeer returns the
471 // inner area, while the content area extends under the translucent
472 // status bar, therefore we use the content view's area
473 #ifdef __WXOSX_IPHONE__
474 GetPeer()->GetContentArea(left, top, w, h);
475 #else
476 m_nowpeer->GetContentArea(left, top, w, h);
477 #endif
478
479 if (width)
480 *width = w ;
481 if (height)
482 *height = h ;
483 }
484
485
486 void wxNonOwnedWindow::Update()
487 {
488 m_nowpeer->Update();
489 }
490
491 WXWindow wxNonOwnedWindow::GetWXWindow() const
492 {
493 return m_nowpeer ? m_nowpeer->GetWXWindow() : NULL;
494 }
495
496 // ---------------------------------------------------------------------------
497 // Shape implementation
498 // ---------------------------------------------------------------------------
499
500
501 bool wxNonOwnedWindow::DoSetShape(const wxRegion& region)
502 {
503 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false,
504 wxT("Shaped windows must be created with the wxFRAME_SHAPED style."));
505
506 m_shape = region;
507
508 // The empty region signifies that the shape
509 // should be removed from the window.
510 if ( region.IsEmpty() )
511 {
512 wxSize sz = GetClientSize();
513 wxRegion rgn(0, 0, sz.x, sz.y);
514 if ( rgn.IsEmpty() )
515 return false ;
516 else
517 return DoSetShape(rgn);
518 }
519
520 return m_nowpeer->SetShape(region);
521 }