* Implemented X11 fullscreen input grab
authorSam Lantinga <slouken@libsdl.org>
Wed, 17 Dec 2008 07:17:54 +0000
changeset 2875 91a7e08cd238
parent 2874 36e312e0fac0
child 2876 3fcb0d447bcd
* Implemented X11 fullscreen input grab * Progress towards being able to toggle in and out of fullscreen mode
src/events/SDL_windowevents.c
src/video/SDL_video.c
src/video/win32/SDL_win32window.c
src/video/x11/SDL_x11window.c
--- a/src/events/SDL_windowevents.c	Tue Dec 16 17:44:10 2008 +0000
+++ b/src/events/SDL_windowevents.c	Wed Dec 17 07:17:54 2008 +0000
@@ -58,6 +58,12 @@
         if (window->flags & SDL_WINDOW_FULLSCREEN) {
             return 0;
         }
+        if (data1 == SDL_WINDOWPOS_UNDEFINED) {
+            data1 = window->x;
+        }
+        if (data2 == SDL_WINDOWPOS_UNDEFINED) {
+            data2 = window->y;
+        }
         if (data1 == window->x && data2 == window->y) {
             return 0;
         }
--- a/src/video/SDL_video.c	Tue Dec 16 17:44:10 2008 +0000
+++ b/src/video/SDL_video.c	Wed Dec 17 07:17:54 2008 +0000
@@ -123,8 +123,7 @@
 static SDL_VideoDevice *_this = NULL;
 
 /* Various local functions */
-int SDL_VideoInit(const char *driver_name, Uint32 flags);
-void SDL_VideoQuit(void);
+static void SDL_UpdateWindowGrab(SDL_Window *window);
 
 static int
 cmpmodes(const void *A, const void *B)
@@ -635,8 +634,7 @@
     for (i = 0; i < display->num_windows; ++i) {
         SDL_Window *window = &display->windows[i];
         if (FULLSCREEN_VISIBLE(window)) {
-            SDL_SetWindowPosition(window->id, SDL_WINDOWPOS_CENTERED,
-                                  SDL_WINDOWPOS_CENTERED);
+            SDL_SetWindowPosition(window->id, window->x, window->y);
         }
     }
 
@@ -752,7 +750,8 @@
     const Uint32 allowed_flags = (SDL_WINDOW_FULLSCREEN |
                                   SDL_WINDOW_OPENGL |
                                   SDL_WINDOW_BORDERLESS |
-                                  SDL_WINDOW_RESIZABLE);
+                                  SDL_WINDOW_RESIZABLE |
+                                  SDL_WINDOW_INPUT_GRABBED);
     SDL_VideoDisplay *display;
     SDL_Window window;
     int num_windows;
@@ -766,11 +765,6 @@
         SDL_SetError("No OpenGL support in video driver");
         return 0;
     }
-    /* Fullscreen windows don't have any window decorations */
-    if (flags & SDL_WINDOW_FULLSCREEN) {
-        flags |= SDL_WINDOW_BORDERLESS;
-        flags &= ~SDL_WINDOW_RESIZABLE;
-    }
     SDL_zero(window);
     window.id = _this->next_object_id++;
     window.x = x;
@@ -809,9 +803,8 @@
     if (flags & SDL_WINDOW_SHOWN) {
         SDL_ShowWindow(window.id);
     }
-    if (flags & SDL_WINDOW_INPUT_GRABBED) {
-        SDL_SetWindowGrab(window.id, 1);
-    }
+    SDL_UpdateWindowGrab(&window);
+
     return window.id;
 }
 
@@ -889,9 +882,8 @@
     if (flags & SDL_WINDOW_SHOWN) {
         SDL_ShowWindow(window->id);
     }
-    if (flags & SDL_WINDOW_INPUT_GRABBED) {
-        SDL_SetWindowGrab(window->id, 1);
-    }
+    SDL_UpdateWindowGrab(window);
+
     return 0;
 }
 
@@ -1004,19 +996,16 @@
     if (!window) {
         return;
     }
-    if (x == SDL_WINDOWPOS_CENTERED) {
-        window->x = (display->current_mode.w - window->w) / 2;
-    } else if (x != SDL_WINDOWPOS_UNDEFINED) {
+    if (x != SDL_WINDOWPOS_UNDEFINED) {
         window->x = x;
     }
-    if (y == SDL_WINDOWPOS_CENTERED) {
-        window->y = (display->current_mode.h - window->h) / 2;
-    } else if (y != SDL_WINDOWPOS_UNDEFINED) {
+    if (y != SDL_WINDOWPOS_UNDEFINED) {
         window->y = y;
     }
     if (_this->SetWindowPosition) {
         _this->SetWindowPosition(_this, window);
     }
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MOVED, x, y);
 }
 
 void
@@ -1082,11 +1071,11 @@
     if (!window || (window->flags & SDL_WINDOW_SHOWN)) {
         return;
     }
-    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_SHOWN, 0, 0);
 
     if (_this->ShowWindow) {
         _this->ShowWindow(_this, window);
     }
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_SHOWN, 0, 0);
 }
 
 void
@@ -1097,11 +1086,11 @@
     if (!window || !(window->flags & SDL_WINDOW_SHOWN)) {
         return;
     }
-    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_HIDDEN, 0, 0);
 
     if (_this->HideWindow) {
         _this->HideWindow(_this, window);
     }
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_HIDDEN, 0, 0);
 }
 
 void
@@ -1125,11 +1114,11 @@
     if (!window || (window->flags & SDL_WINDOW_MAXIMIZED)) {
         return;
     }
-    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
 
     if (_this->MaximizeWindow) {
         _this->MaximizeWindow(_this, window);
     }
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
 }
 
 void
@@ -1140,11 +1129,11 @@
     if (!window || (window->flags & SDL_WINDOW_MINIMIZED)) {
         return;
     }
-    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
 
     if (_this->MinimizeWindow) {
         _this->MinimizeWindow(_this, window);
     }
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
 }
 
 void
@@ -1156,11 +1145,11 @@
         || (window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
         return;
     }
-    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_RESTORED, 0, 0);
 
     if (_this->RestoreWindow) {
         _this->RestoreWindow(_this, window);
     }
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_RESTORED, 0, 0);
 }
 
 int
@@ -1217,7 +1206,12 @@
     } else {
         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
     }
+    SDL_UpdateWindowGrab(window);
+}
 
+static void
+SDL_UpdateWindowGrab(SDL_Window *window)
+{
     if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) {
         _this->SetWindowGrab(_this, window);
     }
@@ -1237,11 +1231,17 @@
 void
 SDL_OnWindowShown(SDL_Window * window)
 {
+    if (window->flags & SDL_WINDOW_FULLSCREEN) {
+        SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
+    }
 }
 
 void
 SDL_OnWindowHidden(SDL_Window * window)
 {
+    if (window->flags & SDL_WINDOW_FULLSCREEN) {
+        SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
+    }
 }
 
 void
@@ -1265,7 +1265,7 @@
     if (display->gamma && _this->SetDisplayGammaRamp) {
         _this->SetDisplayGammaRamp(_this, display->gamma);
     }
-    if ((window->flags & SDL_WINDOW_INPUT_GRABBED) && _this->SetWindowGrab) {
+    if ((window->flags & (SDL_WINDOW_INPUT_GRABBED|SDL_WINDOW_FULLSCREEN)) && _this->SetWindowGrab) {
         _this->SetWindowGrab(_this, window);
     }
 }
@@ -1282,7 +1282,7 @@
     if (display->gamma && _this->SetDisplayGammaRamp) {
         _this->SetDisplayGammaRamp(_this, display->saved_gamma);
     }
-    if ((window->flags & SDL_WINDOW_INPUT_GRABBED) && _this->SetWindowGrab) {
+    if ((window->flags & (SDL_WINDOW_INPUT_GRABBED|SDL_WINDOW_FULLSCREEN)) && _this->SetWindowGrab) {
         _this->SetWindowGrab(_this, window);
     }
 }
--- a/src/video/win32/SDL_win32window.c	Tue Dec 16 17:44:10 2008 +0000
+++ b/src/video/win32/SDL_win32window.c	Wed Dec 17 07:17:54 2008 +0000
@@ -159,12 +159,12 @@
     int x, y;
     int w, h;
 
-    if (window->flags & SDL_WINDOW_BORDERLESS) {
+    if (window->flags & (SDL_WINDOW_BORDERLESS|SDL_WINDOW_FULLSCREEN)) {
         style |= WS_POPUP;
     } else {
         style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
     }
-    if (window->flags & SDL_WINDOW_RESIZABLE) {
+    if ((window->flags & SDL_WINDOW_RESIZABLE) && !(window->flags & SDL_WINDOW_FULLSCREEN)) {
         style |= (WS_THICKFRAME | WS_MAXIMIZEBOX);
     }
 
@@ -182,14 +182,14 @@
     w = (rect.right - rect.left);
     h = (rect.bottom - rect.top);
 
-    if (window->x == SDL_WINDOWPOS_CENTERED) {
+    if ((window->flags & SDL_WINDOW_FULLSCREEN) || window->x == SDL_WINDOWPOS_CENTERED) {
         x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
     } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
         x = CW_USEDEFAULT;
     } else {
         x = window->x + rect.left;
     }
-    if (window->y == SDL_WINDOWPOS_CENTERED) {
+    if ((window->flags & SDL_WINDOW_FULLSCREEN) || window->y == SDL_WINDOWPOS_CENTERED) {
         y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
     } else if (window->y == SDL_WINDOWPOS_UNDEFINED) {
         y = CW_USEDEFAULT;
@@ -331,8 +331,17 @@
     AdjustWindowRectEx(&rect, style,
                        (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) !=
                                                            NULL), 0);
-    x = window->x + rect.left;
-    y = window->y + rect.top;
+
+    if ((window->flags & SDL_WINDOW_FULLSCREEN) || window->x == SDL_WINDOWPOS_CENTERED) {
+        x = (GetSystemMetrics(SM_CXSCREEN) - window->w) / 2;
+    } else {
+        x = window->x + rect.left;
+    }
+    if ((window->flags & SDL_WINDOW_FULLSCREEN) || window->y == SDL_WINDOWPOS_CENTERED) {
+        y = (GetSystemMetrics(SM_CYSCREEN) - window->h) / 2;
+    } else {
+        y = window->y + rect.top;
+    }
 
     SetWindowPos(hwnd, top, x, y, 0, 0, (SWP_NOCOPYBITS | SWP_NOSIZE));
 }
@@ -425,7 +434,7 @@
 {
     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
 
-    if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
+    if ((window->flags & (SDL_WINDOW_INPUT_GRABBED|SDL_WINDOW_FULLSCREEN)) &&
         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
         RECT rect;
         GetClientRect(hwnd, &rect);
--- a/src/video/x11/SDL_x11window.c	Tue Dec 16 17:44:10 2008 +0000
+++ b/src/video/x11/SDL_x11window.c	Wed Dec 17 07:17:54 2008 +0000
@@ -287,7 +287,7 @@
                             visual, AllocNone);
     }
 
-    if (window->x == SDL_WINDOWPOS_CENTERED) {
+    if ((window->flags & SDL_WINDOW_FULLSCREEN) || window->x == SDL_WINDOWPOS_CENTERED) {
         x = (DisplayWidth(data->display, displaydata->screen) -
              window->w) / 2;
     } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
@@ -295,7 +295,7 @@
     } else {
         x = window->x;
     }
-    if (window->y == SDL_WINDOWPOS_CENTERED) {
+    if ((window->flags & SDL_WINDOW_FULLSCREEN) || window->y == SDL_WINDOWPOS_CENTERED) {
         y = (DisplayHeight(data->display, displaydata->screen) -
              window->h) / 2;
     } else if (window->y == SDL_WINDOWPOS_UNDEFINED) {
@@ -321,7 +321,7 @@
 
     sizehints = XAllocSizeHints();
     if (sizehints) {
-        if (window->flags & SDL_WINDOW_RESIZABLE) {
+        if ((window->flags & SDL_WINDOW_RESIZABLE) && !(window->flags & SDL_WINDOW_FULLSCREEN)) {
             sizehints->min_width = 32;
             sizehints->min_height = 32;
             sizehints->max_height = 4096;
@@ -342,7 +342,7 @@
         XFree(sizehints);
     }
 
-    if (window->flags & SDL_WINDOW_BORDERLESS) {
+    if (window->flags & (SDL_WINDOW_BORDERLESS|SDL_WINDOW_FULLSCREEN)) {
         SDL_bool set;
         Atom WM_HINTS;
 
@@ -601,8 +601,19 @@
     SDL_DisplayData *displaydata =
         (SDL_DisplayData *) SDL_GetDisplayFromWindow(window)->driverdata;
     Display *display = data->videodata->display;
+    int x, y;
 
-    XMoveWindow(display, data->window, window->x, window->y);
+    if ((window->flags & SDL_WINDOW_FULLSCREEN) || window->x == SDL_WINDOWPOS_CENTERED) {
+        x = (DisplayWidth(display, displaydata->screen) - window->w) / 2;
+    } else {
+        x = window->x;
+    }
+    if ((window->flags & SDL_WINDOW_FULLSCREEN) || window->y == SDL_WINDOWPOS_CENTERED) {
+        y = (DisplayHeight(display, displaydata->screen) - window->h) / 2;
+    } else {
+        y = window->y;
+    }
+    XMoveWindow(display, data->window, x, y);
 }
 
 void
@@ -662,7 +673,29 @@
 void
 X11_SetWindowGrab(_THIS, SDL_Window * window)
 {
-    /* FIXME */
+    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+    Display *display = data->videodata->display;
+
+    if ((window->flags & (SDL_WINDOW_INPUT_GRABBED|SDL_WINDOW_FULLSCREEN)) &&
+        (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
+        /* Try to grab the mouse */
+        for ( ; ; ) {
+            int result = XGrabPointer(display, data->window, True, 0, GrabModeAsync, GrabModeAsync, data->window, None, CurrentTime);
+            if ( result == GrabSuccess ) {
+                break;
+            }
+            SDL_Delay(100);
+        }
+
+        /* Raise the window if we grab the mouse */
+        XRaiseWindow(display, data->window);
+
+        /* Now grab the keyboard */
+        XGrabKeyboard(display, data->window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
+    } else {
+        XUngrabPointer(display, CurrentTime);
+        XUngrabKeyboard(display, CurrentTime);
+    }
 }
 
 void