1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        mac/toplevel.cpp 
   3 // Purpose:     implements wxTopLevelWindow for MSW 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 2001 SciTech Software, Inc. (www.scitechsoft.com) 
   9 // License:     wxWindows license 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  21     #pragma implementation "toplevel.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  33     #include "wx/toplevel.h" 
  35     #include "wx/string.h" 
  40 #include "wx/mac/uma.h" 
  41 #include "wx/mac/aga.h" 
  42 #include "wx/tooltip.h" 
  44 #define wxMAC_DEBUG_REDRAW 0 
  45 #ifndef wxMAC_DEBUG_REDRAW 
  46 #define wxMAC_DEBUG_REDRAW 0 
  49 // ---------------------------------------------------------------------------- 
  51 // ---------------------------------------------------------------------------- 
  53 // list of all frames and modeless dialogs 
  54 wxWindowList wxModelessWindows
; 
  56 // ============================================================================ 
  57 // wxTopLevelWindowMac implementation 
  58 // ============================================================================ 
  60 // --------------------------------------------------------------------------- 
  61 // wxWindowMac utility functions 
  62 // --------------------------------------------------------------------------- 
  64 // Find an item given the Macintosh Window Reference 
  66 wxList 
*wxWinMacWindowList 
= NULL
; 
  67 wxTopLevelWindowMac 
*wxFindWinFromMacWindow(WindowRef inWindowRef
) 
  69     wxNode 
*node 
= wxWinMacWindowList
->Find((long)inWindowRef
); 
  72     return (wxTopLevelWindowMac 
*)node
->Data(); 
  75 void wxAssociateWinWithMacWindow(WindowRef inWindowRef
, wxTopLevelWindowMac 
*win
) 
  77     // adding NULL WindowRef is (first) surely a result of an error and 
  78     // (secondly) breaks menu command processing 
  79     wxCHECK_RET( inWindowRef 
!= (WindowRef
) NULL
, "attempt to add a NULL WindowRef to window list" ); 
  81     if ( !wxWinMacWindowList
->Find((long)inWindowRef
) ) 
  82         wxWinMacWindowList
->Append((long)inWindowRef
, win
); 
  85 void wxRemoveMacWindowAssociation(wxTopLevelWindowMac 
*win
) 
  87     wxWinMacWindowList
->DeleteObject(win
); 
  91 // ---------------------------------------------------------------------------- 
  92 // wxTopLevelWindowMac creation 
  93 // ---------------------------------------------------------------------------- 
  95 WindowRef 
wxTopLevelWindowMac::s_macWindowInUpdate 
= NULL
; 
  97 void wxTopLevelWindowMac::Init() 
 100     m_maximizeOnShow 
= FALSE
; 
 101     m_macNoEraseUpdateRgn 
= NewRgn() ; 
 102     m_macNeedsErasing 
= false ; 
 105 bool wxTopLevelWindowMac::Create(wxWindow 
*parent
, 
 107                                  const wxString
& title
, 
 111                                  const wxString
& name
) 
 116     m_windowStyle 
= style
; 
 120     m_windowId 
= id 
== -1 ? NewControlId() : id
; 
 122     wxTopLevelWindows
.Append(this); 
 125         parent
->AddChild(this); 
 130 wxTopLevelWindowMac::~wxTopLevelWindowMac() 
 132     wxToolTip::NotifyWindowDelete(m_macWindow
) ; 
 133     UMADisposeWindow( m_macWindow 
) ; 
 135     wxRemoveMacWindowAssociation( this ) ; 
 137     wxTopLevelWindows
.DeleteObject(this); 
 139     if ( wxModelessWindows
.Find(this) ) 
 140         wxModelessWindows
.DeleteObject(this); 
 142     // If this is the last top-level window, exit. 
 143     if ( wxTheApp 
&& (wxTopLevelWindows
.Number() == 0) ) 
 145         wxTheApp
->SetTopWindow(NULL
); 
 147         if ( wxTheApp
->GetExitOnFrameDelete() ) 
 149           wxTheApp
->ExitMainLoop() ;         
 152     DisposeRgn( m_macNoEraseUpdateRgn 
) ; 
 156 // ---------------------------------------------------------------------------- 
 157 // wxTopLevelWindowMac maximize/minimize 
 158 // ---------------------------------------------------------------------------- 
 160 void wxTopLevelWindowMac::Maximize(bool maximize
) 
 162     // not available on mac 
 165 bool wxTopLevelWindowMac::IsMaximized() const 
 170 void wxTopLevelWindowMac::Iconize(bool iconize
) 
 172     // not available on mac 
 175 bool wxTopLevelWindowMac::IsIconized() const 
 177         // mac dialogs cannot be iconized 
 181 void wxTopLevelWindowMac::Restore() 
 183     // not available on mac 
 186 // ---------------------------------------------------------------------------- 
 187 // wxTopLevelWindowMac misc 
 188 // ---------------------------------------------------------------------------- 
 190 void wxTopLevelWindowMac::SetIcon(const wxIcon
& icon
) 
 193     wxTopLevelWindowBase::SetIcon(icon
); 
 196 void  wxTopLevelWindowMac::MacCreateRealWindow( const wxString
& title
, 
 200            const wxString
& name 
)  
 203   m_windowStyle 
= style
; 
 224     ::SetRect(&theBoundsRect
, m_x
, m_y 
, m_x 
+ m_width
, m_y 
+ m_height
); 
 226     // translate the window attributes in the appropriate window class and attributes 
 228     WindowClass wclass 
= 0; 
 229     WindowAttributes attr 
= kWindowNoAttributes 
; 
 231     if ( HasFlag(wxTINY_CAPTION_HORIZ
) ||  HasFlag(wxTINY_CAPTION_VERT
) ) 
 233         wclass 
= kFloatingWindowClass 
; 
 234         if ( HasFlag(wxTINY_CAPTION_VERT
) ) 
 236             attr 
|= kWindowSideTitlebarAttribute 
; 
 239     else if ( HasFlag( wxCAPTION 
) ) 
 241         if ( HasFlag( wxDIALOG_MODAL 
) ) 
 243             wclass 
= kMovableModalWindowClass 
; 
 247             wclass 
= kDocumentWindowClass 
; 
 252         wclass 
= kModalWindowClass 
; 
 255     if ( HasFlag( wxMINIMIZE_BOX 
) || HasFlag( wxMAXIMIZE_BOX 
) ) 
 257         attr 
|= kWindowFullZoomAttribute 
; 
 258         attr 
|= kWindowCollapseBoxAttribute 
; 
 260     if ( HasFlag( wxRESIZE_BORDER 
) ) 
 262         attr 
|= kWindowResizableAttribute 
; 
 264     if ( HasFlag( wxSYSTEM_MENU 
) ) 
 266         attr 
|= kWindowCloseBoxAttribute 
; 
 269     ::CreateNewWindow( wclass 
, attr 
, &theBoundsRect 
, &m_macWindow 
) ; 
 270     wxAssociateWinWithMacWindow( m_macWindow 
, this ) ; 
 272     if( wxApp::s_macDefaultEncodingIsPC 
) 
 273         label 
= wxMacMakeMacStringFromPC( title 
) ; 
 276     UMASetWTitleC( m_macWindow 
, label 
) ; 
 277     ::CreateRootControl( m_macWindow 
, &m_macRootControl 
) ; 
 282 void wxTopLevelWindowMac::MacDoGetPortClientParams(Point
* localOrigin
, Rect
* clipRect
, WindowRef 
*window 
, wxWindowMac
** rootwin 
)  
 288     clipRect
->right 
= m_width 
;//width; 
 289     clipRect
->bottom 
= m_height 
;// height; 
 290     *window 
= m_macWindow 
; 
 294 void wxTopLevelWindowMac::MacGetPortParams(Point
* localOrigin
, Rect
* clipRect
, WindowRef 
*window  
, wxWindowMac
** rootwin
)  
 300     clipRect
->right 
= m_width
; 
 301     clipRect
->bottom 
= m_height
; 
 302     *window 
= m_macWindow 
; 
 306 void wxTopLevelWindowMac::Clear() 
 308     wxMacDrawingClientHelper 
helper ( this ) ; 
 310     wxPoint origin 
= GetClientAreaOrigin() ; 
 311     GetClientSize( &w 
, &h 
) ; 
 312     ::SetThemeWindowBackground( m_macWindow 
, m_macWindowBackgroundTheme 
, false ) ; 
 313     Rect r 
= { origin
.y 
, origin
.x
, origin
.y
+h 
, origin
.x
+w 
} ; 
 317 ControlHandle 
wxTopLevelWindowMac::MacGetContainerForEmbedding()  
 319     return m_macRootControl 
; 
 323 void wxTopLevelWindowMac::MacUpdate( long timestamp
) 
 326     AGAPortHelper 
help( GetWindowPort(m_macWindow
) ) ; 
 328     AGAPortHelper 
help( (m_macWindow
) ) ; 
 331     BeginUpdate( m_macWindow 
) ; 
 333     RgnHandle       updateRgn 
= NewRgn();     
 334     RgnHandle       diffRgn 
= NewRgn() ; 
 335     if ( updateRgn 
&& diffRgn 
) 
 337         GetPortVisibleRegion( GetWindowPort( m_macWindow 
), updateRgn 
); 
 338         DiffRgn( updateRgn 
, m_macNoEraseUpdateRgn 
, diffRgn 
) ; 
 339         if ( !EmptyRgn( updateRgn 
) ) 
 341             MacRedraw( updateRgn 
, timestamp 
, m_macNeedsErasing 
|| !EmptyRgn( diffRgn 
)  ) ; 
 345         DisposeRgn( updateRgn 
); 
 347         DisposeRgn( diffRgn 
); 
 348     EndUpdate( m_macWindow 
) ; 
 349     SetEmptyRgn( m_macNoEraseUpdateRgn 
) ; 
 350     m_macNeedsErasing 
= false ; 
 354 // Raise the window to the top of the Z order 
 355 void wxTopLevelWindowMac::Raise() 
 357     ::BringToFront( m_macWindow 
) ; 
 360 // Lower the window to the bottom of the Z order 
 361 void wxTopLevelWindowMac::Lower() 
 363     ::SendBehind( m_macWindow 
, NULL 
) ; 
 368 extern int wxBusyCursorCount 
; 
 370 void wxTopLevelWindowMac::MacFireMouseEvent( EventRecord 
*ev 
) 
 372     wxMouseEvent 
event(wxEVT_LEFT_DOWN
); 
 373     bool isDown 
= !(ev
->modifiers 
& btnState
) ; // 1 is for up 
 374     bool controlDown 
= ev
->modifiers 
& controlKey 
; // for simulating right mouse 
 376     event
.m_leftDown 
= isDown 
&& !controlDown
; 
 378     event
.m_middleDown 
= FALSE
; 
 379     event
.m_rightDown 
= isDown 
&& controlDown
; 
 381     if ( ev
->what 
== mouseDown 
) 
 384             event
.SetEventType(wxEVT_RIGHT_DOWN 
) ; 
 386             event
.SetEventType(wxEVT_LEFT_DOWN 
) ; 
 388     else if ( ev
->what 
== mouseUp 
) 
 391             event
.SetEventType(wxEVT_RIGHT_UP 
) ; 
 393             event
.SetEventType(wxEVT_LEFT_UP 
) ; 
 397         event
.SetEventType(wxEVT_MOTION 
) ; 
 400     event
.m_shiftDown 
= ev
->modifiers 
& shiftKey
; 
 401     event
.m_controlDown 
= ev
->modifiers 
& controlKey
; 
 402     event
.m_altDown 
= ev
->modifiers 
& optionKey
; 
 403     event
.m_metaDown 
= ev
->modifiers 
& cmdKey
; 
 405     Point       localwhere 
= ev
->where 
; 
 409     ::SetPort( UMAGetWindowPort( m_macWindow 
) ) ; 
 410     ::GlobalToLocal( &localwhere 
) ; 
 413     if ( ev
->what 
== mouseDown 
) 
 415         if ( ev
->when 
- lastWhen 
<= GetDblTime() ) 
 417             if ( abs( localwhere
.h 
- lastWhere
.h 
) < 3 || abs( localwhere
.v 
- lastWhere
.v 
) < 3 ) 
 420                     event
.SetEventType(wxEVT_RIGHT_DCLICK 
) ; 
 422                     event
.SetEventType(wxEVT_LEFT_DCLICK 
) ; 
 428             lastWhen 
= ev
->when 
; 
 430         lastWhere 
= localwhere 
; 
 433     event
.m_x 
= localwhere
.h
; 
 434     event
.m_y 
= localwhere
.v
; 
 439     wxPoint origin = GetClientAreaOrigin() ; 
 441     event.m_x += origin.x ; 
 442     event.m_y += origin.y ; 
 445     event
.m_timeStamp 
= ev
->when
; 
 446     event
.SetEventObject(this); 
 447     if ( wxTheApp
->s_captureWindow 
) 
 451         wxTheApp
->s_captureWindow
->ScreenToClient( &x 
, &y 
) ; 
 454         wxTheApp
->s_captureWindow
->GetEventHandler()->ProcessEvent( event 
) ; 
 455         if ( ev
->what 
== mouseUp 
) 
 457             wxTheApp
->s_captureWindow 
= NULL 
; 
 458             if ( wxBusyCursorCount 
== 0 ) 
 460                 m_cursor
.MacInstall() ; 
 466         MacDispatchMouseEvent( event 
) ; 
 470 void wxTopLevelWindowMac::MacMouseDown( EventRecord 
*ev 
, short part
) 
 472     MacFireMouseEvent( ev 
) ; 
 475 void wxTopLevelWindowMac::MacMouseUp( EventRecord 
*ev 
, short part
) 
 481                 MacFireMouseEvent( ev 
) ; 
 487 void wxTopLevelWindowMac::MacMouseMoved( EventRecord 
*ev 
, short part
) 
 493                 MacFireMouseEvent( ev 
) ; 
 498 void wxTopLevelWindowMac::MacActivate( EventRecord 
*ev 
, bool inIsActivating 
) 
 500     wxActivateEvent 
event(wxEVT_ACTIVATE
, inIsActivating 
, m_windowId
); 
 501     event
.m_timeStamp 
= ev
->when 
; 
 502     event
.SetEventObject(this); 
 504     GetEventHandler()->ProcessEvent(event
); 
 506     UMAHighlightAndActivateWindow( m_macWindow 
, inIsActivating 
) ; 
 508     MacSuperEnabled( inIsActivating 
) ; 
 511 void wxTopLevelWindowMac::MacKeyDown( EventRecord 
*ev 
)  
 515 void wxTopLevelWindowMac::SetTitle(const wxString
& title
) 
 517     wxWindow::SetTitle( title 
) ; 
 521     if( wxApp::s_macDefaultEncodingIsPC 
) 
 522         label 
= wxMacMakeMacStringFromPC( m_label 
) ; 
 526     UMASetWTitleC( m_macWindow 
, label 
) ; 
 529 bool wxTopLevelWindowMac::Show(bool show
) 
 531     if ( !wxWindow::Show(show
) ) 
 536       ::ShowWindow( m_macWindow 
) ; 
 537       ::SelectWindow( m_macWindow 
) ; 
 538       // no need to generate events here, they will get them triggered by macos 
 539       // actually they should be , but apparently they are not 
 540       wxSize 
size(m_width
, m_height
); 
 541       wxSizeEvent 
event(size
, m_windowId
); 
 542       event
.SetEventObject(this); 
 543       GetEventHandler()->ProcessEvent(event
); 
 547       ::HideWindow( m_macWindow 
) ; 
 561 void wxTopLevelWindowMac::DoMoveWindow(int x
, int y
, int width
, int height
) 
 565     int former_w 
= m_width 
; 
 566     int former_h 
= m_height 
; 
 568   int actualWidth 
= width
; 
 569   int actualHeight 
= height
; 
 573     if ((m_minWidth 
!= -1) && (actualWidth 
< m_minWidth
))  
 574         actualWidth 
= m_minWidth
; 
 575     if ((m_minHeight 
!= -1) && (actualHeight 
< m_minHeight
))  
 576         actualHeight 
= m_minHeight
; 
 577     if ((m_maxWidth 
!= -1) && (actualWidth 
> m_maxWidth
))  
 578         actualWidth 
= m_maxWidth
; 
 579     if ((m_maxHeight 
!= -1) && (actualHeight 
> m_maxHeight
))  
 580         actualHeight 
= m_maxHeight
; 
 582     bool doMove 
= false ; 
 583     bool doResize 
= false ; 
 585     if ( actualX 
!= former_x 
|| actualY 
!= former_y 
) 
 589     if ( actualWidth 
!= former_w 
|| actualHeight 
!= former_h 
) 
 594     if ( doMove 
|| doResize 
) 
 598         m_width 
= actualWidth 
; 
 599         m_height 
= actualHeight 
; 
 602             ::MoveWindow(m_macWindow
, m_x
, m_y  
, false); // don't make frontmost 
 605             ::SizeWindow(m_macWindow
, m_width
, m_height  
, true);  
 607         // the OS takes care of invalidating and erasing the new area 
 608         // we have erased the old one    
 610         if ( IsKindOf( CLASSINFO( wxFrame 
) ) ) 
 612             wxFrame
* frame 
= (wxFrame
*) this ; 
 613             frame
->PositionStatusBar(); 
 614             frame
->PositionToolBar(); 
 617             wxWindowMac::MacTopLevelWindowChangedPosition() ; // like this only children will be notified 
 619         MacRepositionScrollBars() ; 
 622             wxPoint 
point(m_x
, m_y
); 
 623             wxMoveEvent 
event(point
, m_windowId
); 
 624             event
.SetEventObject(this); 
 625             GetEventHandler()->ProcessEvent(event
) ; 
 629              MacRepositionScrollBars() ; 
 630              wxSize 
size(m_width
, m_height
); 
 631              wxSizeEvent 
event(size
, m_windowId
); 
 632              event
.SetEventObject(this); 
 633              GetEventHandler()->ProcessEvent(event
); 
 640  * Invalidation Mechanism 
 642  * The update mechanism reflects exactely the windows mechanism 
 643  * the rect gets added to the window invalidate region, if the eraseBackground flag 
 644  * has been true for any part of the update rgn the background is erased in the entire region 
 645  * not just in the specified rect. 
 647  * In order to achive this, we also have an internal m_macNoEraseUpdateRgn, all rects that have  
 648  * the eraseBackground flag set to false are also added to this rgn. upon receiving an update event 
 649  * the update rgn is compared to the m_macNoEraseUpdateRgn and in case they differ, every window 
 650  * will get the eraseBackground event first 
 653 void wxTopLevelWindowMac::MacInvalidate( const Rect 
* rect
, bool eraseBackground 
)  
 656   GetPort( &formerPort 
) ; 
 657   SetPortWindowPort( m_macWindow 
) ; 
 659   m_macNeedsErasing 
|= eraseBackground 
; 
 661   // if we already know that we will have to erase, there's no need to track the rest 
 662   if ( !m_macNeedsErasing
) 
 664     // we end only here if eraseBackground is false 
 665     // if we already have a difference between m_macNoEraseUpdateRgn and UpdateRgn 
 666     // we will have to erase anyway 
 668     RgnHandle       updateRgn 
= NewRgn();     
 669     RgnHandle       diffRgn 
= NewRgn() ; 
 670     if ( updateRgn 
&& diffRgn 
) 
 672         GetWindowUpdateRgn( m_macWindow 
, updateRgn 
); 
 674         LocalToGlobal( &pt 
) ; 
 675         OffsetRgn( updateRgn 
, -pt
.h 
, -pt
.v 
) ; 
 676         DiffRgn( updateRgn 
, m_macNoEraseUpdateRgn 
, diffRgn 
) ; 
 677         if ( !EmptyRgn( diffRgn 
) ) 
 679             m_macNeedsErasing 
= true ; 
 683         DisposeRgn( updateRgn 
); 
 685         DisposeRgn( diffRgn 
); 
 687     if ( !m_macNeedsErasing 
) 
 689       RgnHandle rectRgn 
= NewRgn() ; 
 690       SetRectRgn( rectRgn 
, rect
->left 
, rect
->top 
, rect
->right 
, rect
->bottom 
) ; 
 691       UnionRgn( m_macNoEraseUpdateRgn 
, rectRgn 
, m_macNoEraseUpdateRgn 
) ; 
 692       DisposeRgn( rectRgn 
) ; 
 695   InvalWindowRect( m_macWindow 
, rect 
) ; 
 696   // turn this on to debug the refreshing cycle 
 697 #if wxMAC_DEBUG_REDRAW 
 700   SetPort( formerPort 
) ;