X11: Attempt to go fullscreen the way SDL 1.2 did it.
authorRyan C. Gordon <icculus@icculus.org>
Thu, 27 Sep 2012 03:36:13 -0400
changeset 6467ec5a04e921d4
parent 6466 ebe165c00fab
child 6468 6af2a8db95d0
X11: Attempt to go fullscreen the way SDL 1.2 did it.

Ideally this code is never used, but as a legacy fallback, it could be useful.
src/video/x11/SDL_x11sym.h
src/video/x11/SDL_x11window.c
src/video/x11/SDL_x11window.h
     1.1 --- a/src/video/x11/SDL_x11sym.h	Thu Sep 27 00:53:37 2012 -0400
     1.2 +++ b/src/video/x11/SDL_x11sym.h	Thu Sep 27 03:36:13 2012 -0400
     1.3 @@ -30,6 +30,7 @@
     1.4  SDL_X11_SYM(int,XChangePointerControl,(Display* a,Bool b,Bool c,int d,int e,int f),(a,b,c,d,e,f),return)
     1.5  SDL_X11_SYM(int,XChangeProperty,(Display* a,Window b,Atom c,Atom d,int e,int f,_Xconst unsigned char* g,int h),(a,b,c,d,e,f,g,h),return)
     1.6  SDL_X11_SYM(Bool,XCheckIfEvent,(Display* a,XEvent *b,Bool (*c)(Display*,XEvent*,XPointer),XPointer d),(a,b,c,d),return)
     1.7 +SDL_X11_SYM(int,XClearWindow,(Display* a,Window b),(a,b),return)
     1.8  SDL_X11_SYM(int,XCloseDisplay,(Display* a),(a),return)
     1.9  SDL_X11_SYM(int,XConvertSelection,(Display* a,Atom b,Atom c,Atom d,Window e,Time f),(a,b,c,d,e,f),return)
    1.10  SDL_X11_SYM(Pixmap,XCreateBitmapFromData,(Display *dpy,Drawable d,_Xconst char *data,unsigned int width,unsigned int height),(dpy,d,data,width,height),return)
    1.11 @@ -69,6 +70,7 @@
    1.12  SDL_X11_SYM(Status,XIconifyWindow,(Display* a,Window b,int c),(a,b,c),return)
    1.13  SDL_X11_SYM(KeyCode,XKeysymToKeycode,(Display* a,KeySym b),(a,b),return)
    1.14  SDL_X11_SYM(char*,XKeysymToString,(KeySym a),(a),return)
    1.15 +SDL_X11_SYM(int,XInstallColormap,(Display* a,Colormap b),(a,b),return)
    1.16  SDL_X11_SYM(Atom,XInternAtom,(Display* a,_Xconst char* b,Bool c),(a,b,c),return)
    1.17  SDL_X11_SYM(XPixmapFormatValues*,XListPixmapFormats,(Display* a,int* b),(a,b),return)
    1.18  SDL_X11_SYM(KeySym,XLookupKeysym,(XKeyEvent* a,int b),(a,b),return)
    1.19 @@ -85,6 +87,7 @@
    1.20  SDL_X11_SYM(int,XQueryKeymap,(Display* a,char *b),(a,b),return)
    1.21  SDL_X11_SYM(Bool,XQueryPointer,(Display* a,Window b,Window* c,Window* d,int* e,int* f,int* g,int* h,unsigned int* i),(a,b,c,d,e,f,g,h,i),return)
    1.22  SDL_X11_SYM(int,XRaiseWindow,(Display* a,Window b),(a,b),return)
    1.23 +SDL_X11_SYM(int,XReparentWindow,(Display* a,Window b,Window c,int d,int e),(a,b,c,d,e),return)
    1.24  SDL_X11_SYM(int,XResetScreenSaver,(Display* a),(a),return)
    1.25  SDL_X11_SYM(int,XResizeWindow,(Display* a,Window b,unsigned int c,unsigned int d),(a,b,c,d),return)
    1.26  SDL_X11_SYM(int,XSelectInput,(Display* a,Window b,long c),(a,b,c),return)
    1.27 @@ -95,6 +98,7 @@
    1.28  SDL_X11_SYM(int,XSetSelectionOwner,(Display* a,Atom b,Window c,Time d),(a,b,c,d),return)
    1.29  SDL_X11_SYM(int,XSetTransientForHint,(Display* a,Window b,Window c),(a,b,c),return)
    1.30  SDL_X11_SYM(void,XSetTextProperty,(Display* a,Window b,XTextProperty* c,Atom d),(a,b,c,d),)
    1.31 +SDL_X11_SYM(int,XSetWindowBackground,(Display* a,Window b,unsigned long c),(a,b,c),return)
    1.32  SDL_X11_SYM(void,XSetWMProperties,(Display* a,Window b,XTextProperty* c,XTextProperty* d,char** e,int f,XSizeHints* g,XWMHints* h,XClassHint* i),(a,b,c,d,e,f,g,h,i),)
    1.33  SDL_X11_SYM(void,XSetWMNormalHints,(Display* a,Window b,XSizeHints* c),(a,b,c),)
    1.34  SDL_X11_SYM(Status,XSetWMProtocols,(Display* a,Window b,Atom* c,int d),(a,b,c,d),return)
    1.35 @@ -256,6 +260,7 @@
    1.36  SDL_X11_SYM(Bool,XF86VidModeQueryExtension,(Display *a,int *b,int *c),(a,b,c),return)
    1.37  SDL_X11_SYM(Bool,XF86VidModeQueryVersion,(Display *a,int *b,int *c),(a,b,c),return)
    1.38  SDL_X11_SYM(Bool,XF86VidModeSwitchToMode,(Display *a,int b,XF86VidModeModeInfo *c),(a,b,c),return)
    1.39 +SDL_X11_SYM(Bool,XF86VidModeLockModeSwitch,(Display *a,int b,int c),(a,b,c),return)
    1.40  #endif
    1.41  
    1.42  /* *INDENT-ON* */
     2.1 --- a/src/video/x11/SDL_x11window.c	Thu Sep 27 00:53:37 2012 -0400
     2.2 +++ b/src/video/x11/SDL_x11window.c	Thu Sep 27 03:36:13 2012 -0400
     2.3 @@ -38,22 +38,38 @@
     2.4  
     2.5  #include "SDL_timer.h"
     2.6  #include "SDL_syswm.h"
     2.7 +#include "SDL_assert.h"
     2.8  
     2.9  #define _NET_WM_STATE_REMOVE    0l
    2.10  #define _NET_WM_STATE_ADD       1l
    2.11  #define _NET_WM_STATE_TOGGLE    2l
    2.12  
    2.13 +static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
    2.14 +{
    2.15 +    return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
    2.16 +}
    2.17 +static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
    2.18 +{
    2.19 +    return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
    2.20 +}
    2.21 +static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
    2.22 +{
    2.23 +    return ev->type == ConfigureNotify && ev->xunmap.window == *((Window*)win);
    2.24 +}
    2.25 +static Bool isFocusOut(Display *dpy, XEvent *ev, XPointer win)
    2.26 +{
    2.27 +    return ev->type == FocusOut && ev->xunmap.window == *((Window*)win);
    2.28 +}
    2.29 +static Bool isFocusIn(Display *dpy, XEvent *ev, XPointer win)
    2.30 +{
    2.31 +    return ev->type == FocusIn && ev->xunmap.window == *((Window*)win);
    2.32 +}
    2.33 +
    2.34  static SDL_bool
    2.35 -X11_IsWindowOldFullscreen(_THIS, SDL_Window * window)
    2.36 +X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
    2.37  {
    2.38 -    SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    2.39 -
    2.40 -    /* ICCCM2.0-compliant window managers can handle fullscreen windows */
    2.41 -    if ((window->flags & SDL_WINDOW_FULLSCREEN) && !videodata->net_wm) {
    2.42 -        return SDL_TRUE;
    2.43 -    } else {
    2.44 -        return SDL_FALSE;
    2.45 -    }
    2.46 +    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    2.47 +    return (data->fswindow != 0);
    2.48  }
    2.49  
    2.50  static SDL_bool
    2.51 @@ -724,19 +740,6 @@
    2.52      XFlush(display);
    2.53  }
    2.54  
    2.55 -static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
    2.56 -{
    2.57 -    return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
    2.58 -}
    2.59 -static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
    2.60 -{
    2.61 -    return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
    2.62 -}
    2.63 -static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
    2.64 -{
    2.65 -    return ev->type == ConfigureNotify && ev->xunmap.window == *((Window*)win);
    2.66 -}
    2.67 -
    2.68  void
    2.69  X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
    2.70  {
    2.71 @@ -907,8 +910,9 @@
    2.72      return ret;
    2.73  }
    2.74  
    2.75 -void
    2.76 -X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
    2.77 +/* This asks the Window Manager to handle fullscreen for us. Most don't do it right, though. */
    2.78 +static void
    2.79 +X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
    2.80  {
    2.81      SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    2.82      SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
    2.83 @@ -977,6 +981,189 @@
    2.84      XFlush(display);
    2.85  }
    2.86  
    2.87 +static __inline__ int
    2.88 +maxint(const int a, const int b)
    2.89 +{
    2.90 +    return (a > b ? a : b);
    2.91 +}
    2.92 +
    2.93 +
    2.94 +/* This handles fullscreen itself, outside the Window Manager. */
    2.95 +static void
    2.96 +X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
    2.97 +{
    2.98 +    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    2.99 +    SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
   2.100 +    Visual *visual = data->visual;
   2.101 +    Display *display = data->videodata->display;
   2.102 +    const int screen = displaydata->screen;
   2.103 +    Window root = RootWindow(display, screen);
   2.104 +    const int def_vis = (visual == DefaultVisual(display, screen));
   2.105 +    const int w = maxint(window->w, _display->current_mode.w);
   2.106 +    const int h = maxint(window->h, _display->current_mode.h);
   2.107 +    unsigned long xattrmask = 0;
   2.108 +    XSetWindowAttributes xattr;
   2.109 +    XEvent ev;
   2.110 +    int x = 0;
   2.111 +    int y = 0;
   2.112 +
   2.113 +    if ( data->fswindow ) {
   2.114 +        return;  /* already fullscreen, I hope. */
   2.115 +    }
   2.116 +
   2.117 +    /* Ungrab the input so that we can move the mouse around */
   2.118 +    XUngrabPointer(display, CurrentTime);
   2.119 +
   2.120 +    #if SDL_VIDEO_DRIVER_X11_XINERAMA
   2.121 +    /* !!! FIXME: there was some Xinerama code in 1.2 here to set x,y to the origin of a specific screen. */
   2.122 +    #endif
   2.123 +
   2.124 +    SDL_zero(xattr);
   2.125 +    xattr.override_redirect = True;
   2.126 +    xattrmask |= CWOverrideRedirect;
   2.127 +    xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
   2.128 +    xattrmask |= CWBackPixel;
   2.129 +    xattr.border_pixel = 0;
   2.130 +    xattrmask |= CWBorderPixel;
   2.131 +    xattr.colormap = data->colormap;
   2.132 +    xattrmask |= CWColormap;
   2.133 +
   2.134 +    data->fswindow = XCreateWindow(display, root, x, y, w, h, 0,
   2.135 +                                   displaydata->depth, InputOutput,
   2.136 +                                   visual, xattrmask, &xattr);
   2.137 +
   2.138 +    XSelectInput(display, data->fswindow, StructureNotifyMask);
   2.139 +
   2.140 +    XSetWindowBackground(display, data->fswindow, 0);
   2.141 +    XClearWindow(display, data->fswindow);
   2.142 +
   2.143 +    XMapRaised(display, data->fswindow);
   2.144 +
   2.145 +    /* Wait to be mapped, filter Unmap event out if it arrives. */
   2.146 +    XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
   2.147 +    XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
   2.148 +
   2.149 +#if SDL_VIDEO_DRIVER_X11_XVIDMODE
   2.150 +    if ( displaydata->use_vidmode ) {
   2.151 +        XF86VidModeLockModeSwitch(display, screen, True);
   2.152 +    }
   2.153 +#endif
   2.154 +
   2.155 +    XInstallColormap(display, data->colormap);
   2.156 +
   2.157 +    SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
   2.158 +    XFlush(display);
   2.159 +    //XIfEvent(display, &ev, &isConfigureNotify, (XPointer)&data->xwindow);
   2.160 +
   2.161 +    /* Center actual window within our cover-the-screen window. */
   2.162 +    x += (w - window->w) / 2;
   2.163 +    y += (h - window->h) / 2;
   2.164 +    XReparentWindow(display, data->xwindow, data->fswindow, x, y);
   2.165 +    XRaiseWindow(display, data->xwindow);
   2.166 +
   2.167 +    /* Make sure the fswindow is in view by warping mouse to the corner */
   2.168 +    XWarpPointer(display, None, root, 0, 0, 0, 0, 0, 0);
   2.169 +    XFlush(display);
   2.170 +
   2.171 +    /* Center mouse in the window. */
   2.172 +    x += (window->w / 2);
   2.173 +    y += (window->h / 2);
   2.174 +    XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
   2.175 +
   2.176 +    /* Wait to be mapped, filter Unmap event out if it arrives. */
   2.177 +    XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
   2.178 +
   2.179 +    /* Wait to be visible, or XSetInputFocus() triggers an X error. */
   2.180 +    while (SDL_TRUE) {
   2.181 +        XWindowAttributes attr;
   2.182 +        XSync(display, False);
   2.183 +        XGetWindowAttributes(display, data->xwindow, &attr);
   2.184 +        if (attr.map_state == IsViewable)
   2.185 +            break;
   2.186 +    }
   2.187 +
   2.188 +    XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
   2.189 +    window->flags |= SDL_WINDOW_INPUT_FOCUS;
   2.190 +    SDL_SetKeyboardFocus(data->window);
   2.191 +
   2.192 +    X11_SetWindowGrab(_this, window);
   2.193 +
   2.194 +    XSync(display, False);
   2.195 +}
   2.196 +
   2.197 +static void
   2.198 +X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
   2.199 +{
   2.200 +    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   2.201 +    SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
   2.202 +    Display *display = data->videodata->display;
   2.203 +    const int screen = displaydata->screen;
   2.204 +    Window root = RootWindow(display, screen);
   2.205 +    XEvent ev;
   2.206 +
   2.207 +    if (!data->fswindow)
   2.208 +        return;  /* already not fullscreen, I hope. */
   2.209 +
   2.210 +    XReparentWindow(display, data->xwindow, root, window->x, window->y);
   2.211 +
   2.212 +#if SDL_VIDEO_DRIVER_X11_VIDMODE
   2.213 +    if ( displaydata->use_vidmode ) {
   2.214 +        XF86VidModeLockModeSwitch(display, screen, False);
   2.215 +    }
   2.216 +#endif
   2.217 +
   2.218 +    XUnmapWindow(display, data->fswindow);
   2.219 +    /* Wait to be unmapped. */
   2.220 +    XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
   2.221 +    XDestroyWindow(display, data->fswindow);
   2.222 +    data->fswindow = 0;
   2.223 +
   2.224 +    /* catch these events so we know the window is back in business. */
   2.225 +    XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
   2.226 +    XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
   2.227 +
   2.228 +    XSync(display, True);   /* Flush spurious mode change events */
   2.229 +
   2.230 +    X11_SetWindowGrab(_this, window);
   2.231 +
   2.232 +    SetWindowBordered(display, screen, data->xwindow,
   2.233 +                      (window->flags & SDL_WINDOW_BORDERLESS) == 0);
   2.234 +
   2.235 +    XFlush(display);
   2.236 +}
   2.237 +
   2.238 +
   2.239 +void
   2.240 +X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
   2.241 +{
   2.242 +    /* !!! FIXME: SDL_Hint? */
   2.243 +    SDL_bool legacy = SDL_FALSE;
   2.244 +    const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
   2.245 +    if (env) {
   2.246 +        legacy = SDL_atoi(env);
   2.247 +    } else {
   2.248 +        SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
   2.249 +        if ( displaydata->use_vidmode ) {
   2.250 +            legacy = SDL_TRUE;  /* the new stuff only works with XRandR. */
   2.251 +        } else {
   2.252 +            /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
   2.253 +            /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
   2.254 +            legacy = SDL_FALSE;  /* try the new way. */
   2.255 +        }
   2.256 +    }
   2.257 +
   2.258 +    if (legacy) {
   2.259 +        if (fullscreen) {
   2.260 +            X11_BeginWindowFullscreenLegacy(_this, window, _display);
   2.261 +        } else {
   2.262 +            X11_EndWindowFullscreenLegacy(_this, window, _display);
   2.263 +        }
   2.264 +    } else {
   2.265 +        X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
   2.266 +    }
   2.267 +}
   2.268 +
   2.269 +
   2.270  int
   2.271  X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   2.272  {
   2.273 @@ -1054,7 +1241,7 @@
   2.274      SDL_bool oldstyle_fullscreen;
   2.275  
   2.276      /* ICCCM2.0-compliant window managers can handle fullscreen windows */
   2.277 -    oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
   2.278 +    oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
   2.279  
   2.280      if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
   2.281          && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
     3.1 --- a/src/video/x11/SDL_x11window.h	Thu Sep 27 00:53:37 2012 -0400
     3.2 +++ b/src/video/x11/SDL_x11window.h	Thu Sep 27 03:36:13 2012 -0400
     3.3 @@ -27,6 +27,7 @@
     3.4  {
     3.5      SDL_Window *window;
     3.6      Window xwindow;
     3.7 +    Window fswindow;  /* used if we can't have the WM handle fullscreen. */
     3.8      Visual *visual;
     3.9      Colormap colormap;
    3.10  #ifndef NO_SHARED_MEMORY