src/video/x11/SDL_x11window.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 09 Apr 2015 22:28:37 -0400
changeset 9541 cf8fab52e33b
parent 9479 daeaa68d7acf
child 9614 c9c61d66cfa0
permissions -rw-r--r--
Merged Alex Szpakowski's iOS-improvement branch to default.

Fixes Bugzilla #2798.
Fixes Bugzilla #2212.
Fixes Bugzilla #2826.
Fixes Bugzilla #2661.
Fixes Bugzilla #1885.
Fixes Bugzilla #1578.
Fixes Bugzilla #2751.

(whew!)

Notable changes, from Alex's notes:

- The SDL_WINDOW_ALLOW_HIGHDPI flag is now needed (along with SDL_GL_GetDrawableSize or SDL_GetRendererOutputSize) to use Retina / high DPI resolutions, bringing SDL’s Retina-related behavior on iOS in line with Mac OS X. Window dimensions and display modes are now in the “points” (non-high DPI) coordinate system rather than pixels, whereas SDL_GL_GetDrawableSize is in pixels.

- Reworked the custom extended launch screen code:
- It now hides after the first SDL_PumpEvents call rather than SDL_CreateWindow, and it fades out in a similar manner to the system launch screen behavior.
- It now mirrors the system launch screen behavior when deciding which image to display: it falls back to using the Launch Images dictionary in Info.plist if the iOS 8+ launch screen nib isn’t available, and if the Launch Images dictionary doesn’t exist it uses the old standard launch image names.
- The extended launch screen can now be disabled via the SDL_IPHONE_LAUNCHSCREEN define in SDL_config_iphoneos.h.

- Added support for SDL_HINT_ACCELEROMETER_AS_JOYSTICK.

- Added access to a window view's renderbuffer and framebuffer to syswm.

- Added OpenGL ES debug labels for the Renderbuffer and Framebuffer Objects created with SDL_GL_CreateContext.

- Added support for sRGB OpenGL ES contexts on iOS 7+.

- Updated OpenGL ES contexts to support native-resolution rendering (when SDL_WINDOW_ALLOW_HIGHDPI is enabled) on the iPhone 6 Plus, i.e. 1080x1920 rather than 1242x2208.

- Updated SDL_GL_CreateContext, SDL_GL_SwapWindow, SDL_GL_MakeCurrent, and SDL_GL_DeleteContext to be more robust.

- Updated SDL windows to display a UIView at all times, even when an OpenGL context is not active. This allows rotation, touch events, and other windowing-related events to work properly without an active OpenGL context. It also makes it easier to use SDL_GetWindowWMInfo after creating a SDL window.

- Updated the iOS-specific Objective-C code to use cleaner and more modern language features and APIs, including ARC instead of manual reference counting.

- Updated SDL_HINT_ORIENTATIONS to allow disabling custom orientations if the hint is set with no valid orientation names.

- Fixed several rotation and orientation bugs with windows and display modes, especially in iOS 8+.

- Fixed SDL_SetWindowFullscreen failing to update the status bar visibility on iOS 7+.

- Fixed the orientation of the offset applied to the window’s view when the onscreen keyboard is shown in iOS 8+.

- Fixed SDL_IsScreenKeyboardShown (patch by Phil Hassey.)

- Fixed several major memory leaks caused by missing autorelease pool blocks in the iOS-specific Objective-C code.

- Removed several dead code paths.

- The iOS 7 SDK (Xcode 5) or newer is now required to build SDL for iOS.
     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) / sizeof(long));
   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;
   660     Status status;
   661     const char *title = window->title ? window->title : "";
   662     char *title_locale = NULL;
   663 
   664 #ifdef X_HAVE_UTF8_STRING
   665     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   666 #endif
   667 
   668     title_locale = SDL_iconv_utf8_locale(title);
   669     if (!title_locale) {
   670         SDL_OutOfMemory();
   671         return;
   672     }
   673 
   674     status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
   675     SDL_free(title_locale);
   676     if (status) {
   677         X11_XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   678         X11_XFree(titleprop.value);
   679     }
   680 #ifdef X_HAVE_UTF8_STRING
   681     if (SDL_X11_HAVE_UTF8) {
   682         status = X11_Xutf8TextListToTextProperty(display, (char **) &title, 1,
   683                                             XUTF8StringStyle, &titleprop);
   684         if (status == Success) {
   685             X11_XSetTextProperty(display, data->xwindow, &titleprop,
   686                                  _NET_WM_NAME);
   687             X11_XFree(titleprop.value);
   688         }
   689     }
   690 #endif
   691 
   692     X11_XFlush(display);
   693 }
   694 
   695 void
   696 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   697 {
   698     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   699     Display *display = data->videodata->display;
   700     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   701 
   702     if (icon) {
   703         int propsize;
   704         long *propdata;
   705 
   706         /* Set the _NET_WM_ICON property */
   707         SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
   708         propsize = 2 + (icon->w * icon->h);
   709         propdata = SDL_malloc(propsize * sizeof(long));
   710         if (propdata) {
   711             int x, y;
   712             Uint32 *src;
   713             long *dst;
   714 
   715             propdata[0] = icon->w;
   716             propdata[1] = icon->h;
   717             dst = &propdata[2];
   718             for (y = 0; y < icon->h; ++y) {
   719                 src = (Uint32*)((Uint8*)icon->pixels + y * icon->pitch);
   720                 for (x = 0; x < icon->w; ++x) {
   721                     *dst++ = *src++;
   722                 }
   723             }
   724             X11_XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   725                             32, PropModeReplace, (unsigned char *) propdata,
   726                             propsize);
   727         }
   728         SDL_free(propdata);
   729     } else {
   730         X11_XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   731     }
   732     X11_XFlush(display);
   733 }
   734 
   735 void
   736 X11_SetWindowPosition(_THIS, SDL_Window * window)
   737 {
   738     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   739     Display *display = data->videodata->display;
   740 
   741     X11_XMoveWindow(display, data->xwindow, window->x, window->y);
   742     X11_XFlush(display);
   743 }
   744 
   745 void
   746 X11_SetWindowMinimumSize(_THIS, SDL_Window * window)
   747 {
   748     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   749     Display *display = data->videodata->display;
   750 
   751     if (window->flags & SDL_WINDOW_RESIZABLE) {
   752          XSizeHints *sizehints = X11_XAllocSizeHints();
   753          long userhints;
   754 
   755          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   756 
   757          sizehints->min_width = window->min_w;
   758          sizehints->min_height = window->min_h;
   759          sizehints->flags |= PMinSize;
   760 
   761          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   762 
   763          X11_XFree(sizehints);
   764 
   765         /* See comment in X11_SetWindowSize. */
   766         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   767         X11_XMoveWindow(display, data->xwindow, window->x, window->y);
   768         X11_XRaiseWindow(display, data->xwindow);
   769     }
   770 
   771     X11_XFlush(display);
   772 }
   773 
   774 void
   775 X11_SetWindowMaximumSize(_THIS, SDL_Window * window)
   776 {
   777     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   778     Display *display = data->videodata->display;
   779 
   780     if (window->flags & SDL_WINDOW_RESIZABLE) {
   781          XSizeHints *sizehints = X11_XAllocSizeHints();
   782          long userhints;
   783 
   784          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   785 
   786          sizehints->max_width = window->max_w;
   787          sizehints->max_height = window->max_h;
   788          sizehints->flags |= PMaxSize;
   789 
   790          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   791 
   792          X11_XFree(sizehints);
   793 
   794         /* See comment in X11_SetWindowSize. */
   795         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   796         X11_XMoveWindow(display, data->xwindow, window->x, window->y);
   797         X11_XRaiseWindow(display, data->xwindow);
   798     }
   799 
   800     X11_XFlush(display);
   801 }
   802 
   803 void
   804 X11_SetWindowSize(_THIS, SDL_Window * window)
   805 {
   806     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   807     Display *display = data->videodata->display;
   808 
   809     if (SDL_IsShapedWindow(window)) {
   810         X11_ResizeWindowShape(window);
   811     }
   812     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   813          /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the X11_XResizeWindow, thus
   814             we must set the size hints to adjust the window size. */
   815          XSizeHints *sizehints = X11_XAllocSizeHints();
   816          long userhints;
   817 
   818          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   819 
   820          sizehints->min_width = sizehints->max_width = window->w;
   821          sizehints->min_height = sizehints->max_height = window->h;
   822          sizehints->flags |= PMinSize | PMaxSize;
   823 
   824          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   825 
   826          X11_XFree(sizehints);
   827 
   828         /* From Pierre-Loup:
   829            WMs each have their little quirks with that.  When you change the
   830            size hints, they get a ConfigureNotify event with the
   831            WM_NORMAL_SIZE_HINTS Atom.  They all save the hints then, but they
   832            don't all resize the window right away to enforce the new hints.
   833 
   834            Some of them resize only after:
   835             - A user-initiated move or resize
   836             - A code-initiated move or resize
   837             - Hiding & showing window (Unmap & map)
   838 
   839            The following move & resize seems to help a lot of WMs that didn't
   840            properly update after the hints were changed. We don't do a
   841            hide/show, because there are supposedly subtle problems with doing so
   842            and transitioning from windowed to fullscreen in Unity.
   843          */
   844         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   845         X11_XMoveWindow(display, data->xwindow, window->x, window->y);
   846         X11_XRaiseWindow(display, data->xwindow);
   847     } else {
   848         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   849     }
   850 
   851     X11_XFlush(display);
   852 }
   853 
   854 void
   855 X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   856 {
   857     const SDL_bool focused = ((window->flags & SDL_WINDOW_INPUT_FOCUS) != 0);
   858     const SDL_bool visible = ((window->flags & SDL_WINDOW_HIDDEN) == 0);
   859     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   860     SDL_DisplayData *displaydata =
   861         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   862     Display *display = data->videodata->display;
   863     XEvent event;
   864 
   865     SetWindowBordered(display, displaydata->screen, data->xwindow, bordered);
   866     X11_XFlush(display);
   867     X11_XIfEvent(display, &event, &isConfigureNotify, (XPointer)&data->xwindow);
   868 
   869     if (visible) {
   870         XWindowAttributes attr;
   871         do {
   872             X11_XSync(display, False);
   873             X11_XGetWindowAttributes(display, data->xwindow, &attr);
   874         } while (attr.map_state != IsViewable);
   875 
   876         if (focused) {
   877             X11_XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
   878         }
   879     }
   880 
   881     /* make sure these don't make it to the real event queue if they fired here. */
   882     X11_XSync(display, False);
   883     X11_XCheckIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
   884     X11_XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   885 }
   886 
   887 void
   888 X11_ShowWindow(_THIS, SDL_Window * window)
   889 {
   890     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   891     Display *display = data->videodata->display;
   892     XEvent event;
   893 
   894     if (!X11_IsWindowMapped(_this, window)) {
   895         X11_XMapRaised(display, data->xwindow);
   896         /* Blocking wait for "MapNotify" event.
   897          * We use X11_XIfEvent because pXWindowEvent takes a mask rather than a type,
   898          * and XCheckTypedWindowEvent doesn't block */
   899         X11_XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   900         X11_XFlush(display);
   901     }
   902 }
   903 
   904 void
   905 X11_HideWindow(_THIS, SDL_Window * window)
   906 {
   907     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   908     SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   909     Display *display = data->videodata->display;
   910     XEvent event;
   911 
   912     if (X11_IsWindowMapped(_this, window)) {
   913         X11_XWithdrawWindow(display, data->xwindow, displaydata->screen);
   914         /* Blocking wait for "UnmapNotify" event */
   915         X11_XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
   916         X11_XFlush(display);
   917     }
   918 }
   919 
   920 static void
   921 SetWindowActive(_THIS, SDL_Window * window)
   922 {
   923     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   924     SDL_DisplayData *displaydata =
   925         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   926     Display *display = data->videodata->display;
   927     Atom _NET_ACTIVE_WINDOW = data->videodata->_NET_ACTIVE_WINDOW;
   928 
   929     if (X11_IsWindowMapped(_this, window)) {
   930         XEvent e;
   931 
   932         SDL_zero(e);
   933         e.xany.type = ClientMessage;
   934         e.xclient.message_type = _NET_ACTIVE_WINDOW;
   935         e.xclient.format = 32;
   936         e.xclient.window = data->xwindow;
   937         e.xclient.data.l[0] = 1;  /* source indication. 1 = application */
   938         e.xclient.data.l[1] = CurrentTime;
   939         e.xclient.data.l[2] = 0;
   940 
   941         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   942                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   943 
   944         X11_XFlush(display);
   945     }
   946 }
   947 
   948 void
   949 X11_RaiseWindow(_THIS, SDL_Window * window)
   950 {
   951     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   952     Display *display = data->videodata->display;
   953 
   954     X11_XRaiseWindow(display, data->xwindow);
   955     SetWindowActive(_this, window);
   956     X11_XFlush(display);
   957 }
   958 
   959 static void
   960 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   961 {
   962     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   963     SDL_DisplayData *displaydata =
   964         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   965     Display *display = data->videodata->display;
   966     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   967     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   968     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   969 
   970     if (maximized) {
   971         window->flags |= SDL_WINDOW_MAXIMIZED;
   972     } else {
   973         window->flags &= ~SDL_WINDOW_MAXIMIZED;
   974     }
   975 
   976     if (X11_IsWindowMapped(_this, window)) {
   977         XEvent e;
   978 
   979         SDL_zero(e);
   980         e.xany.type = ClientMessage;
   981         e.xclient.message_type = _NET_WM_STATE;
   982         e.xclient.format = 32;
   983         e.xclient.window = data->xwindow;
   984         e.xclient.data.l[0] =
   985             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   986         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
   987         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
   988         e.xclient.data.l[3] = 0l;
   989 
   990         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   991                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   992     } else {
   993         X11_SetNetWMState(_this, data->xwindow, window->flags);
   994     }
   995     X11_XFlush(display);
   996 }
   997 
   998 void
   999 X11_MaximizeWindow(_THIS, SDL_Window * window)
  1000 {
  1001     SetWindowMaximized(_this, window, SDL_TRUE);
  1002 }
  1003 
  1004 void
  1005 X11_MinimizeWindow(_THIS, SDL_Window * window)
  1006 {
  1007     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1008     SDL_DisplayData *displaydata =
  1009         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  1010     Display *display = data->videodata->display;
  1011 
  1012     X11_XIconifyWindow(display, data->xwindow, displaydata->screen);
  1013     X11_XFlush(display);
  1014 }
  1015 
  1016 void
  1017 X11_RestoreWindow(_THIS, SDL_Window * window)
  1018 {
  1019     SetWindowMaximized(_this, window, SDL_FALSE);
  1020     X11_ShowWindow(_this, window);
  1021     SetWindowActive(_this, window);
  1022 }
  1023 
  1024 /* This asks the Window Manager to handle fullscreen for us. Most don't do it right, though. */
  1025 static void
  1026 X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1027 {
  1028     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1029     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1030     Display *display = data->videodata->display;
  1031     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
  1032     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
  1033 
  1034     if (X11_IsWindowMapped(_this, window)) {
  1035         XEvent e;
  1036 
  1037         if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
  1038             /* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we
  1039                can be resized to the fullscreen resolution (or reset so we're not resizable again) */
  1040             XSizeHints *sizehints = X11_XAllocSizeHints();
  1041             long flags = 0;
  1042             X11_XGetWMNormalHints(display, data->xwindow, sizehints, &flags);
  1043             /* set the resize flags on */
  1044             if (fullscreen) {
  1045                 /* we are going fullscreen so turn the flags off */
  1046                 sizehints->flags &= ~(PMinSize | PMaxSize);
  1047             } else {
  1048                 /* Reset the min/max width height to make the window non-resizable again */
  1049                 sizehints->flags |= PMinSize | PMaxSize;
  1050                 sizehints->min_width = sizehints->max_width = window->windowed.w;
  1051                 sizehints->min_height = sizehints->max_height = window->windowed.h;
  1052             }
  1053             X11_XSetWMNormalHints(display, data->xwindow, sizehints);
  1054             X11_XFree(sizehints);
  1055         }
  1056 
  1057         SDL_zero(e);
  1058         e.xany.type = ClientMessage;
  1059         e.xclient.message_type = _NET_WM_STATE;
  1060         e.xclient.format = 32;
  1061         e.xclient.window = data->xwindow;
  1062         e.xclient.data.l[0] =
  1063             fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  1064         e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
  1065         e.xclient.data.l[3] = 0l;
  1066 
  1067         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1068                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1069     } else {
  1070         Uint32 flags;
  1071 
  1072         flags = window->flags;
  1073         if (fullscreen) {
  1074             flags |= SDL_WINDOW_FULLSCREEN;
  1075         } else {
  1076             flags &= ~SDL_WINDOW_FULLSCREEN;
  1077         }
  1078         X11_SetNetWMState(_this, data->xwindow, flags);
  1079     }
  1080 
  1081     if (data->visual->class == DirectColor) {
  1082         if ( fullscreen ) {
  1083             X11_XInstallColormap(display, data->colormap);
  1084         } else {
  1085             X11_XUninstallColormap(display, data->colormap);
  1086         }
  1087     }
  1088 
  1089     X11_XFlush(display);
  1090 }
  1091 
  1092 /* This handles fullscreen itself, outside the Window Manager. */
  1093 static void
  1094 X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1095 {
  1096     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1097     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1098     Visual *visual = data->visual;
  1099     Display *display = data->videodata->display;
  1100     const int screen = displaydata->screen;
  1101     Window root = RootWindow(display, screen);
  1102     const int def_vis = (visual == DefaultVisual(display, screen));
  1103     unsigned long xattrmask = 0;
  1104     XSetWindowAttributes xattr;
  1105     XEvent ev;
  1106     SDL_Rect rect;
  1107 
  1108     if ( data->fswindow ) {
  1109         return;  /* already fullscreen, I hope. */
  1110     }
  1111 
  1112     X11_GetDisplayBounds(_this, _display, &rect);
  1113 
  1114     SDL_zero(xattr);
  1115     xattr.override_redirect = True;
  1116     xattrmask |= CWOverrideRedirect;
  1117     xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
  1118     xattrmask |= CWBackPixel;
  1119     xattr.border_pixel = 0;
  1120     xattrmask |= CWBorderPixel;
  1121     xattr.colormap = data->colormap;
  1122     xattrmask |= CWColormap;
  1123 
  1124     data->fswindow = X11_XCreateWindow(display, root,
  1125                                    rect.x, rect.y, rect.w, rect.h, 0,
  1126                                    displaydata->depth, InputOutput,
  1127                                    visual, xattrmask, &xattr);
  1128 
  1129     X11_XSelectInput(display, data->fswindow, StructureNotifyMask);
  1130     X11_XSetWindowBackground(display, data->fswindow, 0);
  1131     X11_XInstallColormap(display, data->colormap);
  1132     X11_XClearWindow(display, data->fswindow);
  1133     X11_XMapRaised(display, data->fswindow);
  1134 
  1135     /* Make sure the fswindow is in view by warping mouse to the corner */
  1136     X11_XUngrabPointer(display, CurrentTime);
  1137     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1138 
  1139     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1140     X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
  1141     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1142 
  1143 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
  1144     if ( displaydata->use_vidmode ) {
  1145         X11_XF86VidModeLockModeSwitch(display, screen, True);
  1146     }
  1147 #endif
  1148 
  1149     SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
  1150 
  1151     /* Center actual window within our cover-the-screen window. */
  1152     X11_XReparentWindow(display, data->xwindow, data->fswindow,
  1153                     (rect.w - window->w) / 2, (rect.h - window->h) / 2);
  1154 
  1155     /* Move the mouse to the upper left to make sure it's on-screen */
  1156     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1157 
  1158     /* Center mouse in the fullscreen window. */
  1159     rect.x += (rect.w / 2);
  1160     rect.y += (rect.h / 2);
  1161     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1162 
  1163     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1164     X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1165     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1166 
  1167     SDL_UpdateWindowGrab(window);
  1168 }
  1169 
  1170 static void
  1171 X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1172 {
  1173     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1174     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1175     Display *display = data->videodata->display;
  1176     const int screen = displaydata->screen;
  1177     Window root = RootWindow(display, screen);
  1178     Window fswindow = data->fswindow;
  1179     XEvent ev;
  1180 
  1181     if (!data->fswindow) {
  1182         return;  /* already not fullscreen, I hope. */
  1183     }
  1184 
  1185     data->fswindow = None;
  1186 
  1187 #if SDL_VIDEO_DRIVER_X11_VIDMODE
  1188     if ( displaydata->use_vidmode ) {
  1189         X11_XF86VidModeLockModeSwitch(display, screen, False);
  1190     }
  1191 #endif
  1192 
  1193     SDL_UpdateWindowGrab(window);
  1194 
  1195     X11_XReparentWindow(display, data->xwindow, root, window->x, window->y);
  1196 
  1197     /* flush these events so they don't confuse normal event handling */
  1198     X11_XSync(display, False);
  1199     X11_XCheckIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1200     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1201 
  1202     SetWindowBordered(display, screen, data->xwindow,
  1203                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1204 
  1205     X11_XWithdrawWindow(display, fswindow, screen);
  1206 
  1207     /* Wait to be unmapped. */
  1208     X11_XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&fswindow);
  1209     X11_XDestroyWindow(display, fswindow);
  1210 }
  1211 
  1212 
  1213 void
  1214 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1215 {
  1216     /* !!! FIXME: SDL_Hint? */
  1217     SDL_bool legacy = SDL_FALSE;
  1218     const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
  1219     if (env) {
  1220         legacy = SDL_atoi(env);
  1221     } else {
  1222         SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1223         SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1224         if ( displaydata->use_vidmode ) {
  1225             legacy = SDL_TRUE;  /* the new stuff only works with XRandR. */
  1226         } else if ( !videodata->net_wm ) {
  1227             legacy = SDL_TRUE;  /* The window manager doesn't support it */
  1228         } else {
  1229             /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
  1230             /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
  1231             legacy = SDL_FALSE;  /* try the new way. */
  1232         }
  1233     }
  1234 
  1235     if (legacy) {
  1236         if (fullscreen) {
  1237             X11_BeginWindowFullscreenLegacy(_this, window, _display);
  1238         } else {
  1239             X11_EndWindowFullscreenLegacy(_this, window, _display);
  1240         }
  1241     } else {
  1242         X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
  1243     }
  1244 }
  1245 
  1246 
  1247 int
  1248 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1249 {
  1250     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1251     Display *display = data->videodata->display;
  1252     Visual *visual = data->visual;
  1253     Colormap colormap = data->colormap;
  1254     XColor *colorcells;
  1255     int ncolors;
  1256     int rmask, gmask, bmask;
  1257     int rshift, gshift, bshift;
  1258     int i;
  1259 
  1260     if (visual->class != DirectColor) {
  1261         return SDL_SetError("Window doesn't have DirectColor visual");
  1262     }
  1263 
  1264     ncolors = visual->map_entries;
  1265     colorcells = SDL_malloc(ncolors * sizeof(XColor));
  1266     if (!colorcells) {
  1267         return SDL_OutOfMemory();
  1268     }
  1269 
  1270     rshift = 0;
  1271     rmask = visual->red_mask;
  1272     while (0 == (rmask & 1)) {
  1273         rshift++;
  1274         rmask >>= 1;
  1275     }
  1276 
  1277     gshift = 0;
  1278     gmask = visual->green_mask;
  1279     while (0 == (gmask & 1)) {
  1280         gshift++;
  1281         gmask >>= 1;
  1282     }
  1283 
  1284     bshift = 0;
  1285     bmask = visual->blue_mask;
  1286     while (0 == (bmask & 1)) {
  1287         bshift++;
  1288         bmask >>= 1;
  1289     }
  1290 
  1291     /* build the color table pixel values */
  1292     for (i = 0; i < ncolors; i++) {
  1293         Uint32 rbits = (rmask * i) / (ncolors - 1);
  1294         Uint32 gbits = (gmask * i) / (ncolors - 1);
  1295         Uint32 bbits = (bmask * i) / (ncolors - 1);
  1296         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
  1297 
  1298         colorcells[i].pixel = pix;
  1299 
  1300         colorcells[i].red = ramp[(0 * 256) + i];
  1301         colorcells[i].green = ramp[(1 * 256) + i];
  1302         colorcells[i].blue = ramp[(2 * 256) + i];
  1303 
  1304         colorcells[i].flags = DoRed | DoGreen | DoBlue;
  1305     }
  1306 
  1307     X11_XStoreColors(display, colormap, colorcells, ncolors);
  1308     X11_XFlush(display);
  1309     SDL_free(colorcells);
  1310 
  1311     return 0;
  1312 }
  1313 
  1314 void
  1315 X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
  1316 {
  1317     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1318     Display *display = data->videodata->display;
  1319     SDL_bool oldstyle_fullscreen;
  1320     SDL_bool grab_keyboard;
  1321     const char *hint;
  1322 
  1323     /* ICCCM2.0-compliant window managers can handle fullscreen windows
  1324        If we're using XVidMode to change resolution we need to confine
  1325        the cursor so we don't pan around the virtual desktop.
  1326      */
  1327     oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
  1328 
  1329     if (oldstyle_fullscreen || grabbed) {
  1330         /* Try to grab the mouse */
  1331         for (;;) {
  1332             int result =
  1333                 X11_XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1334                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1335             if (result == GrabSuccess) {
  1336                 break;
  1337             }
  1338             SDL_Delay(50);
  1339         }
  1340 
  1341         /* Raise the window if we grab the mouse */
  1342         X11_XRaiseWindow(display, data->xwindow);
  1343 
  1344         /* Now grab the keyboard */
  1345         hint = SDL_GetHint(SDL_HINT_GRAB_KEYBOARD);
  1346         if (hint && SDL_atoi(hint)) {
  1347             grab_keyboard = SDL_TRUE;
  1348         } else {
  1349             /* We need to do this with the old style override_redirect
  1350                fullscreen window otherwise we won't get keyboard focus.
  1351             */
  1352             grab_keyboard = oldstyle_fullscreen;
  1353         }
  1354         if (grab_keyboard) {
  1355             X11_XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1356                           GrabModeAsync, CurrentTime);
  1357         }
  1358     } else {
  1359         X11_XUngrabPointer(display, CurrentTime);
  1360         X11_XUngrabKeyboard(display, CurrentTime);
  1361     }
  1362     X11_XSync(display, False);
  1363 }
  1364 
  1365 void
  1366 X11_DestroyWindow(_THIS, SDL_Window * window)
  1367 {
  1368     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1369 
  1370     if (data) {
  1371         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1372         Display *display = videodata->display;
  1373         int numwindows = videodata->numwindows;
  1374         SDL_WindowData **windowlist = videodata->windowlist;
  1375         int i;
  1376 
  1377         if (windowlist) {
  1378             for (i = 0; i < numwindows; ++i) {
  1379                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1380                     windowlist[i] = windowlist[numwindows - 1];
  1381                     windowlist[numwindows - 1] = NULL;
  1382                     videodata->numwindows--;
  1383                     break;
  1384                 }
  1385             }
  1386         }
  1387 #ifdef X_HAVE_UTF8_STRING
  1388         if (data->ic) {
  1389             X11_XDestroyIC(data->ic);
  1390         }
  1391 #endif
  1392         if (data->created) {
  1393             X11_XDestroyWindow(display, data->xwindow);
  1394             X11_XFlush(display);
  1395         }
  1396         SDL_free(data);
  1397     }
  1398     window->driverdata = NULL;
  1399 }
  1400 
  1401 SDL_bool
  1402 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1403 {
  1404     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1405     Display *display = data->videodata->display;
  1406 
  1407     if (info->version.major == SDL_MAJOR_VERSION &&
  1408         info->version.minor == SDL_MINOR_VERSION) {
  1409         info->subsystem = SDL_SYSWM_X11;
  1410         info->info.x11.display = display;
  1411         info->info.x11.window = data->xwindow;
  1412         return SDL_TRUE;
  1413     } else {
  1414         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1415                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1416         return SDL_FALSE;
  1417     }
  1418 }
  1419 
  1420 int
  1421 X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
  1422 {
  1423     return 0;  /* just succeed, the real work is done elsewhere. */
  1424 }
  1425 
  1426 #endif /* SDL_VIDEO_DRIVER_X11 */
  1427 
  1428 /* vi: set ts=4 sw=4 expandtab: */