src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Jul 2014 10:33:32 -0700
changeset 8978 7753e4fd3d1d
parent 8953 dc80dc0bd22e
child 9117 236241f5d225
permissions -rw-r--r--
Fixed bug 2629 - Mac: crash when calling SDL_DestroyWindow with an active OpenGL context

Alex Szpakowski

Since this commit https://hg.libsdl.org/SDL/rev/1519c462cee6 , calling SDL_DestroyWindow will crash the program if the window has an active OpenGL context.

This is because the Cocoa_DestroyWindow code sets the window's driverdata to NULL and then calls [context setWindow:NULL], which tries to access the window's driverdata, resulting in a null pointer dereference.

I have attached a patch which fixes the issue by moving the line which sets the driverdata to NULL to after the lines which call functions that use the driverdata pointer.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if SDL_VIDEO_DRIVER_X11
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_hints.h"
    27 #include "../SDL_sysvideo.h"
    28 #include "../SDL_pixels_c.h"
    29 #include "../../events/SDL_keyboard_c.h"
    30 #include "../../events/SDL_mouse_c.h"
    31 
    32 #include "SDL_x11video.h"
    33 #include "SDL_x11mouse.h"
    34 #include "SDL_x11shape.h"
    35 #include "SDL_x11xinput2.h"
    36 
    37 #if SDL_VIDEO_OPENGL_EGL
    38 #include "SDL_x11opengles.h"
    39 #endif
    40 
    41 #include "SDL_timer.h"
    42 #include "SDL_syswm.h"
    43 #include "SDL_assert.h"
    44 
    45 #define _NET_WM_STATE_REMOVE    0l
    46 #define _NET_WM_STATE_ADD       1l
    47 #define _NET_WM_STATE_TOGGLE    2l
    48 
    49 static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
    50 {
    51     return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
    52 }
    53 static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
    54 {
    55     return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
    56 }
    57 static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
    58 {
    59     return ev->type == ConfigureNotify && ev->xconfigure.window == *((Window*)win);
    60 }
    61 
    62 /*
    63 static Bool
    64 X11_XIfEventTimeout(Display *display, XEvent *event_return, Bool (*predicate)(), XPointer arg, int timeoutMS)
    65 {
    66     Uint32 start = SDL_GetTicks();
    67 
    68     while (!X11_XCheckIfEvent(display, event_return, predicate, arg)) {
    69         if (SDL_TICKS_PASSED(SDL_GetTicks(), start + timeoutMS)) {
    70             return False;
    71         }
    72     }
    73     return True;
    74 }
    75 */
    76 
    77 static SDL_bool
    78 X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
    79 {
    80     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    81     return (data->fswindow != 0);
    82 }
    83 
    84 static SDL_bool
    85 X11_IsWindowMapped(_THIS, SDL_Window * window)
    86 {
    87     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    88     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    89     XWindowAttributes attr;
    90 
    91     X11_XGetWindowAttributes(videodata->display, data->xwindow, &attr);
    92     if (attr.map_state != IsUnmapped) {
    93         return SDL_TRUE;
    94     } else {
    95         return SDL_FALSE;
    96     }
    97 }
    98 
    99 #if 0
   100 static SDL_bool
   101 X11_IsActionAllowed(SDL_Window *window, Atom action)
   102 {
   103     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   104     Atom _NET_WM_ALLOWED_ACTIONS = data->videodata->_NET_WM_ALLOWED_ACTIONS;
   105     Atom type;
   106     Display *display = data->videodata->display;
   107     int form;
   108     unsigned long remain;
   109     unsigned long len, i;
   110     Atom *list;
   111     SDL_bool ret = SDL_FALSE;
   112 
   113     if (X11_XGetWindowProperty(display, data->xwindow, _NET_WM_ALLOWED_ACTIONS, 0, 1024, False, XA_ATOM, &type, &form, &len, &remain, (unsigned char **)&list) == Success)
   114     {
   115         for (i=0; i<len; ++i)
   116         {
   117             if (list[i] == action) {
   118                 ret = SDL_TRUE;
   119                 break;
   120             }
   121         }
   122         X11_XFree(list);
   123     }
   124     return ret;
   125 }
   126 #endif /* 0 */
   127 
   128 void
   129 X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags)
   130 {
   131     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   132     Display *display = videodata->display;
   133     Atom _NET_WM_STATE = videodata->_NET_WM_STATE;
   134     /* Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN; */
   135     Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED;
   136     Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   137     Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   138     Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN;
   139     Atom atoms[5];
   140     int count = 0;
   141 
   142     /* The window manager sets this property, we shouldn't set it.
   143        If we did, this would indicate to the window manager that we don't
   144        actually want to be mapped during X11_XMapRaised(), which would be bad.
   145      *
   146     if (flags & SDL_WINDOW_HIDDEN) {
   147         atoms[count++] = _NET_WM_STATE_HIDDEN;
   148     }
   149     */
   150     if (flags & SDL_WINDOW_INPUT_FOCUS) {
   151         atoms[count++] = _NET_WM_STATE_FOCUSED;
   152     }
   153     if (flags & SDL_WINDOW_MAXIMIZED) {
   154         atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   155         atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   156     }
   157     if (flags & SDL_WINDOW_FULLSCREEN) {
   158         atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   159     }
   160     if (count > 0) {
   161         X11_XChangeProperty(display, xwindow, _NET_WM_STATE, XA_ATOM, 32,
   162                         PropModeReplace, (unsigned char *)atoms, count);
   163     } else {
   164         X11_XDeleteProperty(display, xwindow, _NET_WM_STATE);
   165     }
   166 }
   167 
   168 Uint32
   169 X11_GetNetWMState(_THIS, Window xwindow)
   170 {
   171     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   172     Display *display = videodata->display;
   173     Atom _NET_WM_STATE = videodata->_NET_WM_STATE;
   174     Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN;
   175     Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED;
   176     Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   177     Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   178     Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN;
   179     Atom actualType;
   180     int actualFormat;
   181     unsigned long i, numItems, bytesAfter;
   182     unsigned char *propertyValue = NULL;
   183     long maxLength = 1024;
   184     Uint32 flags = 0;
   185 
   186     if (X11_XGetWindowProperty(display, xwindow, _NET_WM_STATE,
   187                            0l, maxLength, False, XA_ATOM, &actualType,
   188                            &actualFormat, &numItems, &bytesAfter,
   189                            &propertyValue) == Success) {
   190         Atom *atoms = (Atom *) propertyValue;
   191         int maximized = 0;
   192         int fullscreen = 0;
   193 
   194         for (i = 0; i < numItems; ++i) {
   195             if (atoms[i] == _NET_WM_STATE_HIDDEN) {
   196                 flags |= SDL_WINDOW_HIDDEN;
   197             } else if (atoms[i] == _NET_WM_STATE_FOCUSED) {
   198                 flags |= SDL_WINDOW_INPUT_FOCUS;
   199             } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
   200                 maximized |= 1;
   201             } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
   202                 maximized |= 2;
   203             } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
   204                 fullscreen = 1;
   205             }
   206         }
   207         if (maximized == 3) {
   208             flags |= SDL_WINDOW_MAXIMIZED;
   209         }  else if (fullscreen == 1) {
   210             flags |= SDL_WINDOW_FULLSCREEN;
   211         }
   212         X11_XFree(propertyValue);
   213     }
   214 
   215     /* FIXME, check the size hints for resizable */
   216     /* flags |= SDL_WINDOW_RESIZABLE; */
   217 
   218     return flags;
   219 }
   220 
   221 static int
   222 SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
   223 {
   224     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   225     SDL_WindowData *data;
   226     int numwindows = videodata->numwindows;
   227     int windowlistlength = videodata->windowlistlength;
   228     SDL_WindowData **windowlist = videodata->windowlist;
   229 
   230     /* Allocate the window data */
   231     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   232     if (!data) {
   233         return SDL_OutOfMemory();
   234     }
   235     data->window = window;
   236     data->xwindow = w;
   237 #ifdef X_HAVE_UTF8_STRING
   238     if (SDL_X11_HAVE_UTF8 && videodata->im) {
   239         data->ic =
   240             X11_XCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w,
   241                        XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
   242                        NULL);
   243     }
   244 #endif
   245     data->created = created;
   246     data->videodata = videodata;
   247 
   248     /* Associate the data with the window */
   249 
   250     if (numwindows < windowlistlength) {
   251         windowlist[numwindows] = data;
   252         videodata->numwindows++;
   253     } else {
   254         windowlist =
   255             (SDL_WindowData **) SDL_realloc(windowlist,
   256                                             (numwindows +
   257                                              1) * sizeof(*windowlist));
   258         if (!windowlist) {
   259             SDL_free(data);
   260             return SDL_OutOfMemory();
   261         }
   262         windowlist[numwindows] = data;
   263         videodata->numwindows++;
   264         videodata->windowlistlength++;
   265         videodata->windowlist = windowlist;
   266     }
   267 
   268     /* Fill in the SDL window with the window data */
   269     {
   270         XWindowAttributes attrib;
   271 
   272         X11_XGetWindowAttributes(data->videodata->display, w, &attrib);
   273         window->x = attrib.x;
   274         window->y = attrib.y;
   275         window->w = attrib.width;
   276         window->h = attrib.height;
   277         if (attrib.map_state != IsUnmapped) {
   278             window->flags |= SDL_WINDOW_SHOWN;
   279         } else {
   280             window->flags &= ~SDL_WINDOW_SHOWN;
   281         }
   282         data->visual = attrib.visual;
   283         data->colormap = attrib.colormap;
   284     }
   285 
   286     window->flags |= X11_GetNetWMState(_this, w);
   287 
   288     {
   289         Window FocalWindow;
   290         int RevertTo=0;
   291         X11_XGetInputFocus(data->videodata->display, &FocalWindow, &RevertTo);
   292         if (FocalWindow==w)
   293         {
   294             window->flags |= SDL_WINDOW_INPUT_FOCUS;
   295         }
   296 
   297         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
   298             SDL_SetKeyboardFocus(data->window);
   299         }
   300 
   301         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   302             /* Tell x11 to clip mouse */
   303         }
   304     }
   305 
   306     /* All done! */
   307     window->driverdata = data;
   308     return 0;
   309 }
   310 
   311 static void
   312 SetWindowBordered(Display *display, int screen, Window window, SDL_bool border)
   313 {
   314     /*
   315      * this code used to check for KWM_WIN_DECORATION, but KDE hasn't
   316      *  supported it for years and years. It now respects _MOTIF_WM_HINTS.
   317      *  Gnome is similar: just use the Motif atom.
   318      */
   319 
   320     Atom WM_HINTS = X11_XInternAtom(display, "_MOTIF_WM_HINTS", True);
   321     if (WM_HINTS != None) {
   322         /* Hints used by Motif compliant window managers */
   323         struct
   324         {
   325             unsigned long flags;
   326             unsigned long functions;
   327             unsigned long decorations;
   328             long input_mode;
   329             unsigned long status;
   330         } MWMHints = {
   331             (1L << 1), 0, border ? 1 : 0, 0, 0
   332         };
   333 
   334         X11_XChangeProperty(display, window, WM_HINTS, WM_HINTS, 32,
   335                         PropModeReplace, (unsigned char *) &MWMHints,
   336                         sizeof(MWMHints) / 4);
   337     } else {  /* set the transient hints instead, if necessary */
   338         X11_XSetTransientForHint(display, window, RootWindow(display, screen));
   339     }
   340 }
   341 
   342 int
   343 X11_CreateWindow(_THIS, SDL_Window * window)
   344 {
   345     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   346     SDL_DisplayData *displaydata =
   347         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   348     SDL_WindowData *windowdata;
   349     Display *display = data->display;
   350     int screen = displaydata->screen;
   351     Visual *visual;
   352     int depth;
   353     XSetWindowAttributes xattr;
   354     Window w;
   355     XSizeHints *sizehints;
   356     XWMHints *wmhints;
   357     XClassHint *classhints;
   358     const long _NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1;
   359     Atom _NET_WM_BYPASS_COMPOSITOR;
   360     Atom _NET_WM_WINDOW_TYPE;
   361     Atom _NET_WM_WINDOW_TYPE_NORMAL;
   362     Atom _NET_WM_PID;
   363     Atom XdndAware, xdnd_version = 5;
   364     long fevent = 0;
   365 
   366 #if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_EGL
   367     if ((window->flags & SDL_WINDOW_OPENGL) &&
   368         !SDL_getenv("SDL_VIDEO_X11_VISUALID")) {
   369         XVisualInfo *vinfo = NULL;
   370 
   371 #if SDL_VIDEO_OPENGL_EGL
   372         if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES 
   373 #if SDL_VIDEO_OPENGL_GLX            
   374             && ( !_this->gl_data || ! _this->gl_data->HAS_GLX_EXT_create_context_es2_profile )
   375 #endif
   376         ) {
   377             vinfo = X11_GLES_GetVisual(_this, display, screen);
   378         } else
   379 #endif
   380         {
   381 #if SDL_VIDEO_OPENGL_GLX
   382             vinfo = X11_GL_GetVisual(_this, display, screen);
   383 #endif
   384         }
   385 
   386         if (!vinfo) {
   387             return -1;
   388         }
   389         visual = vinfo->visual;
   390         depth = vinfo->depth;
   391         X11_XFree(vinfo);
   392     } else
   393 #endif
   394     {
   395         visual = displaydata->visual;
   396         depth = displaydata->depth;
   397     }
   398 
   399     xattr.override_redirect = False;
   400     xattr.background_pixmap = None;
   401     xattr.border_pixel = 0;
   402 
   403     if (visual->class == DirectColor) {
   404         XColor *colorcells;
   405         int i;
   406         int ncolors;
   407         int rmax, gmax, bmax;
   408         int rmask, gmask, bmask;
   409         int rshift, gshift, bshift;
   410 
   411         xattr.colormap =
   412             X11_XCreateColormap(display, RootWindow(display, screen),
   413                             visual, AllocAll);
   414 
   415         /* If we can't create a colormap, then we must die */
   416         if (!xattr.colormap) {
   417             return SDL_SetError("Could not create writable colormap");
   418         }
   419 
   420         /* OK, we got a colormap, now fill it in as best as we can */
   421         colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   422         if (!colorcells) {
   423             return SDL_OutOfMemory();
   424         }
   425         ncolors = visual->map_entries;
   426         rmax = 0xffff;
   427         gmax = 0xffff;
   428         bmax = 0xffff;
   429 
   430         rshift = 0;
   431         rmask = visual->red_mask;
   432         while (0 == (rmask & 1)) {
   433             rshift++;
   434             rmask >>= 1;
   435         }
   436 
   437         gshift = 0;
   438         gmask = visual->green_mask;
   439         while (0 == (gmask & 1)) {
   440             gshift++;
   441             gmask >>= 1;
   442         }
   443 
   444         bshift = 0;
   445         bmask = visual->blue_mask;
   446         while (0 == (bmask & 1)) {
   447             bshift++;
   448             bmask >>= 1;
   449         }
   450 
   451         /* build the color table pixel values */
   452         for (i = 0; i < ncolors; i++) {
   453             Uint32 red = (rmax * i) / (ncolors - 1);
   454             Uint32 green = (gmax * i) / (ncolors - 1);
   455             Uint32 blue = (bmax * i) / (ncolors - 1);
   456 
   457             Uint32 rbits = (rmask * i) / (ncolors - 1);
   458             Uint32 gbits = (gmask * i) / (ncolors - 1);
   459             Uint32 bbits = (bmask * i) / (ncolors - 1);
   460 
   461             Uint32 pix =
   462                 (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   463 
   464             colorcells[i].pixel = pix;
   465 
   466             colorcells[i].red = red;
   467             colorcells[i].green = green;
   468             colorcells[i].blue = blue;
   469 
   470             colorcells[i].flags = DoRed | DoGreen | DoBlue;
   471         }
   472 
   473         X11_XStoreColors(display, xattr.colormap, colorcells, ncolors);
   474 
   475         SDL_free(colorcells);
   476     } else {
   477         xattr.colormap =
   478             X11_XCreateColormap(display, RootWindow(display, screen),
   479                             visual, AllocNone);
   480     }
   481 
   482     w = X11_XCreateWindow(display, RootWindow(display, screen),
   483                       window->x, window->y, window->w, window->h,
   484                       0, depth, InputOutput, visual,
   485                       (CWOverrideRedirect | CWBackPixmap | CWBorderPixel |
   486                        CWColormap), &xattr);
   487     if (!w) {
   488         return SDL_SetError("Couldn't create window");
   489     }
   490 
   491     SetWindowBordered(display, screen, w,
   492                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
   493 
   494     sizehints = X11_XAllocSizeHints();
   495     /* Setup the normal size hints */
   496     sizehints->flags = 0;
   497     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   498         sizehints->min_width = sizehints->max_width = window->w;
   499         sizehints->min_height = sizehints->max_height = window->h;
   500         sizehints->flags |= (PMaxSize | PMinSize);
   501     }
   502     sizehints->x = window->x;
   503     sizehints->y = window->y;
   504     sizehints->flags |= USPosition;
   505 
   506     /* Setup the input hints so we get keyboard input */
   507     wmhints = X11_XAllocWMHints();
   508     wmhints->input = True;
   509     wmhints->flags = InputHint;
   510 
   511     /* Setup the class hints so we can get an icon (AfterStep) */
   512     classhints = X11_XAllocClassHint();
   513     classhints->res_name = data->classname;
   514     classhints->res_class = data->classname;
   515 
   516     /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */
   517     X11_XSetWMProperties(display, w, NULL, NULL, NULL, 0, sizehints, wmhints, classhints);
   518 
   519     X11_XFree(sizehints);
   520     X11_XFree(wmhints);
   521     X11_XFree(classhints);
   522     /* Set the PID related to the window for the given hostname, if possible */
   523     if (data->pid > 0) {
   524         _NET_WM_PID = X11_XInternAtom(display, "_NET_WM_PID", False);
   525         X11_XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace,
   526                         (unsigned char *)&data->pid, 1);
   527     }
   528 
   529     /* Set the window manager state */
   530     X11_SetNetWMState(_this, w, window->flags);
   531 
   532     /* Let the window manager know we're a "normal" window */
   533     _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
   534     _NET_WM_WINDOW_TYPE_NORMAL = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
   535     X11_XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
   536                     PropModeReplace,
   537                     (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1);
   538 
   539     _NET_WM_BYPASS_COMPOSITOR = X11_XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False);
   540     X11_XChangeProperty(display, w, _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
   541                     PropModeReplace,
   542                     (unsigned char *)&_NET_WM_BYPASS_COMPOSITOR_HINT_ON, 1);
   543 
   544     {
   545         Atom protocols[] = {
   546             data->WM_DELETE_WINDOW, /* Allow window to be deleted by the WM */
   547             data->_NET_WM_PING, /* Respond so WM knows we're alive */
   548         };
   549         X11_XSetWMProtocols(display, w, protocols, sizeof (protocols) / sizeof (protocols[0]));
   550     }
   551 
   552     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   553         X11_XDestroyWindow(display, w);
   554         return -1;
   555     }
   556     windowdata = (SDL_WindowData *) window->driverdata;
   557 
   558 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   559     if ((window->flags & SDL_WINDOW_OPENGL) && 
   560         _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
   561 #if SDL_VIDEO_OPENGL_GLX            
   562         && ( !_this->gl_data || ! _this->gl_data->HAS_GLX_EXT_create_context_es2_profile )
   563 #endif  
   564     ) {
   565 #if SDL_VIDEO_OPENGL_EGL  
   566         if (!_this->egl_data) {
   567             X11_XDestroyWindow(display, w);
   568             return -1;
   569         }
   570 
   571         /* Create the GLES window surface */
   572         windowdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) w);
   573 
   574         if (windowdata->egl_surface == EGL_NO_SURFACE) {
   575             X11_XDestroyWindow(display, w);
   576             return SDL_SetError("Could not create GLES window surface");
   577         }
   578 #else
   579         return SDL_SetError("Could not create GLES window surface (no EGL support available)");
   580 #endif /* SDL_VIDEO_OPENGL_EGL */
   581     }
   582 #endif
   583     
   584 
   585 #ifdef X_HAVE_UTF8_STRING
   586     if (SDL_X11_HAVE_UTF8 && windowdata->ic) {
   587         X11_XGetICValues(windowdata->ic, XNFilterEvents, &fevent, NULL);
   588     }
   589 #endif
   590 
   591     X11_Xinput2SelectTouch(_this, window);
   592 
   593     X11_XSelectInput(display, w,
   594                  (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   595                  ExposureMask | ButtonPressMask | ButtonReleaseMask |
   596                  PointerMotionMask | KeyPressMask | KeyReleaseMask |
   597                  PropertyChangeMask | StructureNotifyMask |
   598                  KeymapStateMask | fevent));
   599 
   600     XdndAware = X11_XInternAtom(display, "XdndAware", False);
   601     X11_XChangeProperty(display, w, XdndAware, XA_ATOM, 32,
   602                  PropModeReplace,
   603                  (unsigned char*)&xdnd_version, 1);
   604 
   605     X11_XFlush(display);
   606 
   607     return 0;
   608 }
   609 
   610 int
   611 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   612 {
   613     Window w = (Window) data;
   614 
   615     window->title = X11_GetWindowTitle(_this, w);
   616 
   617     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   618         return -1;
   619     }
   620     return 0;
   621 }
   622 
   623 char *
   624 X11_GetWindowTitle(_THIS, Window xwindow)
   625 {
   626     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   627     Display *display = data->display;
   628     int status, real_format;
   629     Atom real_type;
   630     unsigned long items_read, items_left;
   631     unsigned char *propdata;
   632     char *title = NULL;
   633 
   634     status = X11_XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
   635                 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
   636                 &items_read, &items_left, &propdata);
   637     if (status == Success && propdata) {
   638         title = SDL_strdup(SDL_static_cast(char*, propdata));
   639         X11_XFree(propdata);
   640     } else {
   641         status = X11_XGetWindowProperty(display, xwindow, XA_WM_NAME,
   642                     0L, 8192L, False, XA_STRING, &real_type, &real_format,
   643                     &items_read, &items_left, &propdata);
   644         if (status == Success && propdata) {
   645             title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
   646         } else {
   647             title = SDL_strdup("");
   648         }
   649     }
   650     return title;
   651 }
   652 
   653 void
   654 X11_SetWindowTitle(_THIS, SDL_Window * window)
   655 {
   656     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   657     Display *display = data->videodata->display;
   658     XTextProperty titleprop, iconprop;
   659     Status status;
   660     const char *title = window->title;
   661     const char *icon = NULL;
   662 
   663 #ifdef X_HAVE_UTF8_STRING
   664     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   665     Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME;
   666 #endif
   667 
   668     if (title != NULL) {
   669         char *title_locale = SDL_iconv_utf8_locale(title);
   670         if (!title_locale) {
   671             SDL_OutOfMemory();
   672             return;
   673         }
   674         status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
   675         SDL_free(title_locale);
   676         if (status) {
   677             X11_XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   678             X11_XFree(titleprop.value);
   679         }
   680 #ifdef X_HAVE_UTF8_STRING
   681         if (SDL_X11_HAVE_UTF8) {
   682             status =
   683                 X11_Xutf8TextListToTextProperty(display, (char **) &title, 1,
   684                                             XUTF8StringStyle, &titleprop);
   685             if (status == Success) {
   686                 X11_XSetTextProperty(display, data->xwindow, &titleprop,
   687                                  _NET_WM_NAME);
   688                 X11_XFree(titleprop.value);
   689             }
   690         }
   691 #endif
   692     }
   693     if (icon != NULL) {
   694         char *icon_locale = SDL_iconv_utf8_locale(icon);
   695         if (!icon_locale) {
   696             SDL_OutOfMemory();
   697             return;
   698         }
   699         status = X11_XStringListToTextProperty(&icon_locale, 1, &iconprop);
   700         SDL_free(icon_locale);
   701         if (status) {
   702             X11_XSetTextProperty(display, data->xwindow, &iconprop,
   703                              XA_WM_ICON_NAME);
   704             X11_XFree(iconprop.value);
   705         }
   706 #ifdef X_HAVE_UTF8_STRING
   707         if (SDL_X11_HAVE_UTF8) {
   708             status =
   709                 X11_Xutf8TextListToTextProperty(display, (char **) &icon, 1,
   710                                             XUTF8StringStyle, &iconprop);
   711             if (status == Success) {
   712                 X11_XSetTextProperty(display, data->xwindow, &iconprop,
   713                                  _NET_WM_ICON_NAME);
   714                 X11_XFree(iconprop.value);
   715             }
   716         }
   717 #endif
   718     }
   719     X11_XFlush(display);
   720 }
   721 
   722 void
   723 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   724 {
   725     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   726     Display *display = data->videodata->display;
   727     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   728 
   729     if (icon) {
   730         int propsize;
   731         long *propdata;
   732 
   733         /* Set the _NET_WM_ICON property */
   734         SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
   735         propsize = 2 + (icon->w * icon->h);
   736         propdata = SDL_malloc(propsize * sizeof(long));
   737         if (propdata) {
   738             int x, y;
   739             Uint32 *src;
   740             long *dst;
   741 
   742             propdata[0] = icon->w;
   743             propdata[1] = icon->h;
   744             dst = &propdata[2];
   745             for (y = 0; y < icon->h; ++y) {
   746                 src = (Uint32*)((Uint8*)icon->pixels + y * icon->pitch);
   747                 for (x = 0; x < icon->w; ++x) {
   748                     *dst++ = *src++;
   749                 }
   750             }
   751             X11_XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   752                             32, PropModeReplace, (unsigned char *) propdata,
   753                             propsize);
   754         }
   755         SDL_free(propdata);
   756     } else {
   757         X11_XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   758     }
   759     X11_XFlush(display);
   760 }
   761 
   762 void
   763 X11_SetWindowPosition(_THIS, SDL_Window * window)
   764 {
   765     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   766     Display *display = data->videodata->display;
   767 
   768     X11_XMoveWindow(display, data->xwindow, window->x, window->y);
   769     X11_XFlush(display);
   770 }
   771 
   772 void
   773 X11_SetWindowMinimumSize(_THIS, SDL_Window * window)
   774 {
   775     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   776     Display *display = data->videodata->display;
   777 
   778     if (window->flags & SDL_WINDOW_RESIZABLE) {
   779          XSizeHints *sizehints = X11_XAllocSizeHints();
   780          long userhints;
   781 
   782          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   783 
   784          sizehints->min_width = window->min_w;
   785          sizehints->min_height = window->min_h;
   786          sizehints->flags |= PMinSize;
   787 
   788          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   789 
   790          X11_XFree(sizehints);
   791 
   792         /* See comment in X11_SetWindowSize. */
   793         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   794         X11_XMoveWindow(display, data->xwindow, window->x, window->y);
   795         X11_XRaiseWindow(display, data->xwindow);
   796     }
   797 
   798     X11_XFlush(display);
   799 }
   800 
   801 void
   802 X11_SetWindowMaximumSize(_THIS, SDL_Window * window)
   803 {
   804     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   805     Display *display = data->videodata->display;
   806 
   807     if (window->flags & SDL_WINDOW_RESIZABLE) {
   808          XSizeHints *sizehints = X11_XAllocSizeHints();
   809          long userhints;
   810 
   811          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   812 
   813          sizehints->max_width = window->max_w;
   814          sizehints->max_height = window->max_h;
   815          sizehints->flags |= PMaxSize;
   816 
   817          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   818 
   819          X11_XFree(sizehints);
   820 
   821         /* See comment in X11_SetWindowSize. */
   822         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   823         X11_XMoveWindow(display, data->xwindow, window->x, window->y);
   824         X11_XRaiseWindow(display, data->xwindow);
   825     }
   826 
   827     X11_XFlush(display);
   828 }
   829 
   830 void
   831 X11_SetWindowSize(_THIS, SDL_Window * window)
   832 {
   833     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   834     Display *display = data->videodata->display;
   835 
   836     if (SDL_IsShapedWindow(window)) {
   837         X11_ResizeWindowShape(window);
   838     }
   839     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   840          /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the X11_XResizeWindow, thus
   841             we must set the size hints to adjust the window size. */
   842          XSizeHints *sizehints = X11_XAllocSizeHints();
   843          long userhints;
   844 
   845          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   846 
   847          sizehints->min_width = sizehints->max_width = window->w;
   848          sizehints->min_height = sizehints->max_height = window->h;
   849          sizehints->flags |= PMinSize | PMaxSize;
   850 
   851          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   852 
   853          X11_XFree(sizehints);
   854 
   855         /* From Pierre-Loup:
   856            WMs each have their little quirks with that.  When you change the
   857            size hints, they get a ConfigureNotify event with the
   858            WM_NORMAL_SIZE_HINTS Atom.  They all save the hints then, but they
   859            don't all resize the window right away to enforce the new hints.
   860 
   861            Some of them resize only after:
   862             - A user-initiated move or resize
   863             - A code-initiated move or resize
   864             - Hiding & showing window (Unmap & map)
   865 
   866            The following move & resize seems to help a lot of WMs that didn't
   867            properly update after the hints were changed. We don't do a
   868            hide/show, because there are supposedly subtle problems with doing so
   869            and transitioning from windowed to fullscreen in Unity.
   870          */
   871         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   872         X11_XMoveWindow(display, data->xwindow, window->x, window->y);
   873         X11_XRaiseWindow(display, data->xwindow);
   874     } else {
   875         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   876     }
   877 
   878     X11_XFlush(display);
   879 }
   880 
   881 void
   882 X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   883 {
   884     const SDL_bool focused = ((window->flags & SDL_WINDOW_INPUT_FOCUS) != 0);
   885     const SDL_bool visible = ((window->flags & SDL_WINDOW_HIDDEN) == 0);
   886     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   887     SDL_DisplayData *displaydata =
   888         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   889     Display *display = data->videodata->display;
   890     XEvent event;
   891 
   892     SetWindowBordered(display, displaydata->screen, data->xwindow, bordered);
   893     X11_XFlush(display);
   894     X11_XIfEvent(display, &event, &isConfigureNotify, (XPointer)&data->xwindow);
   895 
   896     if (visible) {
   897         XWindowAttributes attr;
   898         do {
   899             X11_XSync(display, False);
   900             X11_XGetWindowAttributes(display, data->xwindow, &attr);
   901         } while (attr.map_state != IsViewable);
   902 
   903         if (focused) {
   904             X11_XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
   905         }
   906     }
   907 
   908     /* make sure these don't make it to the real event queue if they fired here. */
   909     X11_XSync(display, False);
   910     X11_XCheckIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
   911     X11_XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   912 }
   913 
   914 void
   915 X11_ShowWindow(_THIS, SDL_Window * window)
   916 {
   917     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   918     Display *display = data->videodata->display;
   919     XEvent event;
   920 
   921     if (!X11_IsWindowMapped(_this, window)) {
   922         X11_XMapRaised(display, data->xwindow);
   923         /* Blocking wait for "MapNotify" event.
   924          * We use X11_XIfEvent because pXWindowEvent takes a mask rather than a type,
   925          * and XCheckTypedWindowEvent doesn't block */
   926         X11_XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   927         X11_XFlush(display);
   928     }
   929 }
   930 
   931 void
   932 X11_HideWindow(_THIS, SDL_Window * window)
   933 {
   934     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   935     SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   936     Display *display = data->videodata->display;
   937     XEvent event;
   938 
   939     if (X11_IsWindowMapped(_this, window)) {
   940         X11_XWithdrawWindow(display, data->xwindow, displaydata->screen);
   941         /* Blocking wait for "UnmapNotify" event */
   942         X11_XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
   943         X11_XFlush(display);
   944     }
   945 }
   946 
   947 static void
   948 SetWindowActive(_THIS, SDL_Window * window)
   949 {
   950     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   951     SDL_DisplayData *displaydata =
   952         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   953     Display *display = data->videodata->display;
   954     Atom _NET_ACTIVE_WINDOW = data->videodata->_NET_ACTIVE_WINDOW;
   955 
   956     if (X11_IsWindowMapped(_this, window)) {
   957         XEvent e;
   958 
   959         SDL_zero(e);
   960         e.xany.type = ClientMessage;
   961         e.xclient.message_type = _NET_ACTIVE_WINDOW;
   962         e.xclient.format = 32;
   963         e.xclient.window = data->xwindow;
   964         e.xclient.data.l[0] = 1;  /* source indication. 1 = application */
   965         e.xclient.data.l[1] = CurrentTime;
   966         e.xclient.data.l[2] = 0;
   967 
   968         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   969                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   970 
   971         X11_XFlush(display);
   972     }
   973 }
   974 
   975 void
   976 X11_RaiseWindow(_THIS, SDL_Window * window)
   977 {
   978     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   979     Display *display = data->videodata->display;
   980 
   981     X11_XRaiseWindow(display, data->xwindow);
   982     SetWindowActive(_this, window);
   983     X11_XFlush(display);
   984 }
   985 
   986 static void
   987 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   988 {
   989     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   990     SDL_DisplayData *displaydata =
   991         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   992     Display *display = data->videodata->display;
   993     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   994     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   995     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   996 
   997     if (maximized) {
   998         window->flags |= SDL_WINDOW_MAXIMIZED;
   999     } else {
  1000         window->flags &= ~SDL_WINDOW_MAXIMIZED;
  1001     }
  1002 
  1003     if (X11_IsWindowMapped(_this, window)) {
  1004         XEvent e;
  1005 
  1006         SDL_zero(e);
  1007         e.xany.type = ClientMessage;
  1008         e.xclient.message_type = _NET_WM_STATE;
  1009         e.xclient.format = 32;
  1010         e.xclient.window = data->xwindow;
  1011         e.xclient.data.l[0] =
  1012             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  1013         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
  1014         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
  1015         e.xclient.data.l[3] = 0l;
  1016 
  1017         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1018                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1019     } else {
  1020         X11_SetNetWMState(_this, data->xwindow, window->flags);
  1021     }
  1022     X11_XFlush(display);
  1023 }
  1024 
  1025 void
  1026 X11_MaximizeWindow(_THIS, SDL_Window * window)
  1027 {
  1028     SetWindowMaximized(_this, window, SDL_TRUE);
  1029 }
  1030 
  1031 void
  1032 X11_MinimizeWindow(_THIS, SDL_Window * window)
  1033 {
  1034     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1035     SDL_DisplayData *displaydata =
  1036         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  1037     Display *display = data->videodata->display;
  1038 
  1039     X11_XIconifyWindow(display, data->xwindow, displaydata->screen);
  1040     X11_XFlush(display);
  1041 }
  1042 
  1043 void
  1044 X11_RestoreWindow(_THIS, SDL_Window * window)
  1045 {
  1046     SetWindowMaximized(_this, window, SDL_FALSE);
  1047     X11_ShowWindow(_this, window);
  1048     SetWindowActive(_this, window);
  1049 }
  1050 
  1051 /* This asks the Window Manager to handle fullscreen for us. Most don't do it right, though. */
  1052 static void
  1053 X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1054 {
  1055     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1056     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1057     Display *display = data->videodata->display;
  1058     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
  1059     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
  1060 
  1061     if (X11_IsWindowMapped(_this, window)) {
  1062         XEvent e;
  1063 
  1064         if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
  1065             /* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we
  1066                can be resized to the fullscreen resolution (or reset so we're not resizable again) */
  1067             XSizeHints *sizehints = X11_XAllocSizeHints();
  1068             long flags = 0;
  1069             X11_XGetWMNormalHints(display, data->xwindow, sizehints, &flags);
  1070             /* set the resize flags on */
  1071             if (fullscreen) {
  1072                 /* we are going fullscreen so turn the flags off */
  1073                 sizehints->flags &= ~(PMinSize | PMaxSize);
  1074             } else {
  1075                 /* Reset the min/max width height to make the window non-resizable again */
  1076                 sizehints->flags |= PMinSize | PMaxSize;
  1077                 sizehints->min_width = sizehints->max_width = window->windowed.w;
  1078                 sizehints->min_height = sizehints->max_height = window->windowed.h;
  1079             }
  1080             X11_XSetWMNormalHints(display, data->xwindow, sizehints);
  1081             X11_XFree(sizehints);
  1082         }
  1083 
  1084         SDL_zero(e);
  1085         e.xany.type = ClientMessage;
  1086         e.xclient.message_type = _NET_WM_STATE;
  1087         e.xclient.format = 32;
  1088         e.xclient.window = data->xwindow;
  1089         e.xclient.data.l[0] =
  1090             fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  1091         e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
  1092         e.xclient.data.l[3] = 0l;
  1093 
  1094         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1095                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1096     } else {
  1097         Uint32 flags;
  1098 
  1099         flags = window->flags;
  1100         if (fullscreen) {
  1101             flags |= SDL_WINDOW_FULLSCREEN;
  1102         } else {
  1103             flags &= ~SDL_WINDOW_FULLSCREEN;
  1104         }
  1105         X11_SetNetWMState(_this, data->xwindow, flags);
  1106     }
  1107 
  1108     if (data->visual->class == DirectColor) {
  1109         if ( fullscreen ) {
  1110             X11_XInstallColormap(display, data->colormap);
  1111         } else {
  1112             X11_XUninstallColormap(display, data->colormap);
  1113         }
  1114     }
  1115 
  1116     X11_XFlush(display);
  1117 }
  1118 
  1119 /* This handles fullscreen itself, outside the Window Manager. */
  1120 static void
  1121 X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1122 {
  1123     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1124     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1125     Visual *visual = data->visual;
  1126     Display *display = data->videodata->display;
  1127     const int screen = displaydata->screen;
  1128     Window root = RootWindow(display, screen);
  1129     const int def_vis = (visual == DefaultVisual(display, screen));
  1130     unsigned long xattrmask = 0;
  1131     XSetWindowAttributes xattr;
  1132     XEvent ev;
  1133     SDL_Rect rect;
  1134 
  1135     if ( data->fswindow ) {
  1136         return;  /* already fullscreen, I hope. */
  1137     }
  1138 
  1139     X11_GetDisplayBounds(_this, _display, &rect);
  1140 
  1141     SDL_zero(xattr);
  1142     xattr.override_redirect = True;
  1143     xattrmask |= CWOverrideRedirect;
  1144     xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
  1145     xattrmask |= CWBackPixel;
  1146     xattr.border_pixel = 0;
  1147     xattrmask |= CWBorderPixel;
  1148     xattr.colormap = data->colormap;
  1149     xattrmask |= CWColormap;
  1150 
  1151     data->fswindow = X11_XCreateWindow(display, root,
  1152                                    rect.x, rect.y, rect.w, rect.h, 0,
  1153                                    displaydata->depth, InputOutput,
  1154                                    visual, xattrmask, &xattr);
  1155 
  1156     X11_XSelectInput(display, data->fswindow, StructureNotifyMask);
  1157     X11_XSetWindowBackground(display, data->fswindow, 0);
  1158     X11_XInstallColormap(display, data->colormap);
  1159     X11_XClearWindow(display, data->fswindow);
  1160     X11_XMapRaised(display, data->fswindow);
  1161 
  1162     /* Make sure the fswindow is in view by warping mouse to the corner */
  1163     X11_XUngrabPointer(display, CurrentTime);
  1164     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1165 
  1166     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1167     X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
  1168     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1169 
  1170 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
  1171     if ( displaydata->use_vidmode ) {
  1172         X11_XF86VidModeLockModeSwitch(display, screen, True);
  1173     }
  1174 #endif
  1175 
  1176     SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
  1177 
  1178     /* Center actual window within our cover-the-screen window. */
  1179     X11_XReparentWindow(display, data->xwindow, data->fswindow,
  1180                     (rect.w - window->w) / 2, (rect.h - window->h) / 2);
  1181 
  1182     /* Move the mouse to the upper left to make sure it's on-screen */
  1183     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1184 
  1185     /* Center mouse in the fullscreen window. */
  1186     rect.x += (rect.w / 2);
  1187     rect.y += (rect.h / 2);
  1188     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1189 
  1190     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1191     X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1192     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1193 
  1194     SDL_UpdateWindowGrab(window);
  1195 }
  1196 
  1197 static void
  1198 X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1199 {
  1200     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1201     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1202     Display *display = data->videodata->display;
  1203     const int screen = displaydata->screen;
  1204     Window root = RootWindow(display, screen);
  1205     Window fswindow = data->fswindow;
  1206     XEvent ev;
  1207 
  1208     if (!data->fswindow) {
  1209         return;  /* already not fullscreen, I hope. */
  1210     }
  1211 
  1212     data->fswindow = None;
  1213 
  1214 #if SDL_VIDEO_DRIVER_X11_VIDMODE
  1215     if ( displaydata->use_vidmode ) {
  1216         X11_XF86VidModeLockModeSwitch(display, screen, False);
  1217     }
  1218 #endif
  1219 
  1220     SDL_UpdateWindowGrab(window);
  1221 
  1222     X11_XReparentWindow(display, data->xwindow, root, window->x, window->y);
  1223 
  1224     /* flush these events so they don't confuse normal event handling */
  1225     X11_XSync(display, False);
  1226     X11_XCheckIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1227     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1228 
  1229     SetWindowBordered(display, screen, data->xwindow,
  1230                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1231 
  1232     X11_XWithdrawWindow(display, fswindow, screen);
  1233 
  1234     /* Wait to be unmapped. */
  1235     X11_XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&fswindow);
  1236     X11_XDestroyWindow(display, fswindow);
  1237 }
  1238 
  1239 
  1240 void
  1241 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1242 {
  1243     /* !!! FIXME: SDL_Hint? */
  1244     SDL_bool legacy = SDL_FALSE;
  1245     const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
  1246     if (env) {
  1247         legacy = SDL_atoi(env);
  1248     } else {
  1249         SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1250         SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1251         if ( displaydata->use_vidmode ) {
  1252             legacy = SDL_TRUE;  /* the new stuff only works with XRandR. */
  1253         } else if ( !videodata->net_wm ) {
  1254             legacy = SDL_TRUE;  /* The window manager doesn't support it */
  1255         } else {
  1256             /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
  1257             /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
  1258             legacy = SDL_FALSE;  /* try the new way. */
  1259         }
  1260     }
  1261 
  1262     if (legacy) {
  1263         if (fullscreen) {
  1264             X11_BeginWindowFullscreenLegacy(_this, window, _display);
  1265         } else {
  1266             X11_EndWindowFullscreenLegacy(_this, window, _display);
  1267         }
  1268     } else {
  1269         X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
  1270     }
  1271 }
  1272 
  1273 
  1274 int
  1275 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1276 {
  1277     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1278     Display *display = data->videodata->display;
  1279     Visual *visual = data->visual;
  1280     Colormap colormap = data->colormap;
  1281     XColor *colorcells;
  1282     int ncolors;
  1283     int rmask, gmask, bmask;
  1284     int rshift, gshift, bshift;
  1285     int i;
  1286 
  1287     if (visual->class != DirectColor) {
  1288         return SDL_SetError("Window doesn't have DirectColor visual");
  1289     }
  1290 
  1291     ncolors = visual->map_entries;
  1292     colorcells = SDL_malloc(ncolors * sizeof(XColor));
  1293     if (!colorcells) {
  1294         return SDL_OutOfMemory();
  1295     }
  1296 
  1297     rshift = 0;
  1298     rmask = visual->red_mask;
  1299     while (0 == (rmask & 1)) {
  1300         rshift++;
  1301         rmask >>= 1;
  1302     }
  1303 
  1304     gshift = 0;
  1305     gmask = visual->green_mask;
  1306     while (0 == (gmask & 1)) {
  1307         gshift++;
  1308         gmask >>= 1;
  1309     }
  1310 
  1311     bshift = 0;
  1312     bmask = visual->blue_mask;
  1313     while (0 == (bmask & 1)) {
  1314         bshift++;
  1315         bmask >>= 1;
  1316     }
  1317 
  1318     /* build the color table pixel values */
  1319     for (i = 0; i < ncolors; i++) {
  1320         Uint32 rbits = (rmask * i) / (ncolors - 1);
  1321         Uint32 gbits = (gmask * i) / (ncolors - 1);
  1322         Uint32 bbits = (bmask * i) / (ncolors - 1);
  1323         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
  1324 
  1325         colorcells[i].pixel = pix;
  1326 
  1327         colorcells[i].red = ramp[(0 * 256) + i];
  1328         colorcells[i].green = ramp[(1 * 256) + i];
  1329         colorcells[i].blue = ramp[(2 * 256) + i];
  1330 
  1331         colorcells[i].flags = DoRed | DoGreen | DoBlue;
  1332     }
  1333 
  1334     X11_XStoreColors(display, colormap, colorcells, ncolors);
  1335     X11_XFlush(display);
  1336     SDL_free(colorcells);
  1337 
  1338     return 0;
  1339 }
  1340 
  1341 void
  1342 X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
  1343 {
  1344     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1345     Display *display = data->videodata->display;
  1346     SDL_bool oldstyle_fullscreen;
  1347     SDL_bool grab_keyboard;
  1348     const char *hint;
  1349 
  1350     /* ICCCM2.0-compliant window managers can handle fullscreen windows
  1351        If we're using XVidMode to change resolution we need to confine
  1352        the cursor so we don't pan around the virtual desktop.
  1353      */
  1354     oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
  1355 
  1356     if (oldstyle_fullscreen || grabbed) {
  1357         /* Try to grab the mouse */
  1358         for (;;) {
  1359             int result =
  1360                 X11_XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1361                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1362             if (result == GrabSuccess) {
  1363                 break;
  1364             }
  1365             SDL_Delay(50);
  1366         }
  1367 
  1368         /* Raise the window if we grab the mouse */
  1369         X11_XRaiseWindow(display, data->xwindow);
  1370 
  1371         /* Now grab the keyboard */
  1372         hint = SDL_GetHint(SDL_HINT_GRAB_KEYBOARD);
  1373         if (hint && SDL_atoi(hint)) {
  1374             grab_keyboard = SDL_TRUE;
  1375         } else {
  1376             /* We need to do this with the old style override_redirect
  1377                fullscreen window otherwise we won't get keyboard focus.
  1378             */
  1379             grab_keyboard = oldstyle_fullscreen;
  1380         }
  1381         if (grab_keyboard) {
  1382             X11_XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1383                           GrabModeAsync, CurrentTime);
  1384         }
  1385     } else {
  1386         X11_XUngrabPointer(display, CurrentTime);
  1387         X11_XUngrabKeyboard(display, CurrentTime);
  1388     }
  1389     X11_XSync(display, False);
  1390 }
  1391 
  1392 void
  1393 X11_DestroyWindow(_THIS, SDL_Window * window)
  1394 {
  1395     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1396 
  1397     if (data) {
  1398         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1399         Display *display = videodata->display;
  1400         int numwindows = videodata->numwindows;
  1401         SDL_WindowData **windowlist = videodata->windowlist;
  1402         int i;
  1403 
  1404         if (windowlist) {
  1405             for (i = 0; i < numwindows; ++i) {
  1406                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1407                     windowlist[i] = windowlist[numwindows - 1];
  1408                     windowlist[numwindows - 1] = NULL;
  1409                     videodata->numwindows--;
  1410                     break;
  1411                 }
  1412             }
  1413         }
  1414 #ifdef X_HAVE_UTF8_STRING
  1415         if (data->ic) {
  1416             X11_XDestroyIC(data->ic);
  1417         }
  1418 #endif
  1419         if (data->created) {
  1420             X11_XDestroyWindow(display, data->xwindow);
  1421             X11_XFlush(display);
  1422         }
  1423         SDL_free(data);
  1424     }
  1425     window->driverdata = NULL;
  1426 }
  1427 
  1428 SDL_bool
  1429 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1430 {
  1431     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1432     Display *display = data->videodata->display;
  1433 
  1434     if (info->version.major == SDL_MAJOR_VERSION &&
  1435         info->version.minor == SDL_MINOR_VERSION) {
  1436         info->subsystem = SDL_SYSWM_X11;
  1437         info->info.x11.display = display;
  1438         info->info.x11.window = data->xwindow;
  1439         return SDL_TRUE;
  1440     } else {
  1441         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1442                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1443         return SDL_FALSE;
  1444     }
  1445 }
  1446 
  1447 int
  1448 X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
  1449 {
  1450     return 0;  /* just succeed, the real work is done elsewhere. */
  1451 }
  1452 
  1453 #endif /* SDL_VIDEO_DRIVER_X11 */
  1454 
  1455 /* vi: set ts=4 sw=4 expandtab: */