Cocoa : correctly handle late events sent after window deactivate
authorDamien Plisson <damien.plisson@yahoo.fr>
Thu, 28 Jan 2010 19:18:36 +0000 (19:18 +0000)
committerDamien Plisson <damien.plisson@yahoo.fr>
Thu, 28 Jan 2010 19:18:36 +0000 (19:18 +0000)
Cocoa can still send events (tagged with the correct NSWindow handle) after having sent the window deactivate event.
This caused these events being discarded as there was no active window for GHOST_WindowManager.

Fix is to use this NSWindow handle to retrieve the target window and correctly push the event.

E.g. of effects of this bug: OSKey modifier stuck after having invoked Spotlight through its shortcut (Cmd + Space). This gave the impression the Blender window has not got focus back for the keyboard.

Ton, can you confirm if this fixes the "Cocoa window loses focus permanently on using Spotlight" issue you found ?

intern/ghost/GHOST_IWindow.h
intern/ghost/intern/GHOST_SystemCocoa.mm
intern/ghost/intern/GHOST_Window.cpp
intern/ghost/intern/GHOST_Window.h
intern/ghost/intern/GHOST_WindowCocoa.h
intern/ghost/intern/GHOST_WindowCocoa.mm
intern/ghost/intern/GHOST_WindowManager.cpp
intern/ghost/intern/GHOST_WindowManager.h

index 5d1e0a67e7ee5002ec4d222bfd6588b44c450314..2bb446c229cecd1df8317fdefcb36186d91c260e 100644 (file)
@@ -72,6 +72,12 @@ public:
         */
        virtual bool getValid() const = 0;
 
+       /**
+        * Returns the associated OS object/handle
+        * @return The associated OS object/handle
+        */
+       virtual void* getOSWindow() const = 0;
+
        /**
         * Returns the type of drawing context used in this window.
         * @return The current type of drawing context.
index 5d28e94265545356c2a5a52d93ec25742f2eb8bf..23f95f95df44d68ac1802763f366909f092d7859 100644 (file)
@@ -1186,7 +1186,15 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
        NSEvent *event = (NSEvent *)eventPtr;
        GHOST_IWindow* window = m_windowManager->getActiveWindow();
        
-       if (!window) return GHOST_kFailure;
+       if (!window) {
+               /* If no active window found, still tries to find the window associated with the event
+                This may happen when Cocoa continues to send some events after the window deactivate one */
+               window = m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
+               if (!window) {
+                       //printf("\nW failure for event 0x%x",[event type]);
+                       return GHOST_kFailure;
+               }
+       }
        
        GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData();
        
@@ -1238,7 +1246,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
     GHOST_Window* window = (GHOST_Window*)m_windowManager->getActiveWindow();
        
        if (!window) {
-               return GHOST_kFailure;
+               /* If no active window found, still tries to find the window associated with the event
+                This may happen when Cocoa continues to send some events after the window deactivate one */
+               window = (GHOST_Window*)m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
+               if (!window) {
+                       //printf("\nW failure for event 0x%x",[event type]);
+                       return GHOST_kFailure;
+               }
        }
        
        switch ([event type])
@@ -1442,12 +1456,14 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
        unsigned char ascii;
        NSString* charsIgnoringModifiers;
 
-       /* Can happen, very rarely - seems to only be when command-H makes
-        * the window go away and we still get an HKey up. 
-        */
        if (!window) {
-               //printf("\nW failure");
-               return GHOST_kFailure;
+               /* If no active window found, still tries to find the window associated with the event
+                This may happen when Cocoa continues to send some events after the window deactivate one */
+               window = m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
+               if (!window) {
+                       //printf("\nW failure for event 0x%x",[event type]);
+                       return GHOST_kFailure;
+               }
        }
        
        switch ([event type]) {
@@ -1486,6 +1502,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
        
                case NSFlagsChanged: 
                        modifiers = [event modifierFlags];
+                       
                        if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
                                pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) );
                        }
index 939a911dfac4a50b6828b05b12789d1e299102d5..1c8b51e73a7431dcda9c185cd556818f3ed54d62 100644 (file)
@@ -72,6 +72,10 @@ GHOST_Window::~GHOST_Window()
 {
 }
 
+void* GHOST_Window::getOSWindow() const
+{
+       return NULL;
+}
 
 GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType type)
 {
index 8aab9125130a6e1cdae2780a3126abbffe09c96c..c614ae68f65744cbb225da986b70254be3d7f32c 100644 (file)
@@ -123,6 +123,12 @@ public:
         */
        virtual ~GHOST_Window();
 
+       /**
+        * Returns the associated OS object/handle
+        * @return The associated OS object/handle
+        */
+       virtual void* getOSWindow() const;
+       
        /**
         * Returns the current cursor shape.
         * @return      The current cursor shape.
index b54634b08d7eb085cf0ac3d36506181664e9a57b..5a89b1a53a396abb538b2948c2d92ced3a63727a 100644 (file)
@@ -96,6 +96,12 @@ public:
         * @return The validity of the window.
         */
        virtual bool getValid() const;
+       
+       /**
+        * Returns the associated NSWindow object
+        * @return The associated NSWindow object
+        */
+       virtual void* getOSWindow() const;
 
        /**
         * Sets the title displayed in the title bar.
index c02c3f111677e1f1139306fc3346493100f34584..5dcc949ed4590ab85499116854dda757247e2f3e 100644 (file)
@@ -465,6 +465,10 @@ bool GHOST_WindowCocoa::getValid() const
        return (m_window != 0);
 }
 
+void* GHOST_WindowCocoa::getOSWindow() const
+{
+       return (void*)m_window;
+}
 
 void GHOST_WindowCocoa::setTitle(const STR_String& title)
 {
index 15ee41e3dce6221d8d57b0084d3fda9611339647..56b7c622d9a317ffbb20b7381cee5941963c580b 100644 (file)
@@ -193,6 +193,18 @@ std::vector<GHOST_IWindow *> &GHOST_WindowManager::getWindows()
 }
 
 
+GHOST_IWindow* GHOST_WindowManager::getWindowAssociatedWithOSWindow(void* osWindow)
+{
+       std::vector<GHOST_IWindow*>::iterator iter;
+
+       for (iter = m_windows.begin(); iter != m_windows.end(); iter++) {
+               if ((*iter)->getOSWindow() == osWindow)
+                       return *iter;
+       }
+       
+       return NULL;
+}
+
 bool GHOST_WindowManager::getAnyModifiedState()
 {
        bool isAnyModified = false;
index 3690ad41e2cd791880ab84895bc834c015002b63..6f48c7f4c9c76c1b65c3b76ebd9e199c49f4a271 100644 (file)
@@ -134,7 +134,14 @@ public:
         * interface above for this,
         */
        std::vector<GHOST_IWindow *> & getWindows();
-
+       
+       /**
+        * Finds the window associated with an OS window object/handle
+        * @param osWindow The OS window object/handle
+        * @return The associated window, null if none corresponds
+        */
+       virtual GHOST_IWindow* getWindowAssociatedWithOSWindow(void* osWindow);
+       
        /**
         * Return true if any windows has a modified status
         * @return True if any window has unsaved changes