We need to queue the focus in/out changes because they may occur during video mode changes and we can respond to them by triggering more mode changes.
authorSam Lantinga <slouken@libsdl.org>
Fri, 28 Sep 2012 14:01:55 -0700
changeset 6504 100c49578dba
parent 6503 8ff31baded38
child 6505 ce7abf273d8c
We need to queue the focus in/out changes because they may occur during video mode changes and we can respond to them by triggering more mode changes.
src/video/x11/SDL_x11events.c
src/video/x11/SDL_x11window.h
--- a/src/video/x11/SDL_x11events.c	Fri Sep 28 14:00:43 2012 -0700
+++ b/src/video/x11/SDL_x11events.c	Fri Sep 28 14:01:55 2012 -0700
@@ -29,6 +29,7 @@
 #include <limits.h> /* For INT_MAX */
 
 #include "SDL_x11video.h"
+#include "SDL_x11video.h"
 #include "SDL_x11touch.h"
 #include "SDL_x11xinput2.h"
 #include "../../events/SDL_events_c.h"
@@ -110,6 +111,34 @@
 
 
 static void
+X11_DispatchFocusIn(SDL_WindowData *data)
+{
+#ifdef DEBUG_XEVENTS
+    printf("window %p: Dispatching FocusIn\n", data);
+#endif
+    SDL_SetKeyboardFocus(data->window);
+#ifdef X_HAVE_UTF8_STRING
+    if (data->ic) {
+        XSetICFocus(data->ic);
+    }
+#endif
+}
+
+static void
+X11_DispatchFocusOut(SDL_WindowData *data)
+{
+#ifdef DEBUG_XEVENTS
+    printf("window %p: Dispatching FocusOut\n", data);
+#endif
+    SDL_SetKeyboardFocus(NULL);
+#ifdef X_HAVE_UTF8_STRING
+    if (data->ic) {
+        XUnsetICFocus(data->ic);
+    }
+#endif
+}
+
+static void
 X11_DispatchMapNotify(SDL_WindowData *data)
 {
     SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
@@ -186,7 +215,7 @@
         /* Gaining mouse coverage? */
     case EnterNotify:{
 #ifdef DEBUG_XEVENTS
-            printf("EnterNotify! (%d,%d,%d)\n", 
+            printf("window %p: EnterNotify! (%d,%d,%d)\n", data,
                    xevent.xcrossing.x,
                    xevent.xcrossing.y,
                    xevent.xcrossing.mode);
@@ -201,7 +230,7 @@
         /* Losing mouse coverage? */
     case LeaveNotify:{
 #ifdef DEBUG_XEVENTS
-            printf("LeaveNotify! (%d,%d,%d)\n", 
+            printf("window %p: LeaveNotify! (%d,%d,%d)\n", data,
                    xevent.xcrossing.x,
                    xevent.xcrossing.y,
                    xevent.xcrossing.mode);
@@ -221,35 +250,27 @@
         /* Gaining input focus? */
     case FocusIn:{
 #ifdef DEBUG_XEVENTS
-            printf("FocusIn!\n");
+            printf("window %p: FocusIn!\n", data);
 #endif
-            SDL_SetKeyboardFocus(data->window);
-#ifdef X_HAVE_UTF8_STRING
-            if (data->ic) {
-                XSetICFocus(data->ic);
-            }
-#endif
+            data->pending_focus = PENDING_FOCUS_IN;
+            data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME;
         }
         break;
 
         /* Losing input focus? */
     case FocusOut:{
 #ifdef DEBUG_XEVENTS
-            printf("FocusOut!\n");
+            printf("window %p: FocusOut!\n", data);
 #endif
-            SDL_SetKeyboardFocus(NULL);
-#ifdef X_HAVE_UTF8_STRING
-            if (data->ic) {
-                XUnsetICFocus(data->ic);
-            }
-#endif
+            data->pending_focus = PENDING_FOCUS_OUT;
+            data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_OUT_TIME;
         }
         break;
 
         /* Generated upon EnterWindow and FocusIn */
     case KeymapNotify:{
 #ifdef DEBUG_XEVENTS
-            printf("KeymapNotify!\n");
+            printf("window %p: KeymapNotify!\n", data);
 #endif
             /* FIXME:
                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
@@ -260,7 +281,7 @@
         /* Has the keyboard layout changed? */
     case MappingNotify:{
 #ifdef DEBUG_XEVENTS
-            printf("MappingNotify!\n");
+            printf("window %p: MappingNotify!\n", data);
 #endif
             X11_UpdateKeymap(_this);
         }
@@ -274,7 +295,7 @@
             Status status = 0;
 
 #ifdef DEBUG_XEVENTS
-            printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
+            printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
 #endif
             SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
 #if 1
@@ -313,7 +334,7 @@
             KeyCode keycode = xevent.xkey.keycode;
 
 #ifdef DEBUG_XEVENTS
-            printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
+            printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
 #endif
             if (X11_KeyRepeat(display, &xevent)) {
                 /* We're about to get a repeated key down, ignore the key up */
@@ -326,7 +347,7 @@
         /* Have we been iconified? */
     case UnmapNotify:{
 #ifdef DEBUG_XEVENTS
-            printf("UnmapNotify!\n");
+            printf("window %p: UnmapNotify!\n", data);
 #endif
             X11_DispatchUnmapNotify(data);
         }
@@ -335,7 +356,7 @@
         /* Have we been restored? */
     case MapNotify:{
 #ifdef DEBUG_XEVENTS
-            printf("MapNotify!\n");
+            printf("window %p: MapNotify!\n", data);
 #endif
             X11_DispatchMapNotify(data);
         }
@@ -344,7 +365,7 @@
         /* Have we been resized or moved? */
     case ConfigureNotify:{
 #ifdef DEBUG_XEVENTS
-            printf("ConfigureNotify! (resize: %dx%d)\n",
+            printf("window %p: ConfigureNotify! (resize: %dx%d)\n", data,
                    xevent.xconfigure.width, xevent.xconfigure.height);
 #endif
             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
@@ -368,7 +389,7 @@
         /* Do we need to refresh ourselves? */
     case Expose:{
 #ifdef DEBUG_XEVENTS
-            printf("Expose (count = %d)\n", xevent.xexpose.count);
+            printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
 #endif
             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
         }
@@ -378,7 +399,7 @@
             SDL_Mouse *mouse = SDL_GetMouse();  
             if(!mouse->relative_mode) {
 #ifdef DEBUG_MOTION
-                printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
+                printf("window %p: X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
 #endif
 
                 SDL_SendMouseMotion(data->window, 0, xevent.xmotion.x, xevent.xmotion.y);
@@ -411,7 +432,7 @@
 
             char *name = XGetAtomName(display, xevent.xproperty.atom);
             if (name) {
-                printf("PropertyNotify: %s %s\n", name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed");
+                printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed");
                 XFree(name);
             }
 
@@ -508,7 +529,7 @@
 
             req = &xevent.xselectionrequest;
 #ifdef DEBUG_XEVENTS
-            printf("SelectionRequest (requestor = %ld, target = %ld)\n",
+            printf("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", data,
                 req->requestor, req->target);
 #endif
 
@@ -538,7 +559,7 @@
 
     case SelectionNotify: {
 #ifdef DEBUG_XEVENTS
-            printf("SelectionNotify (requestor = %ld, target = %ld)\n",
+            printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
                 xevent.xselection.requestor, xevent.xselection.target);
 #endif
             videodata->selection_waiting = SDL_FALSE;
@@ -547,13 +568,36 @@
 
     default:{
 #ifdef DEBUG_XEVENTS
-            printf("Unhandled event %d\n", xevent.type);
+            printf("window %p: Unhandled event %d\n", data, xevent.type);
 #endif
         }
         break;
     }
 }
 
+static void
+X11_HandleFocusChanges(_THIS)
+{
+    SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
+    int i;
+
+    if (videodata && videodata->windowlist) {
+        for (i = 0; i < videodata->numwindows; ++i) {
+            SDL_WindowData *data = videodata->windowlist[i];
+            if (data && data->pending_focus != PENDING_FOCUS_NONE) {
+                Uint32 now = SDL_GetTicks();
+                if ( (int)(data->pending_focus_time-now) <= 0 ) {
+                    if ( data->pending_focus == PENDING_FOCUS_IN ) {
+                        X11_DispatchFocusIn(data);
+                    } else {
+                        X11_DispatchFocusOut(data);
+                    }
+                    data->pending_focus = PENDING_FOCUS_NONE;
+                }
+            }
+        }
+    }
+}
 /* Ack!  XPending() actually performs a blocking read if no events available */
 static int
 X11_Pending(Display * display)
@@ -606,6 +650,10 @@
     while (X11_Pending(data->display)) {
         X11_DispatchEvent(_this);
     }
+
+    /* FIXME: Only need to do this when there are pending focus changes */
+    X11_HandleFocusChanges(_this);
+
     /*Dont process evtouch events if XInput2 multitouch is supported*/
     if(X11_Xinput2IsMultitouchSupported()) {
         return;
--- a/src/video/x11/SDL_x11window.h	Fri Sep 28 14:00:43 2012 -0700
+++ b/src/video/x11/SDL_x11window.h	Fri Sep 28 14:01:55 2012 -0700
@@ -23,6 +23,20 @@
 #ifndef _SDL_x11window_h
 #define _SDL_x11window_h
 
+/* We need to queue the focus in/out changes because they may occur during
+   video mode changes and we can respond to them by triggering more mode
+   changes.
+*/
+#define PENDING_FOCUS_IN_TIME   200
+#define PENDING_FOCUS_OUT_TIME  200
+
+typedef enum
+{
+    PENDING_FOCUS_NONE,
+    PENDING_FOCUS_IN,
+    PENDING_FOCUS_OUT
+} PendingFocusEnum;
+
 typedef struct
 {
     SDL_Window *window;
@@ -39,6 +53,8 @@
     GC gc;
     XIC ic;
     SDL_bool created;
+    PendingFocusEnum pending_focus;
+    Uint32 pending_focus_time;
     struct SDL_VideoData *videodata;
 } SDL_WindowData;