From 902ddbfd3e05276b8d575974885256a2134e8fb4 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Sat, 5 Mar 2011 12:21:20 +0000 Subject: [PATCH] support wxWindowDisabler on osx_cocoa git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@67129 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/osx/cocoa/evtloop.h | 8 ++ include/wx/utils.h | 5 +- src/common/utilscmn.cpp | 8 ++ src/osx/cocoa/evtloop.mm | 252 +++++++++++++++++++++++++++------ 4 files changed, 231 insertions(+), 42 deletions(-) diff --git a/include/wx/osx/cocoa/evtloop.h b/include/wx/osx/cocoa/evtloop.h index afccc7a92d..c8b5d9e666 100644 --- a/include/wx/osx/cocoa/evtloop.h +++ b/include/wx/osx/cocoa/evtloop.h @@ -15,6 +15,11 @@ class WXDLLIMPEXP_BASE wxGUIEventLoop : public wxCFEventLoop { public: wxGUIEventLoop(); + ~wxGUIEventLoop(); + + void BeginModalSession( wxWindow* modalWindow ); + + void EndModalSession(); protected: virtual int DoDispatchTimeout(unsigned long timeout); @@ -24,6 +29,9 @@ protected: virtual void DoStop(); virtual CFRunLoopRef CFGetCurrentRunLoop() const; + + void* m_modalSession; + WXWindow m_dummyWindow; }; #endif // _WX_OSX_COCOA_EVTLOOP_H_ diff --git a/include/wx/utils.h b/include/wx/utils.h index 0906fa834c..b539373de9 100644 --- a/include/wx/utils.h +++ b/include/wx/utils.h @@ -55,6 +55,7 @@ class WXDLLIMPEXP_FWD_BASE wxProcess; class WXDLLIMPEXP_FWD_CORE wxFrame; class WXDLLIMPEXP_FWD_CORE wxWindow; class WXDLLIMPEXP_FWD_CORE wxWindowList; +class WXDLLIMPEXP_FWD_CORE wxEventLoop; // ---------------------------------------------------------------------------- // Arithmetic functions @@ -714,7 +715,9 @@ private: // disable all windows except the given one (used by both ctors) void DoDisable(wxWindow *winToSkip = NULL); - +#if defined(__WXOSX__) && wxOSX_USE_COCOA + wxEventLoop* m_modalEventLoop; +#endif wxWindowList *m_winDisabled; bool m_disabled; diff --git a/src/common/utilscmn.cpp b/src/common/utilscmn.cpp index 6037037de0..15908b65e7 100644 --- a/src/common/utilscmn.cpp +++ b/src/common/utilscmn.cpp @@ -1567,6 +1567,12 @@ void wxEnableTopLevelWindows(bool enable) node->GetData()->Enable(enable); } +#if defined(__WXOSX__) && wxOSX_USE_COCOA + +// defined in evtloop.mm + +#else + wxWindowDisabler::wxWindowDisabler(bool disable) { m_disabled = disable; @@ -1629,6 +1635,8 @@ wxWindowDisabler::~wxWindowDisabler() delete m_winDisabled; } +#endif + // Yield to other apps/messages and disable user input to all windows except // the given one bool wxSafeYield(wxWindow *win, bool onlyIfNeeded) diff --git a/src/osx/cocoa/evtloop.mm b/src/osx/cocoa/evtloop.mm index 89957cd2bd..e558a54e25 100644 --- a/src/osx/cocoa/evtloop.mm +++ b/src/osx/cocoa/evtloop.mm @@ -39,45 +39,76 @@ // wxEventLoop implementation // ============================================================================ -/* -static int CalculateNSEventMaskFromEventCategory(wxEventCategory cat) + +static NSUInteger CalculateNSEventMaskFromEventCategory(wxEventCategory cat) { - NSLeftMouseDownMask | - NSLeftMouseUpMask | - NSRightMouseDownMask | - NSRightMouseUpMask = 1 << NSRightMouseUp, - NSMouseMovedMask = 1 << NSMouseMoved, - NSLeftMouseDraggedMask = 1 << NSLeftMouseDragged, - NSRightMouseDraggedMask = 1 << NSRightMouseDragged, - NSMouseEnteredMask = 1 << NSMouseEntered, - NSMouseExitedMask = 1 << NSMouseExited, - NSScrollWheelMask = 1 << NSScrollWheel, + // the masking system doesn't really help, as only the lowlevel UI events + // are split in a useful way, all others are way to broad + + if ( (cat | wxEVT_CATEGORY_USER_INPUT) && (cat | (~wxEVT_CATEGORY_USER_INPUT) ) ) + return NSAnyEventMask; + + NSUInteger mask = 0; + + if ( cat | wxEVT_CATEGORY_USER_INPUT ) + { + mask |= + NSLeftMouseDownMask | + NSLeftMouseUpMask | + NSRightMouseDownMask | + NSRightMouseUpMask | + NSMouseMovedMask | + NSLeftMouseDraggedMask | + NSRightMouseDraggedMask | + NSMouseEnteredMask | + NSMouseExitedMask | + NSScrollWheelMask | #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 - NSTabletPointMask = 1 << NSTabletPoint, - NSTabletProximityMask = 1 << NSTabletProximity, + NSTabletPointMask | + NSTabletProximityMask | #endif - NSOtherMouseDownMask = 1 << NSOtherMouseDown, - NSOtherMouseUpMask = 1 << NSOtherMouseUp, - NSOtherMouseDraggedMask = 1 << NSOtherMouseDragged, + NSOtherMouseDownMask | + NSOtherMouseUpMask | + NSOtherMouseDraggedMask | - - - NSKeyDownMask = 1 << NSKeyDown, - NSKeyUpMask = 1 << NSKeyUp, - NSFlagsChangedMask = 1 << NSFlagsChanged, - - NSAppKitDefinedMask = 1 << NSAppKitDefined, - NSSystemDefinedMask = 1 << NSSystemDefined, - NSApplicationDefinedMask = 1 << NSApplicationDefined, - NSPeriodicMask = 1 << NSPeriodic, - NSCursorUpdateMask = 1 << NSCursorUpdate, - - NSAnyEventMask = 0xffffffffU + NSKeyDownMask | + NSKeyUpMask | + NSFlagsChangedMask | +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + NSEventMaskGesture | + NSEventMaskMagnify | + NSEventMaskSwipe | + NSEventMaskRotate | + NSEventMaskBeginGesture | + NSEventMaskEndGesture | +#endif + 0; + } + + if ( cat | (~wxEVT_CATEGORY_USER_INPUT) ) + { + mask |= + NSAppKitDefinedMask | + NSSystemDefinedMask | + NSApplicationDefinedMask | + NSPeriodicMask | + NSCursorUpdateMask; + } + + return mask; } -*/ + wxGUIEventLoop::wxGUIEventLoop() { + m_modalSession = nil; + m_dummyWindow = nil; +} + +wxGUIEventLoop::~wxGUIEventLoop() +{ + wxASSERT( m_modalSession == nil ); + wxASSERT( m_dummyWindow == nil ); } //----------------------------------------------------------------------------- @@ -156,18 +187,48 @@ int wxGUIEventLoop::DoDispatchTimeout(unsigned long timeout) { wxMacAutoreleasePool autoreleasepool; - NSEvent *event = [NSApp - nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate dateWithTimeIntervalSinceNow: timeout/1000] - inMode:NSDefaultRunLoopMode - dequeue: YES]; - - if ( event == nil ) - return -1; + if ( m_modalSession ) + { + NSInteger response = [NSApp runModalSession:(NSModalSession)m_modalSession]; + + switch (response) + { + case NSRunContinuesResponse: + { + if ( [[NSApplication sharedApplication] + nextEventMatchingMask: NSAnyEventMask + untilDate: nil + inMode: NSDefaultRunLoopMode + dequeue: NO] != nil ) + return 1; + + return -1; + } + + case NSRunStoppedResponse: + case NSRunAbortedResponse: + return -1; + default: + wxFAIL_MSG("unknown response code"); + return -1; + break; + } + } + else + { + NSEvent *event = [NSApp + nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate dateWithTimeIntervalSinceNow: timeout/1000] + inMode:NSDefaultRunLoopMode + dequeue: YES]; + + if ( event == nil ) + return -1; - [NSApp sendEvent: event]; + [NSApp sendEvent: event]; - return 1; + return 1; + } } void wxGUIEventLoop::DoRun() @@ -240,3 +301,112 @@ void wxModalEventLoop::DoStop() [NSApp stopModal]; } +void wxGUIEventLoop::BeginModalSession( wxWindow* modalWindow ) +{ + WXWindow nsnow = nil; + + if ( modalWindow ) + { + wxNonOwnedWindow* now = dynamic_cast (modalWindow); + wxASSERT_MSG( now != NULL, "must pass in a toplevel window for modal event loop" ); + nsnow = now ? now->GetWXWindow() : nil; + } + else + { + NSRect r = NSMakeRect(10, 10, 0, 0); + nsnow = [NSPanel alloc]; + [nsnow initWithContentRect:r + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:YES + ]; + [nsnow orderOut:nil]; + m_dummyWindow = nsnow; + } + m_modalSession = [NSApp beginModalSessionForWindow:nsnow]; +} + +void wxGUIEventLoop::EndModalSession() +{ + wxASSERT_MSG(m_modalSession != NULL, "no modal session active"); + [NSApp endModalSession:(NSModalSession)m_modalSession]; + m_modalSession = nil; + if ( m_dummyWindow ) + { + [m_dummyWindow release]; + m_dummyWindow = nil; + } +} + +// +// +// + +wxWindowDisabler::wxWindowDisabler(bool disable) +{ + m_modalEventLoop = NULL; + m_disabled = disable; + if ( disable ) + DoDisable(); +} + +wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip) +{ + m_disabled = true; + DoDisable(winToSkip); +} + +void wxWindowDisabler::DoDisable(wxWindow *winToSkip) +{ + // remember the top level windows which were already disabled, so that we + // don't reenable them later + m_winDisabled = NULL; + + wxWindowList::compatibility_iterator node; + for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) + { + wxWindow *winTop = node->GetData(); + if ( winTop == winToSkip ) + continue; + + // we don't need to disable the hidden or already disabled windows + if ( winTop->IsEnabled() && winTop->IsShown() ) + { + winTop->Disable(); + } + else + { + if ( !m_winDisabled ) + { + m_winDisabled = new wxWindowList; + } + + m_winDisabled->Append(winTop); + } + } + + m_modalEventLoop = (wxEventLoop*)wxEventLoopBase::GetActive(); + m_modalEventLoop->BeginModalSession(winToSkip); +} + +wxWindowDisabler::~wxWindowDisabler() +{ + if ( !m_disabled ) + return; + + m_modalEventLoop->EndModalSession(); + + wxWindowList::compatibility_iterator node; + for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) + { + wxWindow *winTop = node->GetData(); + if ( !m_winDisabled || !m_winDisabled->Find(winTop) ) + { + winTop->Enable(); + } + //else: had been already disabled, don't reenable + } + + delete m_winDisabled; +} +