src/video/x11/SDL_x11window.c
author Sam Lantinga
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8707 d838991b3fb0
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

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