]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/toplevel.cpp
Fixed uninstalled toolbars in native toolbar mode, with a method for
[wxWidgets.git] / src / mac / carbon / toplevel.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/toplevel.cpp
3 // Purpose: implements wxTopLevelWindow for Mac
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 24.09.01
7 // RCS-ID: $Id$
8 // Copyright: (c) 2001-2004 Stefan Csomor
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/toplevel.h"
28
29 #ifndef WX_PRECOMP
30 #include "wx/app.h"
31 #include "wx/frame.h"
32 #include "wx/string.h"
33 #include "wx/log.h"
34 #include "wx/intl.h"
35 #include "wx/settings.h"
36 #include "wx/strconv.h"
37 #include "wx/control.h"
38 #endif //WX_PRECOMP
39
40 #include "wx/mac/uma.h"
41 #include "wx/mac/aga.h"
42 #include "wx/tooltip.h"
43 #include "wx/dnd.h"
44
45 #if wxUSE_SYSTEM_OPTIONS
46 #include "wx/sysopt.h"
47 #endif
48
49 #ifndef __DARWIN__
50 #include <ToolUtils.h>
51 #endif
52
53 // for targeting OSX
54 #include "wx/mac/private.h"
55
56 // ----------------------------------------------------------------------------
57 // constants
58 // ----------------------------------------------------------------------------
59
60 // trace mask for activation tracing messages
61 static const wxChar *TRACE_ACTIVATE = _T("activation");
62
63 // ----------------------------------------------------------------------------
64 // globals
65 // ----------------------------------------------------------------------------
66
67 // list of all frames and modeless dialogs
68 wxWindowList wxModelessWindows;
69
70 static pascal long wxShapedMacWindowDef(short varCode, WindowRef window, SInt16 message, SInt32 param);
71
72 // ============================================================================
73 // wxTopLevelWindowMac implementation
74 // ============================================================================
75
76 BEGIN_EVENT_TABLE(wxTopLevelWindowMac, wxTopLevelWindowBase)
77 END_EVENT_TABLE()
78
79
80 // ---------------------------------------------------------------------------
81 // Carbon Events
82 // ---------------------------------------------------------------------------
83
84 static const EventTypeSpec eventList[] =
85 {
86 // TODO: remove control related event like key and mouse (except for WindowLeave events)
87
88 { kEventClassKeyboard, kEventRawKeyDown } ,
89 { kEventClassKeyboard, kEventRawKeyRepeat } ,
90 { kEventClassKeyboard, kEventRawKeyUp } ,
91 { kEventClassKeyboard, kEventRawKeyModifiersChanged } ,
92
93 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } ,
94 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea } ,
95
96 { kEventClassWindow , kEventWindowShown } ,
97 { kEventClassWindow , kEventWindowActivated } ,
98 { kEventClassWindow , kEventWindowDeactivated } ,
99 { kEventClassWindow , kEventWindowBoundsChanging } ,
100 { kEventClassWindow , kEventWindowBoundsChanged } ,
101 { kEventClassWindow , kEventWindowClose } ,
102
103 // we have to catch these events on the toplevel window level,
104 // as controls don't get the raw mouse events anymore
105
106 { kEventClassMouse , kEventMouseDown } ,
107 { kEventClassMouse , kEventMouseUp } ,
108 { kEventClassMouse , kEventMouseWheelMoved } ,
109 { kEventClassMouse , kEventMouseMoved } ,
110 { kEventClassMouse , kEventMouseDragged } ,
111 } ;
112
113 static pascal OSStatus KeyboardEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
114 {
115 OSStatus result = eventNotHandledErr ;
116 // call DoFindFocus instead of FindFocus, because for Composite Windows(like WxGenericListCtrl)
117 // FindFocus does not return the actual focus window, but the enclosing window
118 wxWindow* focus = wxWindow::DoFindFocus();
119 if ( focus == NULL )
120 focus = (wxTopLevelWindowMac*) data ;
121
122 unsigned char charCode ;
123 wxChar uniChar[2] ;
124 uniChar[0] = 0;
125 uniChar[1] = 0;
126
127 UInt32 keyCode ;
128 UInt32 modifiers ;
129 Point point ;
130 UInt32 when = EventTimeToTicks( GetEventTime( event ) ) ;
131
132 #if wxUSE_UNICODE
133 ByteCount dataSize = 0 ;
134 if ( GetEventParameter( event, kEventParamKeyUnicodes, typeUnicodeText, NULL, 0 , &dataSize, NULL ) == noErr )
135 {
136 UniChar buf[2] ;
137 int numChars = dataSize / sizeof( UniChar) + 1;
138
139 UniChar* charBuf = buf ;
140
141 if ( numChars * 2 > 4 )
142 charBuf = new UniChar[ numChars ] ;
143 GetEventParameter( event, kEventParamKeyUnicodes, typeUnicodeText, NULL, dataSize , NULL , charBuf ) ;
144 charBuf[ numChars - 1 ] = 0;
145
146 #if SIZEOF_WCHAR_T == 2
147 uniChar = charBuf[0] ;
148 #else
149 wxMBConvUTF16 converter ;
150 converter.MB2WC( uniChar , (const char*)charBuf , 2 ) ;
151 #endif
152
153 if ( numChars * 2 > 4 )
154 delete[] charBuf ;
155 }
156 #endif
157
158 GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &charCode );
159 GetEventParameter( event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode );
160 GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers );
161 GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &point );
162
163 UInt32 message = (keyCode << 8) + charCode;
164 switch ( GetEventKind( event ) )
165 {
166 case kEventRawKeyRepeat :
167 case kEventRawKeyDown :
168 {
169 WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;
170 WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ;
171 wxTheApp->MacSetCurrentEvent( event , handler ) ;
172 if ( /* focus && */ wxTheApp->MacSendKeyDownEvent(
173 focus , message , modifiers , when , point.h , point.v , uniChar[0] ) )
174 {
175 result = noErr ;
176 }
177 wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;
178 }
179 break ;
180
181 case kEventRawKeyUp :
182 if ( /* focus && */ wxTheApp->MacSendKeyUpEvent(
183 focus , message , modifiers , when , point.h , point.v , uniChar[0] ) )
184 {
185 result = noErr ;
186 }
187 break ;
188
189 case kEventRawKeyModifiersChanged :
190 {
191 wxKeyEvent event(wxEVT_KEY_DOWN);
192
193 event.m_shiftDown = modifiers & shiftKey;
194 event.m_controlDown = modifiers & controlKey;
195 event.m_altDown = modifiers & optionKey;
196 event.m_metaDown = modifiers & cmdKey;
197 event.m_x = point.h;
198 event.m_y = point.v;
199
200 #if wxUSE_UNICODE
201 event.m_uniChar = uniChar[0] ;
202 #endif
203
204 event.SetTimestamp(when);
205 event.SetEventObject(focus);
206
207 if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & controlKey )
208 {
209 event.m_keyCode = WXK_CONTROL ;
210 event.SetEventType( ( modifiers & controlKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;
211 focus->GetEventHandler()->ProcessEvent( event ) ;
212 }
213 if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & shiftKey )
214 {
215 event.m_keyCode = WXK_SHIFT ;
216 event.SetEventType( ( modifiers & shiftKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;
217 focus->GetEventHandler()->ProcessEvent( event ) ;
218 }
219 if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & optionKey )
220 {
221 event.m_keyCode = WXK_ALT ;
222 event.SetEventType( ( modifiers & optionKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;
223 focus->GetEventHandler()->ProcessEvent( event ) ;
224 }
225 if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & cmdKey )
226 {
227 event.m_keyCode = WXK_COMMAND ;
228 event.SetEventType( ( modifiers & cmdKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;
229 focus->GetEventHandler()->ProcessEvent( event ) ;
230 }
231
232 wxApp::s_lastModifiers = modifiers ;
233 }
234 break ;
235
236 default:
237 break;
238 }
239
240 return result ;
241 }
242
243 // we don't interfere with foreign controls on our toplevel windows, therefore we always give back eventNotHandledErr
244 // for windows that we didn't create (like eg Scrollbars in a databrowser), or for controls where we did not handle the
245 // mouse down at all
246 //
247 // This handler can also be called from app level where data (ie target window) may be null or a non wx window
248
249 wxWindow* g_MacLastWindow = NULL ;
250
251 EventMouseButton g_lastButton = 0 ;
252 bool g_lastButtonWasFakeRight = false ;
253
254 void SetupMouseEvent( wxMouseEvent &wxevent , wxMacCarbonEvent &cEvent )
255 {
256 UInt32 modifiers = cEvent.GetParameter<UInt32>(kEventParamKeyModifiers, typeUInt32) ;
257 Point screenMouseLocation = cEvent.GetParameter<Point>(kEventParamMouseLocation) ;
258
259 // this parameter are not given for all events
260 EventMouseButton button = 0 ;
261 UInt32 clickCount = 0 ;
262 cEvent.GetParameter<EventMouseButton>( kEventParamMouseButton, typeMouseButton , &button ) ;
263 cEvent.GetParameter<UInt32>( kEventParamClickCount, typeUInt32 , &clickCount ) ;
264
265 wxevent.m_x = screenMouseLocation.h;
266 wxevent.m_y = screenMouseLocation.v;
267 wxevent.m_shiftDown = modifiers & shiftKey;
268 wxevent.m_controlDown = modifiers & controlKey;
269 wxevent.m_altDown = modifiers & optionKey;
270 wxevent.m_metaDown = modifiers & cmdKey;
271 wxevent.SetTimestamp( cEvent.GetTicks() ) ;
272
273 // a control click is interpreted as a right click
274 bool thisButtonIsFakeRight = false ;
275 if ( button == kEventMouseButtonPrimary && (modifiers & controlKey) )
276 {
277 button = kEventMouseButtonSecondary ;
278 thisButtonIsFakeRight = true ;
279 }
280 // otherwise we report double clicks by connecting a left click with a ctrl-left click
281 if ( clickCount > 1 && button != g_lastButton )
282 clickCount = 1 ;
283
284 // we must make sure that our synthetic 'right' button corresponds in
285 // mouse down, moved and mouse up, and does not deliver a right down and left up
286
287 if ( cEvent.GetKind() == kEventMouseDown )
288 {
289 g_lastButton = button ;
290 g_lastButtonWasFakeRight = thisButtonIsFakeRight ;
291 }
292
293 if ( button == 0 )
294 {
295 g_lastButton = 0 ;
296 g_lastButtonWasFakeRight = false ;
297 }
298 else if ( g_lastButton == kEventMouseButtonSecondary && g_lastButtonWasFakeRight )
299 button = g_lastButton ;
300
301 // determine the correct down state, wx does not want a 'down' for a mouseUp event,
302 // while mac delivers this button
303 if ( button != 0 && cEvent.GetKind() != kEventMouseUp )
304 {
305 switch ( button )
306 {
307 case kEventMouseButtonPrimary :
308 wxevent.m_leftDown = true ;
309 break ;
310
311 case kEventMouseButtonSecondary :
312 wxevent.m_rightDown = true ;
313 break ;
314
315 case kEventMouseButtonTertiary :
316 wxevent.m_middleDown = true ;
317 break ;
318
319 default:
320 break ;
321 }
322 }
323
324 // translate into wx types
325 switch ( cEvent.GetKind() )
326 {
327 case kEventMouseDown :
328 switch ( button )
329 {
330 case kEventMouseButtonPrimary :
331 wxevent.SetEventType( clickCount > 1 ? wxEVT_LEFT_DCLICK : wxEVT_LEFT_DOWN ) ;
332 break ;
333
334 case kEventMouseButtonSecondary :
335 wxevent.SetEventType( clickCount > 1 ? wxEVT_RIGHT_DCLICK : wxEVT_RIGHT_DOWN ) ;
336 break ;
337
338 case kEventMouseButtonTertiary :
339 wxevent.SetEventType( clickCount > 1 ? wxEVT_MIDDLE_DCLICK : wxEVT_MIDDLE_DOWN ) ;
340 break ;
341
342 default:
343 break ;
344 }
345 break ;
346
347 case kEventMouseUp :
348 switch ( button )
349 {
350 case kEventMouseButtonPrimary :
351 wxevent.SetEventType( wxEVT_LEFT_UP ) ;
352 break ;
353
354 case kEventMouseButtonSecondary :
355 wxevent.SetEventType( wxEVT_RIGHT_UP ) ;
356 break ;
357
358 case kEventMouseButtonTertiary :
359 wxevent.SetEventType( wxEVT_MIDDLE_UP ) ;
360 break ;
361
362 default:
363 break ;
364 }
365 break ;
366
367 case kEventMouseWheelMoved :
368 {
369 wxevent.SetEventType( wxEVT_MOUSEWHEEL ) ;
370
371 EventMouseWheelAxis axis = cEvent.GetParameter<EventMouseWheelAxis>(kEventParamMouseWheelAxis, typeMouseWheelAxis) ;
372 SInt32 delta = cEvent.GetParameter<SInt32>(kEventParamMouseWheelDelta, typeSInt32) ;
373
374 wxevent.m_wheelRotation = delta;
375 wxevent.m_wheelDelta = 1;
376 wxevent.m_linesPerAction = 1;
377 if ( axis == kEventMouseWheelAxisX )
378 wxevent.m_wheelAxis = 1;
379 }
380 break ;
381
382 default :
383 wxevent.SetEventType( wxEVT_MOTION ) ;
384 break ;
385 }
386 }
387
388 ControlRef wxMacFindSubControl( wxTopLevelWindowMac* toplevelWindow, const Point& location , ControlRef superControl , ControlPartCode *outPart )
389 {
390 if ( superControl )
391 {
392 UInt16 childrenCount = 0 ;
393 ControlHandle sibling ;
394 Rect r ;
395 OSStatus err = CountSubControls( superControl , &childrenCount ) ;
396 if ( err == errControlIsNotEmbedder )
397 return NULL ;
398
399 wxASSERT_MSG( err == noErr , wxT("Unexpected error when accessing subcontrols") ) ;
400
401 for ( UInt16 i = childrenCount ; i >=1 ; --i )
402 {
403 err = GetIndexedSubControl( superControl , i , & sibling ) ;
404 if ( err == errControlIsNotEmbedder )
405 return NULL ;
406
407 wxASSERT_MSG( err == noErr , wxT("Unexpected error when accessing subcontrols") ) ;
408 if ( IsControlVisible( sibling ) )
409 {
410 UMAGetControlBoundsInWindowCoords( sibling , &r ) ;
411 if ( MacPtInRect( location , &r ) )
412 {
413 ControlHandle child = wxMacFindSubControl( toplevelWindow , location , sibling , outPart ) ;
414 if ( child )
415 {
416 return child ;
417 }
418 else
419 {
420 Point testLocation = location ;
421
422 if ( toplevelWindow )
423 {
424 testLocation.h -= r.left ;
425 testLocation.v -= r.top ;
426 }
427
428 *outPart = TestControl( sibling , testLocation ) ;
429
430 return sibling ;
431 }
432 }
433 }
434 }
435 }
436
437 return NULL ;
438 }
439
440 ControlRef wxMacFindControlUnderMouse( wxTopLevelWindowMac* toplevelWindow , const Point& location , WindowRef window , ControlPartCode *outPart )
441 {
442 #if TARGET_API_MAC_OSX
443 if ( UMAGetSystemVersion() >= 0x1030 )
444 return FindControlUnderMouse( location , window , outPart ) ;
445 #endif
446
447 ControlRef rootControl = NULL ;
448 verify_noerr( GetRootControl( window , &rootControl ) ) ;
449
450 return wxMacFindSubControl( toplevelWindow , location , rootControl , outPart ) ;
451 }
452
453 #define NEW_CAPTURE_HANDLING 1
454
455 pascal OSStatus wxMacTopLevelMouseEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
456 {
457 wxTopLevelWindowMac* toplevelWindow = (wxTopLevelWindowMac*) data ;
458
459 OSStatus result = eventNotHandledErr ;
460
461 wxMacCarbonEvent cEvent( event ) ;
462
463 Point screenMouseLocation = cEvent.GetParameter<Point>(kEventParamMouseLocation) ;
464 Point windowMouseLocation = screenMouseLocation ;
465
466 WindowRef window = NULL;
467 short windowPart = ::FindWindow(screenMouseLocation, &window);
468
469 wxWindow* currentMouseWindow = NULL ;
470 ControlRef control = NULL ;
471
472 #if NEW_CAPTURE_HANDLING
473 if ( wxApp::s_captureWindow )
474 {
475 window = (WindowRef) wxApp::s_captureWindow->MacGetTopLevelWindowRef() ;
476 windowPart = inContent ;
477 }
478 #endif
479
480 if ( window )
481 {
482 wxMacGlobalToLocal( window, &windowMouseLocation ) ;
483
484 if ( wxApp::s_captureWindow
485 #if !NEW_CAPTURE_HANDLING
486 && wxApp::s_captureWindow->MacGetTopLevelWindowRef() == (WXWindow) window && windowPart == inContent
487 #endif
488 )
489 {
490 currentMouseWindow = wxApp::s_captureWindow ;
491 }
492 else if ( (IsWindowActive(window) && windowPart == inContent) )
493 {
494 ControlPartCode part ;
495 control = wxMacFindControlUnderMouse( toplevelWindow , windowMouseLocation , window , &part ) ;
496 // if there is no control below the mouse position, send the event to the toplevel window itself
497 if ( control == 0 )
498 {
499 currentMouseWindow = (wxWindow*) data ;
500 }
501 else
502 {
503 currentMouseWindow = wxFindControlFromMacControl( control ) ;
504 if ( currentMouseWindow == NULL && cEvent.GetKind() == kEventMouseMoved )
505 {
506 #if wxUSE_TOOLBAR
507 // for wxToolBar to function we have to send certaint events to it
508 // instead of its children (wxToolBarTools)
509 ControlRef parent ;
510 GetSuperControl(control, &parent );
511 wxWindow *wxParent = wxFindControlFromMacControl( parent ) ;
512 if ( wxParent && wxParent->IsKindOf( CLASSINFO( wxToolBar ) ) )
513 currentMouseWindow = wxParent ;
514 #endif
515 }
516 }
517
518 // disabled windows must not get any input messages
519 if ( currentMouseWindow && !currentMouseWindow->MacIsReallyEnabled() )
520 currentMouseWindow = NULL;
521 }
522 }
523
524 wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
525 SetupMouseEvent( wxevent , cEvent ) ;
526
527 // handle all enter / leave events
528
529 if ( currentMouseWindow != g_MacLastWindow )
530 {
531 if ( g_MacLastWindow )
532 {
533 wxMouseEvent eventleave(wxevent);
534 eventleave.SetEventType( wxEVT_LEAVE_WINDOW );
535 g_MacLastWindow->ScreenToClient( &eventleave.m_x, &eventleave.m_y );
536 eventleave.SetEventObject( g_MacLastWindow ) ;
537 wxevent.SetId( g_MacLastWindow->GetId() ) ;
538
539 #if wxUSE_TOOLTIPS
540 wxToolTip::RelayEvent( g_MacLastWindow , eventleave);
541 #endif
542
543 g_MacLastWindow->GetEventHandler()->ProcessEvent(eventleave);
544 }
545
546 if ( currentMouseWindow )
547 {
548 wxMouseEvent evententer(wxevent);
549 evententer.SetEventType( wxEVT_ENTER_WINDOW );
550 currentMouseWindow->ScreenToClient( &evententer.m_x, &evententer.m_y );
551 evententer.SetEventObject( currentMouseWindow ) ;
552 wxevent.SetId( currentMouseWindow->GetId() ) ;
553
554 #if wxUSE_TOOLTIPS
555 wxToolTip::RelayEvent( currentMouseWindow , evententer );
556 #endif
557
558 currentMouseWindow->GetEventHandler()->ProcessEvent(evententer);
559 }
560
561 g_MacLastWindow = currentMouseWindow ;
562 }
563
564 if ( windowPart == inMenuBar )
565 {
566 // special case menu bar, as we are having a low-level runloop we must do it ourselves
567 if ( cEvent.GetKind() == kEventMouseDown )
568 {
569 ::MenuSelect( screenMouseLocation ) ;
570 result = noErr ;
571 }
572 }
573 else if ( currentMouseWindow )
574 {
575 wxWindow *currentMouseWindowParent = currentMouseWindow->GetParent();
576
577 currentMouseWindow->ScreenToClient( &wxevent.m_x , &wxevent.m_y ) ;
578
579 wxevent.SetEventObject( currentMouseWindow ) ;
580 wxevent.SetId( currentMouseWindow->GetId() ) ;
581
582 // make tooltips current
583
584 #if wxUSE_TOOLTIPS
585 if ( wxevent.GetEventType() == wxEVT_MOTION )
586 wxToolTip::RelayEvent( currentMouseWindow , wxevent );
587 #endif
588
589 if ( currentMouseWindow->GetEventHandler()->ProcessEvent(wxevent) )
590 {
591 if ((currentMouseWindowParent != NULL) &&
592 (currentMouseWindowParent->GetChildren().Find(currentMouseWindow) == NULL))
593 currentMouseWindow = NULL;
594
595 result = noErr;
596 }
597 else
598 {
599 // if the user code did _not_ handle the event, then perform the
600 // default processing
601 if ( wxevent.GetEventType() == wxEVT_LEFT_DOWN )
602 {
603 // ... that is set focus to this window
604 if (currentMouseWindow->CanAcceptFocus() && wxWindow::FindFocus()!=currentMouseWindow)
605 currentMouseWindow->SetFocus();
606 }
607
608 ControlPartCode dummyPart ;
609 // if built-in find control is finding the wrong control (ie static box instead of overlaid
610 // button, we cannot let the standard handler do its job, but must handle manually
611
612 if ( ( cEvent.GetKind() == kEventMouseDown )
613 #ifdef __WXMAC_OSX__
614 &&
615 (FindControlUnderMouse(windowMouseLocation , window , &dummyPart) !=
616 wxMacFindControlUnderMouse( toplevelWindow , windowMouseLocation , window , &dummyPart ) )
617 #endif
618 )
619 {
620 if ( currentMouseWindow->MacIsReallyEnabled() )
621 {
622 EventModifiers modifiers = cEvent.GetParameter<EventModifiers>(kEventParamKeyModifiers, typeUInt32) ;
623 Point clickLocation = windowMouseLocation ;
624
625 currentMouseWindow->MacRootWindowToWindow( &clickLocation.h , &clickLocation.v ) ;
626
627 HandleControlClick( (ControlRef) currentMouseWindow->GetHandle() , clickLocation ,
628 modifiers , (ControlActionUPP ) -1 ) ;
629
630 if ((currentMouseWindowParent != NULL) &&
631 (currentMouseWindowParent->GetChildren().Find(currentMouseWindow) == NULL))
632 {
633 currentMouseWindow = NULL;
634 }
635 }
636
637 result = noErr ;
638 }
639 }
640
641 if ( cEvent.GetKind() == kEventMouseUp && wxApp::s_captureWindow )
642 {
643 wxApp::s_captureWindow = NULL ;
644 // update cursor ?
645 }
646
647 // update cursor
648
649 wxWindow* cursorTarget = currentMouseWindow ;
650 wxPoint cursorPoint( wxevent.m_x , wxevent.m_y ) ;
651
652 while ( cursorTarget && !cursorTarget->MacSetupCursor( cursorPoint ) )
653 {
654 cursorTarget = cursorTarget->GetParent() ;
655 if ( cursorTarget )
656 cursorPoint += cursorTarget->GetPosition();
657 }
658
659 }
660 else // currentMouseWindow == NULL
661 {
662 // don't mess with controls we don't know about
663 // for some reason returning eventNotHandledErr does not lead to the correct behaviour
664 // so we try sending them the correct control directly
665 if ( cEvent.GetKind() == kEventMouseDown && toplevelWindow && control )
666 {
667 EventModifiers modifiers = cEvent.GetParameter<EventModifiers>(kEventParamKeyModifiers, typeUInt32) ;
668 Point clickLocation = windowMouseLocation ;
669 #if TARGET_API_MAC_OSX
670 HIPoint hiPoint ;
671 hiPoint.x = clickLocation.h ;
672 hiPoint.y = clickLocation.v ;
673 HIViewConvertPoint( &hiPoint , (ControlRef) toplevelWindow->GetHandle() , control ) ;
674 clickLocation.h = (int)hiPoint.x ;
675 clickLocation.v = (int)hiPoint.y ;
676 #endif // TARGET_API_MAC_OSX
677
678 HandleControlClick( control , clickLocation , modifiers , (ControlActionUPP ) -1 ) ;
679 result = noErr ;
680 }
681 }
682
683 return result ;
684 }
685
686 static pascal OSStatus wxMacTopLevelWindowEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
687 {
688 OSStatus result = eventNotHandledErr ;
689
690 wxMacCarbonEvent cEvent( event ) ;
691
692 // WindowRef windowRef = cEvent.GetParameter<WindowRef>(kEventParamDirectObject) ;
693 wxTopLevelWindowMac* toplevelWindow = (wxTopLevelWindowMac*) data ;
694
695 switch ( GetEventKind( event ) )
696 {
697 case kEventWindowActivated :
698 {
699 toplevelWindow->MacActivate( cEvent.GetTicks() , true) ;
700 wxActivateEvent wxevent(wxEVT_ACTIVATE, true , toplevelWindow->GetId());
701 wxevent.SetTimestamp( cEvent.GetTicks() ) ;
702 wxevent.SetEventObject(toplevelWindow);
703 toplevelWindow->GetEventHandler()->ProcessEvent(wxevent);
704 // we still sending an eventNotHandledErr in order to allow for default processing
705 }
706 break ;
707
708 case kEventWindowDeactivated :
709 {
710 toplevelWindow->MacActivate(cEvent.GetTicks() , false) ;
711 wxActivateEvent wxevent(wxEVT_ACTIVATE, false , toplevelWindow->GetId());
712 wxevent.SetTimestamp( cEvent.GetTicks() ) ;
713 wxevent.SetEventObject(toplevelWindow);
714 toplevelWindow->GetEventHandler()->ProcessEvent(wxevent);
715 // we still sending an eventNotHandledErr in order to allow for default processing
716 }
717 break ;
718
719 case kEventWindowShown :
720 toplevelWindow->Refresh() ;
721 result = noErr ;
722 break ;
723
724 case kEventWindowClose :
725 toplevelWindow->Close() ;
726 result = noErr ;
727 break ;
728
729 case kEventWindowBoundsChanged :
730 {
731 UInt32 attributes = cEvent.GetParameter<UInt32>(kEventParamAttributes, typeUInt32) ;
732 Rect newRect = cEvent.GetParameter<Rect>(kEventParamCurrentBounds) ;
733 wxRect r( newRect.left , newRect.top , newRect.right - newRect.left , newRect.bottom - newRect.top ) ;
734 if ( attributes & kWindowBoundsChangeSizeChanged )
735 {
736 // according to the other ports we handle this within the OS level
737 // resize event, not within a wxSizeEvent
738 wxFrame *frame = wxDynamicCast( toplevelWindow , wxFrame ) ;
739 if ( frame )
740 {
741 frame->PositionBars();
742 }
743
744 wxSizeEvent event( r.GetSize() , toplevelWindow->GetId() ) ;
745 event.SetEventObject( toplevelWindow ) ;
746
747 toplevelWindow->GetEventHandler()->ProcessEvent(event) ;
748 toplevelWindow->wxWindowMac::MacSuperChangedPosition() ; // like this only children will be notified
749 }
750
751 if ( attributes & kWindowBoundsChangeOriginChanged )
752 {
753 wxMoveEvent event( r.GetLeftTop() , toplevelWindow->GetId() ) ;
754 event.SetEventObject( toplevelWindow ) ;
755 toplevelWindow->GetEventHandler()->ProcessEvent(event) ;
756 }
757
758 result = noErr ;
759 }
760 break ;
761
762 case kEventWindowBoundsChanging :
763 {
764 UInt32 attributes = cEvent.GetParameter<UInt32>(kEventParamAttributes,typeUInt32) ;
765 Rect newRect = cEvent.GetParameter<Rect>(kEventParamCurrentBounds) ;
766
767 if ( (attributes & kWindowBoundsChangeSizeChanged) || (attributes & kWindowBoundsChangeOriginChanged) )
768 {
769 // all (Mac) rects are in content area coordinates, all wxRects in structure coordinates
770 int left , top , right , bottom ;
771 toplevelWindow->MacGetContentAreaInset( left , top , right , bottom ) ;
772
773 wxRect r(
774 newRect.left - left,
775 newRect.top - top,
776 newRect.right - newRect.left + left + right,
777 newRect.bottom - newRect.top + top + bottom ) ;
778
779 // this is a EVT_SIZING not a EVT_SIZE type !
780 wxSizeEvent wxevent( r , toplevelWindow->GetId() ) ;
781 wxevent.SetEventObject( toplevelWindow ) ;
782 wxRect adjustR = r ;
783 if ( toplevelWindow->GetEventHandler()->ProcessEvent(wxevent) )
784 adjustR = wxevent.GetRect() ;
785
786 if ( toplevelWindow->GetMaxWidth() != -1 && adjustR.GetWidth() > toplevelWindow->GetMaxWidth() )
787 adjustR.SetWidth( toplevelWindow->GetMaxWidth() ) ;
788 if ( toplevelWindow->GetMaxHeight() != -1 && adjustR.GetHeight() > toplevelWindow->GetMaxHeight() )
789 adjustR.SetHeight( toplevelWindow->GetMaxHeight() ) ;
790 if ( toplevelWindow->GetMinWidth() != -1 && adjustR.GetWidth() < toplevelWindow->GetMinWidth() )
791 adjustR.SetWidth( toplevelWindow->GetMinWidth() ) ;
792 if ( toplevelWindow->GetMinHeight() != -1 && adjustR.GetHeight() < toplevelWindow->GetMinHeight() )
793 adjustR.SetHeight( toplevelWindow->GetMinHeight() ) ;
794 const Rect adjustedRect = { adjustR.y + top , adjustR.x + left , adjustR.y + adjustR.height - bottom , adjustR.x + adjustR.width - right } ;
795 if ( !EqualRect( &newRect , &adjustedRect ) )
796 cEvent.SetParameter<Rect>( kEventParamCurrentBounds , &adjustedRect ) ;
797 toplevelWindow->wxWindowMac::MacSuperChangedPosition() ; // like this only children will be notified
798 }
799
800 result = noErr ;
801 }
802 break ;
803
804 default :
805 break ;
806 }
807
808 return result ;
809 }
810
811 // mix this in from window.cpp
812 pascal OSStatus wxMacUnicodeTextEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) ;
813
814 pascal OSStatus wxMacTopLevelEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
815 {
816 OSStatus result = eventNotHandledErr ;
817
818 switch ( GetEventClass( event ) )
819 {
820 case kEventClassTextInput :
821 result = wxMacUnicodeTextEventHandler( handler, event , data ) ;
822 break ;
823
824 case kEventClassKeyboard :
825 result = KeyboardEventHandler( handler, event , data ) ;
826 break ;
827
828 case kEventClassWindow :
829 result = wxMacTopLevelWindowEventHandler( handler, event , data ) ;
830 break ;
831
832 case kEventClassMouse :
833 result = wxMacTopLevelMouseEventHandler( handler, event , data ) ;
834 break ;
835
836 default :
837 break ;
838 }
839
840 return result ;
841 }
842
843 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacTopLevelEventHandler )
844
845 // ---------------------------------------------------------------------------
846 // wxWindowMac utility functions
847 // ---------------------------------------------------------------------------
848
849 // Find an item given the Macintosh Window Reference
850
851 WX_DECLARE_HASH_MAP(WindowRef, wxTopLevelWindowMac*, wxPointerHash, wxPointerEqual, MacWindowMap);
852
853 static MacWindowMap wxWinMacWindowList;
854
855 wxTopLevelWindowMac *wxFindWinFromMacWindow(WindowRef inWindowRef)
856 {
857 MacWindowMap::iterator node = wxWinMacWindowList.find(inWindowRef);
858
859 return (node == wxWinMacWindowList.end()) ? NULL : node->second;
860 }
861
862 void wxAssociateWinWithMacWindow(WindowRef inWindowRef, wxTopLevelWindowMac *win) ;
863 void wxAssociateWinWithMacWindow(WindowRef inWindowRef, wxTopLevelWindowMac *win)
864 {
865 // adding NULL WindowRef is (first) surely a result of an error and
866 // nothing else :-)
867 wxCHECK_RET( inWindowRef != (WindowRef) NULL, wxT("attempt to add a NULL WindowRef to window list") );
868
869 wxWinMacWindowList[inWindowRef] = win;
870 }
871
872 void wxRemoveMacWindowAssociation(wxTopLevelWindowMac *win) ;
873 void wxRemoveMacWindowAssociation(wxTopLevelWindowMac *win)
874 {
875 MacWindowMap::iterator it;
876 for ( it = wxWinMacWindowList.begin(); it != wxWinMacWindowList.end(); ++it )
877 {
878 if ( it->second == win )
879 {
880 wxWinMacWindowList.erase(it);
881 break;
882 }
883 }
884 }
885
886 // ----------------------------------------------------------------------------
887 // wxTopLevelWindowMac creation
888 // ----------------------------------------------------------------------------
889
890 wxTopLevelWindowMac *wxTopLevelWindowMac::s_macDeactivateWindow = NULL;
891
892 typedef struct
893 {
894 wxPoint m_position ;
895 wxSize m_size ;
896 bool m_wasResizable ;
897 } FullScreenData ;
898
899 void wxTopLevelWindowMac::Init()
900 {
901 m_iconized =
902 m_maximizeOnShow = false;
903 m_macWindow = NULL ;
904
905 m_macEventHandler = NULL ;
906 m_macFullScreenData = NULL ;
907 }
908
909 class wxMacDeferredWindowDeleter : public wxObject
910 {
911 public :
912 wxMacDeferredWindowDeleter( WindowRef windowRef )
913 {
914 m_macWindow = windowRef ;
915 }
916
917 virtual ~wxMacDeferredWindowDeleter()
918 {
919 UMADisposeWindow( (WindowRef) m_macWindow ) ;
920 }
921
922 protected :
923 WindowRef m_macWindow ;
924 } ;
925
926 bool wxTopLevelWindowMac::Create(wxWindow *parent,
927 wxWindowID id,
928 const wxString& title,
929 const wxPoint& pos,
930 const wxSize& size,
931 long style,
932 const wxString& name)
933 {
934 // init our fields
935 Init();
936
937 m_windowStyle = style;
938
939 SetName( name );
940
941 m_windowId = id == -1 ? NewControlId() : id;
942 wxWindow::SetLabel( title ) ;
943
944 MacCreateRealWindow( title, pos , size , style , name ) ;
945
946 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
947
948 if (GetExtraStyle() & wxFRAME_EX_METAL)
949 MacSetMetalAppearance(true);
950
951 wxTopLevelWindows.Append(this);
952
953 if ( parent )
954 parent->AddChild(this);
955
956 return true;
957 }
958
959 wxTopLevelWindowMac::~wxTopLevelWindowMac()
960 {
961 if ( m_macWindow )
962 {
963 #if wxUSE_TOOLTIPS
964 wxToolTip::NotifyWindowDelete(m_macWindow) ;
965 #endif
966 wxPendingDelete.Append( new wxMacDeferredWindowDeleter( (WindowRef) m_macWindow ) ) ;
967 }
968
969 if ( m_macEventHandler )
970 {
971 ::RemoveEventHandler((EventHandlerRef) m_macEventHandler);
972 m_macEventHandler = NULL ;
973 }
974
975 wxRemoveMacWindowAssociation( this ) ;
976
977 if ( wxModelessWindows.Find(this) )
978 wxModelessWindows.DeleteObject(this);
979
980 FullScreenData *data = (FullScreenData *) m_macFullScreenData ;
981 delete data ;
982 m_macFullScreenData = NULL ;
983
984 // avoid dangling refs
985 if ( s_macDeactivateWindow == this )
986 s_macDeactivateWindow = NULL;
987 }
988
989
990 // ----------------------------------------------------------------------------
991 // wxTopLevelWindowMac maximize/minimize
992 // ----------------------------------------------------------------------------
993
994 void wxTopLevelWindowMac::Maximize(bool maximize)
995 {
996 Point idealSize = { 0 , 0 } ;
997 if ( maximize )
998 {
999 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1000 HIRect bounds ;
1001 HIWindowGetAvailablePositioningBounds(kCGNullDirectDisplay,kHICoordSpace72DPIGlobal,
1002 &bounds);
1003 idealSize.h = bounds.size.width;
1004 idealSize.v = bounds.size.height;
1005 #else
1006 Rect rect ;
1007 GetAvailableWindowPositioningBounds(GetMainDevice(),&rect) ;
1008 idealSize.h = rect.right - rect.left ;
1009 idealSize.v = rect.bottom - rect.top ;
1010 #endif
1011 }
1012 ZoomWindowIdeal( (WindowRef)m_macWindow , maximize ? inZoomOut : inZoomIn , &idealSize ) ;
1013 }
1014
1015 bool wxTopLevelWindowMac::IsMaximized() const
1016 {
1017 return IsWindowInStandardState( (WindowRef)m_macWindow , NULL , NULL ) ;
1018 }
1019
1020 void wxTopLevelWindowMac::Iconize(bool iconize)
1021 {
1022 if ( IsWindowCollapsable( (WindowRef)m_macWindow) )
1023 CollapseWindow( (WindowRef)m_macWindow , iconize ) ;
1024 }
1025
1026 bool wxTopLevelWindowMac::IsIconized() const
1027 {
1028 return IsWindowCollapsed((WindowRef)m_macWindow ) ;
1029 }
1030
1031 void wxTopLevelWindowMac::Restore()
1032 {
1033 if ( IsMaximized() )
1034 Maximize(false);
1035 else if ( IsIconized() )
1036 Iconize(false);
1037 }
1038
1039 // ----------------------------------------------------------------------------
1040 // wxTopLevelWindowMac misc
1041 // ----------------------------------------------------------------------------
1042
1043 wxPoint wxTopLevelWindowMac::GetClientAreaOrigin() const
1044 {
1045 return wxPoint(0, 0) ;
1046 }
1047
1048 void wxTopLevelWindowMac::MacSetBackgroundBrush( const wxBrush &brush )
1049 {
1050 wxTopLevelWindowBase::MacSetBackgroundBrush( brush ) ;
1051
1052 if ( m_macBackgroundBrush.Ok() && m_macBackgroundBrush.GetStyle() != wxTRANSPARENT && m_macBackgroundBrush.MacGetBrushKind() == kwxMacBrushTheme )
1053 {
1054 SetThemeWindowBackground( (WindowRef) m_macWindow , m_macBackgroundBrush.MacGetTheme() , false ) ;
1055 }
1056 }
1057
1058 void wxTopLevelWindowMac::MacInstallTopLevelWindowEventHandler()
1059 {
1060 if ( m_macEventHandler != NULL )
1061 {
1062 verify_noerr( ::RemoveEventHandler( (EventHandlerRef) m_macEventHandler ) ) ;
1063 }
1064
1065 InstallWindowEventHandler(
1066 MAC_WXHWND(m_macWindow), GetwxMacTopLevelEventHandlerUPP(),
1067 GetEventTypeCount(eventList), eventList, this, (EventHandlerRef *)&m_macEventHandler );
1068 }
1069
1070 void wxTopLevelWindowMac::MacCreateRealWindow(
1071 const wxString& title,
1072 const wxPoint& pos,
1073 const wxSize& size,
1074 long style,
1075 const wxString& name )
1076 {
1077 OSStatus err = noErr ;
1078 SetName(name);
1079 m_windowStyle = style;
1080 m_isShown = false;
1081
1082 // create frame.
1083 int x = (int)pos.x;
1084 int y = (int)pos.y;
1085
1086 Rect theBoundsRect;
1087 wxRect display = wxGetClientDisplayRect() ;
1088
1089 if ( x == wxDefaultPosition.x )
1090 x = display.x ;
1091
1092 if ( y == wxDefaultPosition.y )
1093 y = display.y ;
1094
1095 int w = WidthDefault(size.x);
1096 int h = HeightDefault(size.y);
1097
1098 ::SetRect(&theBoundsRect, x, y , x + w, y + h);
1099
1100 // translate the window attributes in the appropriate window class and attributes
1101 WindowClass wclass = 0;
1102 WindowAttributes attr = kWindowNoAttributes ;
1103 WindowGroupRef group = NULL ;
1104
1105 if ( HasFlag( wxFRAME_TOOL_WINDOW) )
1106 {
1107 if (
1108 HasFlag( wxMINIMIZE_BOX ) || HasFlag( wxMAXIMIZE_BOX ) ||
1109 HasFlag( wxSYSTEM_MENU ) || HasFlag( wxCAPTION ) ||
1110 HasFlag(wxTINY_CAPTION_HORIZ) || HasFlag(wxTINY_CAPTION_VERT)
1111 )
1112 {
1113 wclass = kFloatingWindowClass ;
1114
1115 if ( HasFlag(wxTINY_CAPTION_VERT) )
1116 attr |= kWindowSideTitlebarAttribute ;
1117 }
1118 else
1119 {
1120 wclass = kPlainWindowClass ;
1121 }
1122 }
1123 else if ( HasFlag( wxPOPUP_WINDOW ) )
1124 {
1125 // TEMPORARY HACK!
1126 // Until we've got a real wxPopupWindow class on wxMac make it a
1127 // little easier for wxFrame to be used to emulate it and workaround
1128 // the lack of wxPopupWindow.
1129 if ( HasFlag( wxBORDER_NONE ) )
1130 wclass = kHelpWindowClass ; // has no border
1131 else
1132 wclass = kPlainWindowClass ; // has a single line border, it will have to do for now
1133 //attr |= kWindowNoShadowAttribute; // turn off the shadow Should we??
1134 group = GetWindowGroupOfClass( // float above other windows
1135 kFloatingWindowClass) ;
1136 }
1137 else if ( HasFlag( wxCAPTION ) )
1138 {
1139 wclass = kDocumentWindowClass ;
1140 attr |= kWindowInWindowMenuAttribute ;
1141 }
1142 #if defined( __WXMAC__ ) && TARGET_API_MAC_OSX && ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
1143 else if ( HasFlag( wxFRAME_DRAWER ) )
1144 {
1145 wclass = kDrawerWindowClass;
1146 }
1147 #endif //10.2 and up
1148 else
1149 {
1150 if ( HasFlag( wxMINIMIZE_BOX ) || HasFlag( wxMAXIMIZE_BOX ) ||
1151 HasFlag( wxCLOSE_BOX ) || HasFlag( wxSYSTEM_MENU ) )
1152 {
1153 wclass = kDocumentWindowClass ;
1154 }
1155 else
1156 {
1157 wclass = kPlainWindowClass ;
1158 }
1159 }
1160
1161 if ( wclass != kPlainWindowClass )
1162 {
1163 if ( HasFlag( wxMINIMIZE_BOX ) )
1164 attr |= kWindowCollapseBoxAttribute ;
1165
1166 if ( HasFlag( wxMAXIMIZE_BOX ) )
1167 attr |= kWindowFullZoomAttribute ;
1168
1169 if ( HasFlag( wxRESIZE_BORDER ) )
1170 attr |= kWindowResizableAttribute ;
1171
1172 if ( HasFlag( wxCLOSE_BOX) )
1173 attr |= kWindowCloseBoxAttribute ;
1174 }
1175
1176 // turn on live resizing (OS X only)
1177 if (UMAGetSystemVersion() >= 0x1000)
1178 attr |= kWindowLiveResizeAttribute;
1179
1180 if ( HasFlag(wxSTAY_ON_TOP) )
1181 group = GetWindowGroupOfClass(kUtilityWindowClass) ;
1182
1183 if ( HasFlag( wxFRAME_FLOAT_ON_PARENT ) )
1184 group = GetWindowGroupOfClass(kFloatingWindowClass) ;
1185
1186 attr |= kWindowCompositingAttribute;
1187 #if 0 // wxMAC_USE_CORE_GRAPHICS ; TODO : decide on overall handling of high dpi screens (pixel vs userscale)
1188 attr |= kWindowFrameworkScaledAttribute;
1189 #endif
1190
1191 if ( HasFlag(wxFRAME_SHAPED) )
1192 {
1193 WindowDefSpec customWindowDefSpec;
1194 customWindowDefSpec.defType = kWindowDefProcPtr;
1195 customWindowDefSpec.u.defProc =
1196 #ifdef __LP64__
1197 (WindowDefUPP) wxShapedMacWindowDef;
1198 #else
1199 NewWindowDefUPP(wxShapedMacWindowDef);
1200 #endif
1201 err = ::CreateCustomWindow( &customWindowDefSpec, wclass,
1202 attr, &theBoundsRect,
1203 (WindowRef*) &m_macWindow);
1204 }
1205 else
1206 {
1207 err = ::CreateNewWindow( wclass , attr , &theBoundsRect , (WindowRef*)&m_macWindow ) ;
1208 }
1209
1210 if ( err == noErr && m_macWindow != NULL && group != NULL )
1211 SetWindowGroup( (WindowRef) m_macWindow , group ) ;
1212
1213 wxCHECK_RET( err == noErr, wxT("Mac OS error when trying to create new window") );
1214
1215 // setup a separate group for each window, so that overlays can be handled easily
1216 verify_noerr( CreateWindowGroup( kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrHideOnCollapse, &group ));
1217 verify_noerr( SetWindowGroupParent( group, GetWindowGroup( (WindowRef) m_macWindow )));
1218 verify_noerr( SetWindowGroup( (WindowRef) m_macWindow , group ));
1219
1220 // the create commands are only for content rect,
1221 // so we have to set the size again as structure bounds
1222 SetWindowBounds( (WindowRef) m_macWindow , kWindowStructureRgn , &theBoundsRect ) ;
1223
1224 wxAssociateWinWithMacWindow( (WindowRef) m_macWindow , this ) ;
1225 UMASetWTitle( (WindowRef) m_macWindow , title , m_font.GetEncoding() ) ;
1226 m_peer = new wxMacControl(this , true /*isRootControl*/) ;
1227
1228 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1229 // the content view, so we have to retrieve it explicitly
1230 HIViewFindByID( HIViewGetRoot( (WindowRef) m_macWindow ) , kHIViewWindowContentID ,
1231 m_peer->GetControlRefAddr() ) ;
1232 if ( !m_peer->Ok() )
1233 {
1234 // compatibility mode fallback
1235 GetRootControl( (WindowRef) m_macWindow , m_peer->GetControlRefAddr() ) ;
1236 }
1237
1238 // the root control level handler
1239 MacInstallEventHandler( (WXWidget) m_peer->GetControlRef() ) ;
1240
1241 // Causes the inner part of the window not to be metal
1242 // if the style is used before window creation.
1243 #if 0 // TARGET_API_MAC_OSX
1244 if ( m_macUsesCompositing && m_macWindow != NULL )
1245 {
1246 if ( GetExtraStyle() & wxFRAME_EX_METAL )
1247 MacSetMetalAppearance( true ) ;
1248 }
1249 #endif
1250
1251 // the frame window event handler
1252 InstallStandardEventHandler( GetWindowEventTarget(MAC_WXHWND(m_macWindow)) ) ;
1253 MacInstallTopLevelWindowEventHandler() ;
1254
1255 DoSetWindowVariant( m_windowVariant ) ;
1256
1257 m_macFocus = NULL ;
1258
1259 if ( HasFlag(wxFRAME_SHAPED) )
1260 {
1261 // default shape matches the window size
1262 wxRegion rgn( 0, 0, w, h );
1263 SetShape( rgn );
1264 }
1265
1266 wxWindowCreateEvent event(this);
1267 GetEventHandler()->ProcessEvent(event);
1268 }
1269
1270 void wxTopLevelWindowMac::ClearBackground()
1271 {
1272 wxWindow::ClearBackground() ;
1273 }
1274
1275 // Raise the window to the top of the Z order
1276 void wxTopLevelWindowMac::Raise()
1277 {
1278 ::SelectWindow( (WindowRef)m_macWindow ) ;
1279 }
1280
1281 // Lower the window to the bottom of the Z order
1282 void wxTopLevelWindowMac::Lower()
1283 {
1284 ::SendBehind( (WindowRef)m_macWindow , NULL ) ;
1285 }
1286
1287 void wxTopLevelWindowMac::MacDelayedDeactivation(long timestamp)
1288 {
1289 if (s_macDeactivateWindow)
1290 {
1291 wxLogTrace(TRACE_ACTIVATE,
1292 wxT("Doing delayed deactivation of %p"),
1293 s_macDeactivateWindow);
1294
1295 s_macDeactivateWindow->MacActivate(timestamp, false);
1296 }
1297 }
1298
1299 void wxTopLevelWindowMac::MacActivate( long timestamp , bool inIsActivating )
1300 {
1301 wxLogTrace(TRACE_ACTIVATE, wxT("TopLevel=%p::MacActivate"), this);
1302
1303 if (s_macDeactivateWindow == this)
1304 s_macDeactivateWindow = NULL;
1305
1306 MacDelayedDeactivation(timestamp);
1307 MacPropagateHiliteChanged() ;
1308 }
1309
1310 void wxTopLevelWindowMac::SetTitle(const wxString& title)
1311 {
1312 wxWindow::SetLabel( title ) ;
1313 UMASetWTitle( (WindowRef)m_macWindow , title , m_font.GetEncoding() ) ;
1314 }
1315
1316 wxString wxTopLevelWindowMac::GetTitle() const
1317 {
1318 return wxWindow::GetLabel();
1319 }
1320
1321 bool wxTopLevelWindowMac::Show(bool show)
1322 {
1323 if ( !wxTopLevelWindowBase::Show(show) )
1324 return false;
1325
1326 bool plainTransition = false;
1327
1328 #if wxUSE_SYSTEM_OPTIONS
1329 // code contributed by Ryan Wilcox December 18, 2003
1330 plainTransition = UMAGetSystemVersion() >= 0x1000 ;
1331 if ( wxSystemOptions::HasOption(wxMAC_WINDOW_PLAIN_TRANSITION) )
1332 plainTransition = ( wxSystemOptions::GetOptionInt( wxMAC_WINDOW_PLAIN_TRANSITION ) == 1 ) ;
1333 #endif
1334
1335 if (show)
1336 {
1337 if ( plainTransition )
1338 ::ShowWindow( (WindowRef)m_macWindow );
1339 else
1340 ::TransitionWindow( (WindowRef)m_macWindow, kWindowZoomTransitionEffect, kWindowShowTransitionAction, NULL );
1341
1342 ::SelectWindow( (WindowRef)m_macWindow ) ;
1343
1344 // because apps expect a size event to occur at this moment
1345 wxSizeEvent event(GetSize() , m_windowId);
1346 event.SetEventObject(this);
1347 GetEventHandler()->ProcessEvent(event);
1348 }
1349 else
1350 {
1351 if ( plainTransition )
1352 ::HideWindow( (WindowRef)m_macWindow );
1353 else
1354 ::TransitionWindow( (WindowRef)m_macWindow, kWindowZoomTransitionEffect, kWindowHideTransitionAction, NULL );
1355 }
1356
1357 MacPropagateVisibilityChanged() ;
1358
1359 return true ;
1360 }
1361
1362 bool wxTopLevelWindowMac::ShowFullScreen(bool show, long style)
1363 {
1364 if ( show )
1365 {
1366 FullScreenData *data = (FullScreenData *)m_macFullScreenData ;
1367 delete data ;
1368 data = new FullScreenData() ;
1369
1370 m_macFullScreenData = data ;
1371 data->m_position = GetPosition() ;
1372 data->m_size = GetSize() ;
1373 data->m_wasResizable = MacGetWindowAttributes() & kWindowResizableAttribute ;
1374
1375 if ( style & wxFULLSCREEN_NOMENUBAR )
1376 HideMenuBar() ;
1377
1378 wxRect client = wxGetClientDisplayRect() ;
1379
1380 int left , top , right , bottom ;
1381 int x, y, w, h ;
1382
1383 x = client.x ;
1384 y = client.y ;
1385 w = client.width ;
1386 h = client.height ;
1387
1388 MacGetContentAreaInset( left , top , right , bottom ) ;
1389
1390 if ( style & wxFULLSCREEN_NOCAPTION )
1391 {
1392 y -= top ;
1393 h += top ;
1394 }
1395
1396 if ( style & wxFULLSCREEN_NOBORDER )
1397 {
1398 x -= left ;
1399 w += left + right ;
1400 h += bottom ;
1401 }
1402
1403 if ( style & wxFULLSCREEN_NOTOOLBAR )
1404 {
1405 // TODO
1406 }
1407
1408 if ( style & wxFULLSCREEN_NOSTATUSBAR )
1409 {
1410 // TODO
1411 }
1412
1413 SetSize( x , y , w, h ) ;
1414 if ( data->m_wasResizable )
1415 MacChangeWindowAttributes( kWindowNoAttributes , kWindowResizableAttribute ) ;
1416 }
1417 else
1418 {
1419 ShowMenuBar() ;
1420 FullScreenData *data = (FullScreenData *) m_macFullScreenData ;
1421 if ( data->m_wasResizable )
1422 MacChangeWindowAttributes( kWindowResizableAttribute , kWindowNoAttributes ) ;
1423 SetPosition( data->m_position ) ;
1424 SetSize( data->m_size ) ;
1425
1426 delete data ;
1427 m_macFullScreenData = NULL ;
1428 }
1429
1430 return false;
1431 }
1432
1433 bool wxTopLevelWindowMac::IsFullScreen() const
1434 {
1435 return m_macFullScreenData != NULL ;
1436 }
1437
1438
1439 bool wxTopLevelWindowMac::SetTransparent(wxByte alpha)
1440 {
1441 OSStatus result = SetWindowAlpha((WindowRef)m_macWindow, float(alpha)/255.0);
1442 return result == noErr;
1443 }
1444
1445
1446 bool wxTopLevelWindowMac::CanSetTransparent()
1447 {
1448 return true;
1449 }
1450
1451
1452 void wxTopLevelWindowMac::SetExtraStyle(long exStyle)
1453 {
1454 if ( GetExtraStyle() == exStyle )
1455 return ;
1456
1457 wxTopLevelWindowBase::SetExtraStyle( exStyle ) ;
1458
1459 #if TARGET_API_MAC_OSX
1460 if ( m_macWindow != NULL )
1461 {
1462 bool metal = GetExtraStyle() & wxFRAME_EX_METAL ;
1463 if ( MacGetMetalAppearance() != metal )
1464 MacSetMetalAppearance( metal ) ;
1465 }
1466 #endif
1467 }
1468
1469 // TODO: switch to structure bounds -
1470 // we are still using coordinates of the content view
1471 //
1472 void wxTopLevelWindowMac::MacGetContentAreaInset( int &left , int &top , int &right , int &bottom )
1473 {
1474 Rect content, structure ;
1475
1476 GetWindowBounds( (WindowRef) m_macWindow, kWindowStructureRgn , &structure ) ;
1477 GetWindowBounds( (WindowRef) m_macWindow, kWindowContentRgn , &content ) ;
1478
1479 left = content.left - structure.left ;
1480 top = content.top - structure.top ;
1481 right = structure.right - content.right ;
1482 bottom = structure.bottom - content.bottom ;
1483 }
1484
1485 void wxTopLevelWindowMac::DoMoveWindow(int x, int y, int width, int height)
1486 {
1487 m_cachedClippedRectValid = false ;
1488 Rect bounds = { y , x , y + height , x + width } ;
1489 verify_noerr(SetWindowBounds( (WindowRef) m_macWindow, kWindowStructureRgn , &bounds )) ;
1490 wxWindowMac::MacSuperChangedPosition() ; // like this only children will be notified
1491 }
1492
1493 void wxTopLevelWindowMac::DoGetPosition( int *x, int *y ) const
1494 {
1495 Rect bounds ;
1496
1497 verify_noerr(GetWindowBounds((WindowRef) m_macWindow, kWindowStructureRgn , &bounds )) ;
1498
1499 if (x)
1500 *x = bounds.left ;
1501 if (y)
1502 *y = bounds.top ;
1503 }
1504
1505 void wxTopLevelWindowMac::DoGetSize( int *width, int *height ) const
1506 {
1507 Rect bounds ;
1508
1509 verify_noerr(GetWindowBounds((WindowRef) m_macWindow, kWindowStructureRgn , &bounds )) ;
1510
1511 if (width)
1512 *width = bounds.right - bounds.left ;
1513 if (height)
1514 *height = bounds.bottom - bounds.top ;
1515 }
1516
1517 void wxTopLevelWindowMac::DoGetClientSize( int *width, int *height ) const
1518 {
1519 Rect bounds ;
1520
1521 verify_noerr(GetWindowBounds((WindowRef) m_macWindow, kWindowContentRgn , &bounds )) ;
1522
1523 if (width)
1524 *width = bounds.right - bounds.left ;
1525 if (height)
1526 *height = bounds.bottom - bounds.top ;
1527 }
1528
1529 void wxTopLevelWindowMac::MacSetMetalAppearance( bool set )
1530 {
1531 #if TARGET_API_MAC_OSX
1532 MacChangeWindowAttributes( set ? kWindowMetalAttribute : kWindowNoAttributes ,
1533 set ? kWindowNoAttributes : kWindowMetalAttribute ) ;
1534 #endif
1535 }
1536
1537 bool wxTopLevelWindowMac::MacGetMetalAppearance() const
1538 {
1539 #if TARGET_API_MAC_OSX
1540 return MacGetWindowAttributes() & kWindowMetalAttribute ;
1541 #else
1542 return false ;
1543 #endif
1544 }
1545
1546 void wxTopLevelWindowMac::MacChangeWindowAttributes( wxUint32 attributesToSet , wxUint32 attributesToClear )
1547 {
1548 ChangeWindowAttributes( (WindowRef)m_macWindow, attributesToSet, attributesToClear ) ;
1549 }
1550
1551 wxUint32 wxTopLevelWindowMac::MacGetWindowAttributes() const
1552 {
1553 UInt32 attr = 0 ;
1554 GetWindowAttributes( (WindowRef) m_macWindow, &attr ) ;
1555
1556 return attr ;
1557 }
1558
1559 void wxTopLevelWindowMac::MacPerformUpdates()
1560 {
1561 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1562 // for composited windows this also triggers a redraw of all
1563 // invalid views in the window
1564 if ( UMAGetSystemVersion() >= 0x1030 )
1565 HIWindowFlush((WindowRef) m_macWindow) ;
1566 else
1567 #endif
1568 {
1569 // the only way to trigger the redrawing on earlier systems is to call
1570 // ReceiveNextEvent
1571
1572 EventRef currentEvent = (EventRef) wxTheApp->MacGetCurrentEvent() ;
1573 UInt32 currentEventClass = 0 ;
1574 if ( currentEvent != NULL )
1575 {
1576 currentEventClass = ::GetEventClass( currentEvent ) ;
1577 ::GetEventKind( currentEvent ) ;
1578 }
1579
1580 if ( currentEventClass != kEventClassMenu )
1581 {
1582 // when tracking a menu, strange redraw errors occur if we flush now, so leave..
1583 EventRef theEvent;
1584 ReceiveNextEvent( 0 , NULL , kEventDurationNoWait , false , &theEvent ) ;
1585 }
1586 }
1587 }
1588
1589 // Attracts the users attention to this window if the application is
1590 // inactive (should be called when a background event occurs)
1591
1592 static pascal void wxMacNMResponse( NMRecPtr ptr )
1593 {
1594 NMRemove( ptr ) ;
1595 DisposePtr( (Ptr)ptr ) ;
1596 }
1597
1598 void wxTopLevelWindowMac::RequestUserAttention(int flags )
1599 {
1600 NMRecPtr notificationRequest = (NMRecPtr) NewPtr( sizeof( NMRec) ) ;
1601 static wxMacNMUPP nmupp( wxMacNMResponse );
1602
1603 memset( notificationRequest , 0 , sizeof(*notificationRequest) ) ;
1604 notificationRequest->qType = nmType ;
1605 notificationRequest->nmMark = 1 ;
1606 notificationRequest->nmIcon = 0 ;
1607 notificationRequest->nmSound = 0 ;
1608 notificationRequest->nmStr = NULL ;
1609 notificationRequest->nmResp = nmupp ;
1610
1611 verify_noerr( NMInstall( notificationRequest ) ) ;
1612 }
1613
1614 // ---------------------------------------------------------------------------
1615 // Shape implementation
1616 // ---------------------------------------------------------------------------
1617
1618
1619 bool wxTopLevelWindowMac::SetShape(const wxRegion& region)
1620 {
1621 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false,
1622 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1623
1624 // The empty region signifies that the shape
1625 // should be removed from the window.
1626 if ( region.IsEmpty() )
1627 {
1628 wxSize sz = GetClientSize();
1629 wxRegion rgn(0, 0, sz.x, sz.y);
1630 if ( rgn.IsEmpty() )
1631 return false ;
1632 else
1633 return SetShape(rgn);
1634 }
1635
1636 // Make a copy of the region
1637 RgnHandle shapeRegion = NewRgn();
1638 CopyRgn( (RgnHandle)region.GetWXHRGN(), shapeRegion );
1639
1640 // Dispose of any shape region we may already have
1641 RgnHandle oldRgn = (RgnHandle)GetWRefCon( (WindowRef)MacGetWindowRef() );
1642 if ( oldRgn )
1643 DisposeRgn(oldRgn);
1644
1645 // Save the region so we can use it later
1646 SetWRefCon((WindowRef)MacGetWindowRef(), (URefCon)shapeRegion);
1647
1648 // inform the window manager that the window has changed shape
1649 ReshapeCustomWindow((WindowRef)MacGetWindowRef());
1650
1651 return true;
1652 }
1653
1654 // ---------------------------------------------------------------------------
1655 // Support functions for shaped windows, based on Apple's CustomWindow sample at
1656 // http://developer.apple.com/samplecode/Sample_Code/Human_Interface_Toolbox/Mac_OS_High_Level_Toolbox/CustomWindow.htm
1657 // ---------------------------------------------------------------------------
1658
1659 static void wxShapedMacWindowGetPos(WindowRef window, Rect* inRect)
1660 {
1661 GetWindowPortBounds(window, inRect);
1662 Point pt = { inRect->top ,inRect->left };
1663 wxMacLocalToGlobal( window, &pt ) ;
1664 inRect->bottom += pt.v - inRect->top;
1665 inRect->right += pt.h - inRect->left;
1666 inRect->top = pt.v;
1667 inRect->left = pt.h;
1668 }
1669
1670 static SInt32 wxShapedMacWindowGetFeatures(WindowRef window, SInt32 param)
1671 {
1672 /*------------------------------------------------------
1673 Define which options your custom window supports.
1674 --------------------------------------------------------*/
1675 //just enable everything for our demo
1676 *(OptionBits*)param =
1677 //kWindowCanGrow |
1678 //kWindowCanZoom |
1679 //kWindowCanCollapse |
1680 //kWindowCanGetWindowRegion |
1681 //kWindowHasTitleBar |
1682 //kWindowSupportsDragHilite |
1683 kWindowCanDrawInCurrentPort |
1684 //kWindowCanMeasureTitle |
1685 kWindowWantsDisposeAtProcessDeath |
1686 kWindowSupportsGetGrowImageRegion |
1687 kWindowDefSupportsColorGrafPort;
1688
1689 return 1;
1690 }
1691
1692 // The content region is left as a rectangle matching the window size, this is
1693 // so the origin in the paint event, and etc. still matches what the
1694 // programmer expects.
1695 static void wxShapedMacWindowContentRegion(WindowRef window, RgnHandle rgn)
1696 {
1697 SetEmptyRgn(rgn);
1698 wxTopLevelWindowMac* win = wxFindWinFromMacWindow(window);
1699 if (win)
1700 {
1701 Rect r ;
1702 wxShapedMacWindowGetPos( window, &r ) ;
1703 RectRgn( rgn , &r ) ;
1704 }
1705 }
1706
1707 // The structure region is set to the shape given to the SetShape method.
1708 static void wxShapedMacWindowStructureRegion(WindowRef window, RgnHandle rgn)
1709 {
1710 RgnHandle cachedRegion = (RgnHandle) GetWRefCon(window);
1711
1712 SetEmptyRgn(rgn);
1713 if (cachedRegion)
1714 {
1715 Rect windowRect;
1716 wxShapedMacWindowGetPos(window, &windowRect); // how big is the window
1717 CopyRgn(cachedRegion, rgn); // make a copy of our cached region
1718 OffsetRgn(rgn, windowRect.left, windowRect.top); // position it over window
1719 //MapRgn(rgn, &mMaskSize, &windowRect); //scale it to our actual window size
1720 }
1721 }
1722
1723 static SInt32 wxShapedMacWindowGetRegion(WindowRef window, SInt32 param)
1724 {
1725 GetWindowRegionPtr rgnRec = (GetWindowRegionPtr)param;
1726
1727 if (rgnRec == NULL)
1728 return paramErr;
1729
1730 switch (rgnRec->regionCode)
1731 {
1732 case kWindowStructureRgn:
1733 wxShapedMacWindowStructureRegion(window, rgnRec->winRgn);
1734 break;
1735
1736 case kWindowContentRgn:
1737 wxShapedMacWindowContentRegion(window, rgnRec->winRgn);
1738 break;
1739
1740 default:
1741 SetEmptyRgn(rgnRec->winRgn);
1742 break;
1743 }
1744
1745 return noErr;
1746 }
1747
1748 // Determine the region of the window which was hit
1749 //
1750 static SInt32 wxShapedMacWindowHitTest(WindowRef window, SInt32 param)
1751 {
1752 Point hitPoint;
1753 static RgnHandle tempRgn = NULL;
1754
1755 if (tempRgn == NULL)
1756 tempRgn = NewRgn();
1757
1758 // get the point clicked
1759 SetPt( &hitPoint, LoWord(param), HiWord(param) );
1760
1761 // Mac OS 8.5 or later
1762 wxShapedMacWindowStructureRegion(window, tempRgn);
1763 if (PtInRgn( hitPoint, tempRgn )) //in window content region?
1764 return wInContent;
1765
1766 // no significant area was hit
1767 return wNoHit;
1768 }
1769
1770 static pascal long wxShapedMacWindowDef(short varCode, WindowRef window, SInt16 message, SInt32 param)
1771 {
1772 switch (message)
1773 {
1774 case kWindowMsgHitTest:
1775 return wxShapedMacWindowHitTest(window, param);
1776
1777 case kWindowMsgGetFeatures:
1778 return wxShapedMacWindowGetFeatures(window, param);
1779
1780 // kWindowMsgGetRegion is sent during CreateCustomWindow and ReshapeCustomWindow
1781 case kWindowMsgGetRegion:
1782 return wxShapedMacWindowGetRegion(window, param);
1783
1784 default:
1785 break;
1786 }
1787
1788 return 0;
1789 }