src/video/x11/SDL_x11window.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 06 Apr 2015 00:10:54 -0400
changeset 9458 543298b36b28
parent 9117 236241f5d225
child 9460 1aa9826bb1bd
permissions -rw-r--r--
This function can be static.
     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             X11_XFree(propdata);
   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 
  1398     if (data) {
  1399         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1400         Display *display = videodata->display;
  1401         int numwindows = videodata->numwindows;
  1402         SDL_WindowData **windowlist = videodata->windowlist;
  1403         int i;
  1404 
  1405         if (windowlist) {
  1406             for (i = 0; i < numwindows; ++i) {
  1407                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1408                     windowlist[i] = windowlist[numwindows - 1];
  1409                     windowlist[numwindows - 1] = NULL;
  1410                     videodata->numwindows--;
  1411                     break;
  1412                 }
  1413             }
  1414         }
  1415 #ifdef X_HAVE_UTF8_STRING
  1416         if (data->ic) {
  1417             X11_XDestroyIC(data->ic);
  1418         }
  1419 #endif
  1420         if (data->created) {
  1421             X11_XDestroyWindow(display, data->xwindow);
  1422             X11_XFlush(display);
  1423         }
  1424         SDL_free(data);
  1425     }
  1426     window->driverdata = NULL;
  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 int
  1449 X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
  1450 {
  1451     return 0;  /* just succeed, the real work is done elsewhere. */
  1452 }
  1453 
  1454 #endif /* SDL_VIDEO_DRIVER_X11 */
  1455 
  1456 /* vi: set ts=4 sw=4 expandtab: */