X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/732b3a752b77de9ac00f770ac42b95ec99b5809d..920b9675d9e4ae7f721bd6eeb85c184a74434f7b:/src/mac/toplevel.cpp diff --git a/src/mac/toplevel.cpp b/src/mac/toplevel.cpp index 6aed596250..dd928635f1 100644 --- a/src/mac/toplevel.cpp +++ b/src/mac/toplevel.cpp @@ -43,6 +43,9 @@ #include "wx/tooltip.h" #include "wx/dnd.h" +#include "ToolUtils.h" + + #define wxMAC_DEBUG_REDRAW 0 #ifndef wxMAC_DEBUG_REDRAW #define wxMAC_DEBUG_REDRAW 0 @@ -59,6 +62,11 @@ wxWindowList wxModelessWindows; static Point gs_lastWhere; static long gs_lastWhen = 0; + +#if TARGET_CARBON +static pascal long wxShapedMacWindowDef(short varCode, WindowRef window, SInt16 message, SInt32 param); +#endif + // ============================================================================ // wxTopLevelWindowMac implementation // ============================================================================ @@ -181,19 +189,19 @@ static pascal OSStatus KeyboardEventHandler( EventHandlerCallRef handler , Event wxWindow* focus = wxWindow::FindFocus() ; event.SetEventObject(focus); - if ( (modifiers ^ wxTheApp->s_lastModifiers ) & controlKey ) + if ( focus && (modifiers ^ wxTheApp->s_lastModifiers ) & controlKey ) { event.m_keyCode = WXK_CONTROL ; event.SetEventType( ( modifiers & controlKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; focus->GetEventHandler()->ProcessEvent( event ) ; } - if ( (modifiers ^ wxTheApp->s_lastModifiers ) & shiftKey ) + if ( focus && (modifiers ^ wxTheApp->s_lastModifiers ) & shiftKey ) { event.m_keyCode = WXK_SHIFT ; event.SetEventType( ( modifiers & shiftKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; focus->GetEventHandler()->ProcessEvent( event ) ; } - if ( (modifiers ^ wxTheApp->s_lastModifiers ) & optionKey ) + if ( focus && (modifiers ^ wxTheApp->s_lastModifiers ) & optionKey ) { event.m_keyCode = WXK_ALT ; event.SetEventType( ( modifiers & optionKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; @@ -341,6 +349,64 @@ pascal OSStatus wxMacWindowEventHandler( EventHandlerCallRef handler , EventRef DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacWindowEventHandler ) +// Patch 531199 defined a window event handler, as follows. +// TODO: merge the moving/sizing event handling with the event +// handler above. +#if 0 +static pascal OSStatus +WindowHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* userData ) +{ + Rect bounds; + SInt16 height, width; + UInt32 attributes; + OSStatus result = eventNotHandledErr; + + GetEventParameter( inEvent, kEventParamAttributes, typeUInt32, NULL, sizeof( UInt32 ), NULL, &attributes ); + + if ((attributes & (kWindowBoundsChangeSizeChanged | kWindowBoundsChangeOriginChanged)) != 0) + { + // Extract the current bounds. This is the paramter you get to modify to + // alter the window position or size during a window resizing. + GetEventParameter( inEvent, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof( bounds ), NULL, &bounds ); + + wxRect rect; + rect.SetLeft(bounds.left); + rect.SetTop(bounds.top); + rect.SetRight(bounds.right); + rect.SetBottom(bounds.bottom); + + bool rc; + wxWindowMac *pWindow = (wxWindowMac*)userData; + if ((attributes & kWindowBoundsChangeSizeChanged) != 0) { + wxSizeEvent event(rect, pWindow->GetId()); + event.SetEventObject(pWindow); + rc = pWindow->GetEventHandler()->ProcessEvent(event); + rect = event.GetRect(); + } + else { + wxMoveEvent event(rect, pWindow->GetId()); + event.SetEventObject(pWindow); + rc = pWindow->GetEventHandler()->ProcessEvent(event); + rect = event.GetRect(); + } + + if (rc) { + bounds.left = rect.GetLeft(); + bounds.top = rect.GetTop(); + bounds.right = rect.GetRight(); + bounds.bottom = rect.GetBottom(); + } + + // Set the current bounds parameter to our adjusted bounds. Return + // noErr to indicate we handled this event. + SetEventParameter( inEvent, kEventParamCurrentBounds, typeQDRectangle, sizeof( bounds ), &bounds ); + result = noErr; + } + return result; +} +#endif + // WindowHandler + #endif // --------------------------------------------------------------------------- @@ -590,7 +656,30 @@ void wxTopLevelWindowMac::MacCreateRealWindow( const wxString& title, attr |= kWindowCloseBoxAttribute ; } - ::CreateNewWindow( wclass , attr , &theBoundsRect , (WindowRef*)&m_macWindow ) ; +#if TARGET_CARBON +#if 0 // having problems right now with that + if (HasFlag(wxSTAY_ON_TOP)) + wclass = kUtilityWindowClass; +#endif +#endif + +#if TARGET_CARBON + if ( HasFlag(wxFRAME_SHAPED) ) + { + WindowDefSpec customWindowDefSpec; + customWindowDefSpec.defType = kWindowDefProcPtr; + customWindowDefSpec.u.defProc = NewWindowDefUPP(wxShapedMacWindowDef); + + ::CreateCustomWindow( &customWindowDefSpec, wclass, + attr, &theBoundsRect, + (WindowRef*) &m_macWindow); + } + else +#endif + { + ::CreateNewWindow( wclass , attr , &theBoundsRect , (WindowRef*)&m_macWindow ) ; + } + wxAssociateWinWithMacWindow( m_macWindow , this ) ; UMASetWTitle( (WindowRef)m_macWindow , title ) ; ::CreateRootControl( (WindowRef)m_macWindow , (ControlHandle*)&m_macRootControl ) ; @@ -598,8 +687,29 @@ void wxTopLevelWindowMac::MacCreateRealWindow( const wxString& title, InstallStandardEventHandler( GetWindowEventTarget(MAC_WXHWND(m_macWindow)) ) ; InstallWindowEventHandler(MAC_WXHWND(m_macWindow), GetwxMacWindowEventHandlerUPP(), GetEventTypeCount(eventList), eventList, this, &((EventHandlerRef)m_macEventHandler)); + + // Patch 531199 also defined a window event handler, as follows: +#if 0 + // install a window event handler to send wxEVT_MOVING and wxEVT_SIZING events + EventTypeSpec events[] = { { kEventClassWindow, kEventWindowBoundsChanging } }; + EventHandlerUPP handlerProc = NewEventHandlerUPP( WindowHandler ); + EventHandlerRef eventHandlerRef; + InstallWindowEventHandler( m_macWindowData->m_macWindow, handlerProc, GetEventTypeCount(events), + events, (void*)this, &eventHandlerRef); +#endif + #endif m_macFocus = NULL ; + + +#if TARGET_CARBON + if ( HasFlag(wxFRAME_SHAPED) ) + { + // default shape matches the window size + wxRegion rgn(0, 0, m_width, m_height); + SetShape(rgn); + } +#endif } void wxTopLevelWindowMac::MacGetPortParams(WXPOINTPTR localOrigin, WXRECTPTR clipRect, WXHWND *window , wxWindowMac** rootwin) @@ -629,20 +739,26 @@ void wxTopLevelWindowMac::MacUpdate( long timestamp) { wxMacPortStateHelper help( (GrafPtr) GetWindowPort( (WindowRef) m_macWindow) ) ; + RgnHandle visRgn = NewRgn() ; + GetPortVisibleRegion( GetWindowPort( (WindowRef)m_macWindow ), visRgn ); BeginUpdate( (WindowRef)m_macWindow ) ; RgnHandle updateRgn = NewRgn(); RgnHandle diffRgn = NewRgn() ; + if ( updateRgn && diffRgn ) { #if 1 // macos internal control redraws clean up areas we'd like to redraw ourselves // therefore we pick the boundary rect and make sure we can redraw it + // this has to be intersected by the visRgn in order to avoid drawing over its own + // boundaries RgnHandle trueUpdateRgn = NewRgn() ; Rect trueUpdateRgnBoundary ; GetPortVisibleRegion( GetWindowPort( (WindowRef)m_macWindow ), trueUpdateRgn ); GetRegionBounds( trueUpdateRgn , &trueUpdateRgnBoundary ) ; - RectRgn( (RgnHandle) updateRgn , &trueUpdateRgnBoundary ) ; + RectRgn( updateRgn , &trueUpdateRgnBoundary ) ; + SectRgn( updateRgn , visRgn , updateRgn ) ; if ( trueUpdateRgn ) DisposeRgn( trueUpdateRgn ) ; SetPortVisibleRegion( GetWindowPort( (WindowRef)m_macWindow ), updateRgn ) ; @@ -659,6 +775,9 @@ void wxTopLevelWindowMac::MacUpdate( long timestamp) DisposeRgn( updateRgn ); if ( diffRgn ) DisposeRgn( diffRgn ); + if ( visRgn ) + DisposeRgn( visRgn ) ; + EndUpdate( (WindowRef)m_macWindow ) ; SetEmptyRgn( (RgnHandle) m_macNoEraseUpdateRgn ) ; m_macNeedsErasing = false ; @@ -725,7 +844,7 @@ void wxTopLevelWindowMac::MacFireMouseEvent( if ( kind == mouseDown ) { - if ( timestamp - gs_lastWhen <= GetDblTime() ) + if ( timestamp - gs_lastWhen <= (long) GetDblTime() ) { if ( abs( localwhere.h - gs_lastWhere.h ) < 3 && abs( localwhere.v - gs_lastWhere.v ) < 3 ) { @@ -827,7 +946,7 @@ void wxTopLevelWindowMac::MacActivate( long timestamp , bool inIsActivating ) // Early versions of MacOS X don't refresh backgrounds properly, // so refresh the whole window on activation and deactivation. long osVersion = UMAGetSystemVersion(); - if (osVersion >= 0x1000 && osVersion < 0x1020) + if (osVersion >= 0x1000 && osVersion < 0x1020 ) { Refresh(TRUE); } @@ -1031,7 +1150,174 @@ void wxTopLevelWindowMac::MacInvalidate( const WXRECTPTR rect, bool eraseBackgro SetPort( formerPort ) ; } + bool wxTopLevelWindowMac::SetShape(const wxRegion& region) { + wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), FALSE, + _T("Shaped windows must be created with the wxFRAME_SHAPED style.")); + +#if TARGET_CARBON + // The empty region signifies that the shape should be removed from the + // window. + if ( region.IsEmpty() ) + { + wxSize sz = GetClientSize(); + wxRegion rgn(0, 0, sz.x, sz.y); + return SetShape(rgn); + } + + // Make a copy of the region + RgnHandle shapeRegion = NewRgn(); + CopyRgn( (RgnHandle)region.GetWXHRGN(), shapeRegion ); + + // Dispose of any shape region we may already have + RgnHandle oldRgn = (RgnHandle)GetWRefCon( (WindowRef)MacGetWindowRef() ); + if ( oldRgn ) + DisposeRgn(oldRgn); + + // Save the region so we can use it later + SetWRefCon((WindowRef)MacGetWindowRef(), (SInt32)shapeRegion); + + // Tell the window manager that the window has changed shape + ReshapeCustomWindow((WindowRef)MacGetWindowRef()); + return TRUE; +#else return FALSE; +#endif } + +// --------------------------------------------------------------------------- +// Support functions for shaped windows, based on Apple's CustomWindow sample at +// http://developer.apple.com/samplecode/Sample_Code/Human_Interface_Toolbox/Mac_OS_High_Level_Toolbox/CustomWindow.htm +// --------------------------------------------------------------------------- + +#if TARGET_CARBON + +static void wxShapedMacWindowGetPos(WindowRef window, Rect* inRect) +{ + GetWindowPortBounds(window, inRect); + Point pt = {inRect->left, inRect->top}; + SetPort((GrafPtr) GetWindowPort(window)); + LocalToGlobal(&pt); + inRect->top = pt.v; + inRect->left = pt.h; + inRect->bottom += pt.v; + inRect->right += pt.h; +} + + +static SInt32 wxShapedMacWindowGetFeatures(WindowRef window, SInt32 param) +{ + /*------------------------------------------------------ + Define which options your custom window supports. + --------------------------------------------------------*/ + //just enable everything for our demo + *(OptionBits*)param=//kWindowCanGrow| + //kWindowCanZoom| + //kWindowCanCollapse| + //kWindowCanGetWindowRegion| + //kWindowHasTitleBar| + //kWindowSupportsDragHilite| + kWindowCanDrawInCurrentPort| + //kWindowCanMeasureTitle| + kWindowWantsDisposeAtProcessDeath| + kWindowSupportsSetGrowImageRegion| + kWindowDefSupportsColorGrafPort; + return 1; +} + +// The content region is left as a rectangle matching the window size, this is +// so the origin in the paint event, and etc. still matches what the +// programmer expects. +static void wxShapedMacWindowContentRegion(WindowRef window, RgnHandle rgn) +{ + SetEmptyRgn(rgn); + wxTopLevelWindowMac* win = wxFindWinFromMacWindow(window); + if (win) + { + wxRect r = win->GetRect(); + SetRectRgn(rgn, r.GetLeft(), r.GetTop(), r.GetRight(), r.GetBottom()); + } +} + +// The structure region is set to the shape given to the SetShape method. +static void wxShapedMacWindowStructureRegion(WindowRef window, RgnHandle rgn) +{ + RgnHandle cachedRegion = (RgnHandle) GetWRefCon(window); + + SetEmptyRgn(rgn); + if (cachedRegion) + { + Rect windowRect; + wxShapedMacWindowGetPos(window, &windowRect); //how big is the window + CopyRgn(cachedRegion, rgn); //make a copy of our cached region + OffsetRgn(rgn, windowRect.left, windowRect.top); // position it over window + //MapRgn(rgn, &mMaskSize, &windowRect); //scale it to our actual window size + } +} + + + +static SInt32 wxShapedMacWindowGetRegion(WindowRef window, SInt32 param) +{ + GetWindowRegionPtr rgnRec=(GetWindowRegionPtr)param; + + switch(rgnRec->regionCode) + { + case kWindowStructureRgn: + wxShapedMacWindowStructureRegion(window, rgnRec->winRgn); + break; + case kWindowContentRgn: + wxShapedMacWindowContentRegion(window, rgnRec->winRgn); + break; + default: + SetEmptyRgn(rgnRec->winRgn); + } //switch + + return noErr; +} + + +static SInt32 wxShapedMacWindowHitTest(WindowRef window,SInt32 param) +{ + /*------------------------------------------------------ + Determine the region of the window which was hit + --------------------------------------------------------*/ + Point hitPoint; + static RgnHandle tempRgn=nil; + + if(!tempRgn) + tempRgn=NewRgn(); + + SetPt(&hitPoint,LoWord(param),HiWord(param));//get the point clicked + + //Mac OS 8.5 or later + wxShapedMacWindowStructureRegion(window, tempRgn); + if (PtInRgn(hitPoint, tempRgn)) //in window content region? + return wInContent; + + return wNoHit;//no significant area was hit. +} + + +static pascal long wxShapedMacWindowDef(short varCode, WindowRef window, SInt16 message, SInt32 param) +{ + switch(message) + { + case kWindowMsgHitTest: + return wxShapedMacWindowHitTest(window,param); + + case kWindowMsgGetFeatures: + return wxShapedMacWindowGetFeatures(window,param); + + // kWindowMsgGetRegion is sent during CreateCustomWindow and ReshapeCustomWindow + case kWindowMsgGetRegion: + return wxShapedMacWindowGetRegion(window,param); + } + + return 0; +} + +#endif +// --------------------------------------------------------------------------- +