Merged Ryan's commits
authorSam Lantinga <slouken@libsdl.org>
Fri, 28 Sep 2012 14:22:33 -0700
changeset 6507 42acda949dfb
parent 6506 305f0fcc0e99 (diff)
parent 6499 a34024340f54 (current diff)
child 6508 81a3d541d9a2
Merged Ryan's commits
--- a/src/video/x11/SDL_x11events.c	Fri Sep 28 14:17:30 2012 -0400
+++ b/src/video/x11/SDL_x11events.c	Fri Sep 28 14:22:33 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_x11modes.c	Fri Sep 28 14:17:30 2012 -0400
+++ b/src/video/x11/SDL_x11modes.c	Fri Sep 28 14:22:33 2012 -0700
@@ -217,6 +217,7 @@
             displaydata->screen = 0;
             displaydata->use_xinerama = xinerama_major * 100 + xinerama_minor;
             displaydata->xinerama_info = xinerama[screen];
+            displaydata->xinerama_screen = screen;
         }
         else displaydata->screen = screen;
 #else
@@ -637,6 +638,16 @@
 
 #if SDL_VIDEO_DRIVER_X11_XINERAMA
     if (data->use_xinerama) {
+        int screencount;
+        XineramaScreenInfo *xinerama;
+
+        /* Update the current screen layout information */
+        xinerama = XineramaQueryScreens(display, &screencount);
+        if (xinerama && data->xinerama_screen < screencount) {
+            data->xinerama_info = xinerama[data->xinerama_screen];
+        }
+        if (xinerama) XFree(xinerama);
+
         *w = data->xinerama_info.width;
         *h = data->xinerama_info.height;
         *rate = 0;
@@ -789,21 +800,20 @@
 int
 X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
 {
+    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
+    int real_rate;
+
+    rect->x = 0;
+    rect->y = 0;
+    get_real_resolution(display, data, &rect->w, &rect->h, &real_rate);
 
 #if SDL_VIDEO_DRIVER_X11_XINERAMA
-    if (data && data->use_xinerama) {
+    if (data->use_xinerama) {
         rect->x = data->xinerama_info.x_org;
         rect->y = data->xinerama_info.y_org;
-        rect->w = data->xinerama_info.width;
-        rect->h = data->xinerama_info.height;
-        return 0;
     }
 #endif
-    rect->x = 0;
-    rect->y = 0;
-    rect->w = sdl_display->current_mode.w;
-    rect->h = sdl_display->current_mode.h;
     return 0;
 }
 
--- a/src/video/x11/SDL_x11modes.h	Fri Sep 28 14:17:30 2012 -0400
+++ b/src/video/x11/SDL_x11modes.h	Fri Sep 28 14:22:33 2012 -0700
@@ -36,6 +36,7 @@
 
 #if SDL_VIDEO_DRIVER_X11_XINERAMA
     XineramaScreenInfo xinerama_info;
+    int xinerama_screen;
 #endif
 #if SDL_VIDEO_DRIVER_X11_XRANDR
     XRRScreenConfiguration *screen_config;
--- a/src/video/x11/SDL_x11window.c	Fri Sep 28 14:17:30 2012 -0400
+++ b/src/video/x11/SDL_x11window.c	Fri Sep 28 14:22:33 2012 -0700
@@ -56,14 +56,6 @@
 {
     return ev->type == ConfigureNotify && ev->xconfigure.window == *((Window*)win);
 }
-static Bool isFocusIn(Display *dpy, XEvent *ev, XPointer win)
-{
-    return ev->type == FocusIn && ev->xfocus.window == *((Window*)win);
-}
-static Bool isFocusOut(Display *dpy, XEvent *ev, XPointer win)
-{
-    return ev->type == FocusOut && ev->xfocus.window == *((Window*)win);
-}
 
 static SDL_bool
 X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
@@ -1019,10 +1011,12 @@
 
     XSelectInput(display, data->fswindow, StructureNotifyMask);
     XSetWindowBackground(display, data->fswindow, 0);
+    XInstallColormap(display, data->colormap);
     XClearWindow(display, data->fswindow);
     XMapRaised(display, data->fswindow);
 
     /* Make sure the fswindow is in view by warping mouse to the corner */
+    XUngrabPointer(display, CurrentTime);
     XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
 
     /* Wait to be mapped, filter Unmap event out if it arrives. */
@@ -1034,28 +1028,22 @@
         XF86VidModeLockModeSwitch(display, screen, True);
     }
 #endif
-    XInstallColormap(display, data->colormap);
 
     SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
 
     /* Center actual window within our cover-the-screen window. */
-    rect.x += (rect.w - window->w) / 2;
-    rect.y += (rect.h - window->h) / 2;
-    XReparentWindow(display, data->xwindow, data->fswindow, rect.x, rect.y);
+    XReparentWindow(display, data->xwindow, data->fswindow,
+                    (rect.w - window->w) / 2, (rect.h - window->h) / 2);
 
-    /* Center mouse in the window. */
-    rect.x += (window->w / 2);
-    rect.y += (window->h / 2);
+    /* Center mouse in the fullscreen window. */
+    rect.x += (rect.w / 2);
+    rect.y += (rect.h / 2);
     XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
 
     /* Wait to be mapped, filter Unmap event out if it arrives. */
     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
     XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
 
-    /* Set the input focus because we're about to grab input */
-    window->flags |= SDL_WINDOW_INPUT_FOCUS;
-    SDL_SetKeyboardFocus(data->window);
-
     X11_SetWindowGrab(_this, window);
 }
 
@@ -1214,9 +1202,9 @@
     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
     oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
 
-    if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
-        && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
-        XEvent ev;
+    if (oldstyle_fullscreen ||
+        ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
+         (window->flags & SDL_WINDOW_INPUT_FOCUS))) {
 
         /* Try to grab the mouse */
         for (;;) {
@@ -1235,15 +1223,11 @@
         /* Now grab the keyboard */
         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
                       GrabModeAsync, CurrentTime);
-
-        /* flush these events so they don't confuse normal event handling */
-        XSync(display, False);
-        XCheckIfEvent(display, &ev, &isFocusIn, (XPointer)&data->xwindow);
-        XCheckIfEvent(display, &ev, &isFocusOut, (XPointer)&data->xwindow);
     } else {
         XUngrabPointer(display, CurrentTime);
         XUngrabKeyboard(display, CurrentTime);
     }
+    XSync(display, False);
 }
 
 void
--- a/src/video/x11/SDL_x11window.h	Fri Sep 28 14:17:30 2012 -0400
+++ b/src/video/x11/SDL_x11window.h	Fri Sep 28 14:22:33 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;
 
--- a/test/common.c	Fri Sep 28 14:17:30 2012 -0400
+++ b/test/common.c	Fri Sep 28 14:22:33 2012 -0700
@@ -617,6 +617,7 @@
         }
 
         if (state->verbose & VERBOSE_MODES) {
+            SDL_Rect bounds;
             SDL_DisplayMode mode;
             int bpp;
             Uint32 Rmask, Gmask, Bmask, Amask;
@@ -626,6 +627,10 @@
             for (i = 0; i < n; ++i) {
                 fprintf(stderr, "Display %d:\n", i);
 
+                SDL_zero(bounds);
+                SDL_GetDisplayBounds(i, &bounds);
+                fprintf(stderr, "Bounds: %dx%d at %d,%d\n", bounds.w, bounds.h, bounds.x, bounds.y);
+
                 SDL_GetDesktopDisplayMode(i, &mode);
                 SDL_PixelFormatEnumToMasks(mode.format, &bpp, &Rmask, &Gmask,
                                            &Bmask, &Amask);
@@ -736,7 +741,8 @@
                 return SDL_FALSE;
             }
             SDL_GetWindowSize(state->windows[i], &w, &h);
-            if (w != state->window_w || h != state->window_h) {
+            if (!(state->window_flags & SDL_WINDOW_RESIZABLE) &&
+                (w != state->window_w || h != state->window_h)) {
                 printf("Window requested size %dx%d, got %dx%d\n", state->window_w, state->window_h, w, h);
                 state->window_w = w;
                 state->window_h = h;