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::MacGetPortParams(Point
* localOrigin
, Rect
* clipRect
, WindowRef
*window
, wxWindowMac
** rootwin
)
288 clipRect
->right
= m_width
;
289 clipRect
->bottom
= m_height
;
290 *window
= m_macWindow
;
294 void wxTopLevelWindowMac::Clear()
299 ControlHandle
wxTopLevelWindowMac::MacGetContainerForEmbedding()
301 return m_macRootControl
;
305 void wxTopLevelWindowMac::MacUpdate( long timestamp
)
308 AGAPortHelper
help( GetWindowPort(m_macWindow
) ) ;
310 AGAPortHelper
help( (m_macWindow
) ) ;
312 BeginUpdate( m_macWindow
) ;
314 RgnHandle updateRgn
= NewRgn();
315 RgnHandle diffRgn
= NewRgn() ;
316 if ( updateRgn
&& diffRgn
)
318 GetPortVisibleRegion( GetWindowPort( m_macWindow
), updateRgn
);
319 DiffRgn( updateRgn
, m_macNoEraseUpdateRgn
, diffRgn
) ;
320 if ( !EmptyRgn( updateRgn
) )
322 MacRedraw( updateRgn
, timestamp
, m_macNeedsErasing
|| !EmptyRgn( diffRgn
) ) ;
326 DisposeRgn( updateRgn
);
328 DisposeRgn( diffRgn
);
329 EndUpdate( m_macWindow
) ;
330 SetEmptyRgn( m_macNoEraseUpdateRgn
) ;
331 m_macNeedsErasing
= false ;
335 // Raise the window to the top of the Z order
336 void wxTopLevelWindowMac::Raise()
338 ::BringToFront( m_macWindow
) ;
341 // Lower the window to the bottom of the Z order
342 void wxTopLevelWindowMac::Lower()
344 ::SendBehind( m_macWindow
, NULL
) ;
349 extern int wxBusyCursorCount
;
351 void wxTopLevelWindowMac::MacFireMouseEvent( EventRecord
*ev
)
353 wxMouseEvent
event(wxEVT_LEFT_DOWN
);
354 bool isDown
= !(ev
->modifiers
& btnState
) ; // 1 is for up
355 bool controlDown
= ev
->modifiers
& controlKey
; // for simulating right mouse
357 event
.m_leftDown
= isDown
&& !controlDown
;
359 event
.m_middleDown
= FALSE
;
360 event
.m_rightDown
= isDown
&& controlDown
;
362 if ( ev
->what
== mouseDown
)
365 event
.SetEventType(wxEVT_RIGHT_DOWN
) ;
367 event
.SetEventType(wxEVT_LEFT_DOWN
) ;
369 else if ( ev
->what
== mouseUp
)
372 event
.SetEventType(wxEVT_RIGHT_UP
) ;
374 event
.SetEventType(wxEVT_LEFT_UP
) ;
378 event
.SetEventType(wxEVT_MOTION
) ;
381 event
.m_shiftDown
= ev
->modifiers
& shiftKey
;
382 event
.m_controlDown
= ev
->modifiers
& controlKey
;
383 event
.m_altDown
= ev
->modifiers
& optionKey
;
384 event
.m_metaDown
= ev
->modifiers
& cmdKey
;
386 Point localwhere
= ev
->where
;
390 ::SetPort( UMAGetWindowPort( m_macWindow
) ) ;
391 ::GlobalToLocal( &localwhere
) ;
394 if ( ev
->what
== mouseDown
)
396 if ( ev
->when
- lastWhen
<= GetDblTime() )
398 if ( abs( localwhere
.h
- lastWhere
.h
) < 3 || abs( localwhere
.v
- lastWhere
.v
) < 3 )
401 event
.SetEventType(wxEVT_RIGHT_DCLICK
) ;
403 event
.SetEventType(wxEVT_LEFT_DCLICK
) ;
409 lastWhen
= ev
->when
;
411 lastWhere
= localwhere
;
414 event
.m_x
= localwhere
.h
;
415 event
.m_y
= localwhere
.v
;
420 wxPoint origin = GetClientAreaOrigin() ;
422 event.m_x += origin.x ;
423 event.m_y += origin.y ;
426 event
.m_timeStamp
= ev
->when
;
427 event
.SetEventObject(this);
428 if ( wxTheApp
->s_captureWindow
)
432 wxTheApp
->s_captureWindow
->ScreenToClient( &x
, &y
) ;
435 wxTheApp
->s_captureWindow
->GetEventHandler()->ProcessEvent( event
) ;
436 if ( ev
->what
== mouseUp
)
438 wxTheApp
->s_captureWindow
= NULL
;
439 if ( wxBusyCursorCount
== 0 )
441 m_cursor
.MacInstall() ;
447 MacDispatchMouseEvent( event
) ;
451 void wxTopLevelWindowMac::MacMouseDown( EventRecord
*ev
, short part
)
453 MacFireMouseEvent( ev
) ;
456 void wxTopLevelWindowMac::MacMouseUp( EventRecord
*ev
, short part
)
462 MacFireMouseEvent( ev
) ;
468 void wxTopLevelWindowMac::MacMouseMoved( EventRecord
*ev
, short part
)
474 MacFireMouseEvent( ev
) ;
479 void wxTopLevelWindowMac::MacActivate( EventRecord
*ev
, bool inIsActivating
)
481 wxActivateEvent
event(wxEVT_ACTIVATE
, inIsActivating
, m_windowId
);
482 event
.m_timeStamp
= ev
->when
;
483 event
.SetEventObject(this);
485 GetEventHandler()->ProcessEvent(event
);
487 UMAHighlightAndActivateWindow( m_macWindow
, inIsActivating
) ;
489 MacSuperEnabled( inIsActivating
) ;
492 void wxTopLevelWindowMac::MacKeyDown( EventRecord
*ev
)
496 void wxTopLevelWindowMac::SetTitle(const wxString
& title
)
498 wxWindow::SetTitle( title
) ;
502 if( wxApp::s_macDefaultEncodingIsPC
)
503 label
= wxMacMakeMacStringFromPC( m_label
) ;
507 UMASetWTitleC( m_macWindow
, label
) ;
510 bool wxTopLevelWindowMac::Show(bool show
)
512 if ( !wxWindow::Show(show
) )
517 ::ShowWindow( m_macWindow
) ;
518 ::SelectWindow( m_macWindow
) ;
519 // no need to generate events here, they will get them triggered by macos
520 // actually they should be , but apparently they are not
521 wxSize
size(m_width
, m_height
);
522 wxSizeEvent
event(size
, m_windowId
);
523 event
.SetEventObject(this);
524 GetEventHandler()->ProcessEvent(event
);
528 ::HideWindow( m_macWindow
) ;
542 void wxTopLevelWindowMac::DoMoveWindow(int x
, int y
, int width
, int height
)
546 int former_w
= m_width
;
547 int former_h
= m_height
;
549 int actualWidth
= width
;
550 int actualHeight
= height
;
554 if ((m_minWidth
!= -1) && (actualWidth
< m_minWidth
))
555 actualWidth
= m_minWidth
;
556 if ((m_minHeight
!= -1) && (actualHeight
< m_minHeight
))
557 actualHeight
= m_minHeight
;
558 if ((m_maxWidth
!= -1) && (actualWidth
> m_maxWidth
))
559 actualWidth
= m_maxWidth
;
560 if ((m_maxHeight
!= -1) && (actualHeight
> m_maxHeight
))
561 actualHeight
= m_maxHeight
;
563 bool doMove
= false ;
564 bool doResize
= false ;
566 if ( actualX
!= former_x
|| actualY
!= former_y
)
570 if ( actualWidth
!= former_w
|| actualHeight
!= former_h
)
575 if ( doMove
|| doResize
)
579 m_width
= actualWidth
;
580 m_height
= actualHeight
;
583 ::MoveWindow(m_macWindow
, m_x
, m_y
, false); // don't make frontmost
586 ::SizeWindow(m_macWindow
, m_width
, m_height
, true);
588 // the OS takes care of invalidating and erasing the new area
589 // we have erased the old one
591 if ( IsKindOf( CLASSINFO( wxFrame
) ) )
593 wxFrame
* frame
= (wxFrame
*) this ;
594 frame
->PositionStatusBar();
595 frame
->PositionToolBar();
598 wxWindowMac::MacTopLevelWindowChangedPosition() ; // like this only children will be notified
600 MacRepositionScrollBars() ;
603 wxPoint
point(m_x
, m_y
);
604 wxMoveEvent
event(point
, m_windowId
);
605 event
.SetEventObject(this);
606 GetEventHandler()->ProcessEvent(event
) ;
610 MacRepositionScrollBars() ;
611 wxSize
size(m_width
, m_height
);
612 wxSizeEvent
event(size
, m_windowId
);
613 event
.SetEventObject(this);
614 GetEventHandler()->ProcessEvent(event
);
621 * Invalidation Mechanism
623 * The update mechanism reflects exactely the windows mechanism
624 * the rect gets added to the window invalidate region, if the eraseBackground flag
625 * has been true for any part of the update rgn the background is erased in the entire region
626 * not just in the specified rect.
628 * In order to achive this, we also have an internal m_macNoEraseUpdateRgn, all rects that have
629 * the eraseBackground flag set to false are also added to this rgn. upon receiving an update event
630 * the update rgn is compared to the m_macNoEraseUpdateRgn and in case they differ, every window
631 * will get the eraseBackground event first
634 void wxTopLevelWindowMac::MacInvalidate( const Rect
* rect
, bool eraseBackground
)
637 GetPort( &formerPort
) ;
638 SetPortWindowPort( m_macWindow
) ;
640 m_macNeedsErasing
|= eraseBackground
;
642 // if we already know that we will have to erase, there's no need to track the rest
643 if ( !m_macNeedsErasing
)
645 // we end only here if eraseBackground is false
646 // if we already have a difference between m_macNoEraseUpdateRgn and UpdateRgn
647 // we will have to erase anyway
649 RgnHandle updateRgn
= NewRgn();
650 RgnHandle diffRgn
= NewRgn() ;
651 if ( updateRgn
&& diffRgn
)
653 GetWindowUpdateRgn( m_macWindow
, updateRgn
);
655 LocalToGlobal( &pt
) ;
656 OffsetRgn( updateRgn
, -pt
.h
, -pt
.v
) ;
657 DiffRgn( updateRgn
, m_macNoEraseUpdateRgn
, diffRgn
) ;
658 if ( !EmptyRgn( diffRgn
) )
660 m_macNeedsErasing
= true ;
664 DisposeRgn( updateRgn
);
666 DisposeRgn( diffRgn
);
668 if ( !m_macNeedsErasing
)
670 RgnHandle rectRgn
= NewRgn() ;
671 SetRectRgn( rectRgn
, rect
->left
, rect
->top
, rect
->right
, rect
->bottom
) ;
672 UnionRgn( m_macNoEraseUpdateRgn
, rectRgn
, m_macNoEraseUpdateRgn
) ;
673 DisposeRgn( rectRgn
) ;
676 InvalWindowRect( m_macWindow
, rect
) ;
677 // turn this on to debug the refreshing cycle
678 #if wxMAC_DEBUG_REDRAW
681 SetPort( formerPort
) ;