src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 27 Sep 2012 13:52:57 -0700
changeset 6477 1e99ebaf0b14
parent 6475 71d39944810b
child 6479 388318faf0fb
permissions -rwxr-xr-x
When we're reparented we'll get both unmapnotify and mapnotify. Eat both so the unmap notify doesn't confuse the normal event processing.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_X11
    24 
    25 #include "../SDL_sysvideo.h"
    26 #include "../SDL_pixels_c.h"
    27 #include "../../events/SDL_keyboard_c.h"
    28 #include "../../events/SDL_mouse_c.h"
    29 
    30 #include "SDL_x11video.h"
    31 #include "SDL_x11mouse.h"
    32 #include "SDL_x11shape.h"
    33 #include "SDL_x11xinput2.h"
    34 
    35 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
    36 #include "SDL_x11opengles.h"
    37 #endif
    38 
    39 #include "SDL_timer.h"
    40 #include "SDL_syswm.h"
    41 #include "SDL_assert.h"
    42 
    43 #define _NET_WM_STATE_REMOVE    0l
    44 #define _NET_WM_STATE_ADD       1l
    45 #define _NET_WM_STATE_TOGGLE    2l
    46 
    47 static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
    48 {
    49     return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
    50 }
    51 static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
    52 {
    53     return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
    54 }
    55 static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
    56 {
    57     return ev->type == ConfigureNotify && ev->xunmap.window == *((Window*)win);
    58 }
    59 
    60 static SDL_bool
    61 X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
    62 {
    63     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    64     return (data->fswindow != 0);
    65 }
    66 
    67 static SDL_bool
    68 X11_IsWindowMapped(_THIS, SDL_Window * window)
    69 {
    70     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    71     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    72     XWindowAttributes attr;
    73 
    74     XGetWindowAttributes(videodata->display, data->xwindow, &attr);
    75     if (attr.map_state != IsUnmapped) {
    76         return SDL_TRUE;
    77     } else {
    78         return SDL_FALSE;
    79     }
    80 }
    81 
    82 static int
    83 X11_GetWMStateProperty(_THIS, SDL_Window * window, Atom atoms[3])
    84 {
    85     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    86     int count = 0;
    87 
    88     if (window->flags & SDL_WINDOW_FULLSCREEN) {
    89         atoms[count++] = data->_NET_WM_STATE_FULLSCREEN;
    90     }
    91     if (window->flags & SDL_WINDOW_MAXIMIZED) {
    92         atoms[count++] = data->_NET_WM_STATE_MAXIMIZED_VERT;
    93         atoms[count++] = data->_NET_WM_STATE_MAXIMIZED_HORZ;
    94     }
    95     return count;
    96 }
    97 
    98 static int
    99 SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
   100 {
   101     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   102     SDL_WindowData *data;
   103     int numwindows = videodata->numwindows;
   104     int windowlistlength = videodata->windowlistlength;
   105     SDL_WindowData **windowlist = videodata->windowlist;
   106 
   107     /* Allocate the window data */
   108     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   109     if (!data) {
   110         SDL_OutOfMemory();
   111         return -1;
   112     }
   113     data->window = window;
   114     data->xwindow = w;
   115 #ifdef X_HAVE_UTF8_STRING
   116     if (SDL_X11_HAVE_UTF8) {
   117         data->ic =
   118             pXCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w,
   119                        XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
   120                        XNResourceName, videodata->classname, XNResourceClass,
   121                        videodata->classname, NULL);
   122     }
   123 #endif
   124     data->created = created;
   125     data->videodata = videodata;
   126 
   127     /* Associate the data with the window */
   128 
   129     if (numwindows < windowlistlength) {
   130         windowlist[numwindows] = data;
   131         videodata->numwindows++;
   132     } else {
   133         windowlist =
   134             (SDL_WindowData **) SDL_realloc(windowlist,
   135                                             (numwindows +
   136                                              1) * sizeof(*windowlist));
   137         if (!windowlist) {
   138             SDL_OutOfMemory();
   139             SDL_free(data);
   140             return -1;
   141         }
   142         windowlist[numwindows] = data;
   143         videodata->numwindows++;
   144         videodata->windowlistlength++;
   145         videodata->windowlist = windowlist;
   146     }
   147 
   148     /* Fill in the SDL window with the window data */
   149     {
   150         XWindowAttributes attrib;
   151 
   152         XGetWindowAttributes(data->videodata->display, w, &attrib);
   153         window->x = attrib.x;
   154         window->y = attrib.y;
   155         window->w = attrib.width;
   156         window->h = attrib.height;
   157         if (attrib.map_state != IsUnmapped) {
   158             window->flags |= SDL_WINDOW_SHOWN;
   159         } else {
   160             window->flags &= ~SDL_WINDOW_SHOWN;
   161         }
   162         data->visual = attrib.visual;
   163         data->colormap = attrib.colormap;
   164     }
   165 
   166     {
   167         Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   168         Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   169         Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   170         Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   171         Atom actualType;
   172         int actualFormat;
   173         unsigned long i, numItems, bytesAfter;
   174         unsigned char *propertyValue = NULL;
   175         long maxLength = 1024;
   176 
   177         if (XGetWindowProperty(data->videodata->display, w, _NET_WM_STATE,
   178                                0l, maxLength, False, XA_ATOM, &actualType,
   179                                &actualFormat, &numItems, &bytesAfter,
   180                                &propertyValue) == Success) {
   181             Atom *atoms = (Atom *) propertyValue;
   182             int maximized = 0;
   183             int fullscreen = 0;
   184 
   185             for (i = 0; i < numItems; ++i) {
   186                 if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
   187                     maximized |= 1;
   188                 } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
   189                     maximized |= 2;
   190                 } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
   191                     fullscreen = 1;
   192                 }
   193             }
   194             if (maximized == 3) {
   195                 window->flags |= SDL_WINDOW_MAXIMIZED;
   196             }  else if (fullscreen == 1) {
   197                 window->flags |= SDL_WINDOW_FULLSCREEN;
   198             }
   199             XFree(propertyValue);
   200         }
   201     }
   202 
   203     {
   204         Window FocalWindow;
   205         int RevertTo=0;
   206         XGetInputFocus(data->videodata->display, &FocalWindow, &RevertTo);
   207         if (FocalWindow==w)
   208         {
   209             window->flags |= SDL_WINDOW_INPUT_FOCUS;
   210             SDL_SetKeyboardFocus(data->window);
   211         }
   212 
   213         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   214             /* Tell x11 to clip mouse */
   215         }
   216     }
   217 
   218     /* FIXME: How can I tell?
   219        {
   220        DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   221        if (style & WS_VISIBLE) {
   222        if (style & (WS_BORDER | WS_THICKFRAME)) {
   223        window->flags &= ~SDL_WINDOW_BORDERLESS;
   224        } else {
   225        window->flags |= SDL_WINDOW_BORDERLESS;
   226        }
   227        if (style & WS_THICKFRAME) {
   228        window->flags |= SDL_WINDOW_RESIZABLE;
   229        } else {
   230        window->flags &= ~SDL_WINDOW_RESIZABLE;
   231        }
   232        if (style & WS_MINIMIZE) {
   233        window->flags |= SDL_WINDOW_MINIMIZED;
   234        } else {
   235        window->flags &= ~SDL_WINDOW_MINIMIZED;
   236        }
   237        }
   238        if (GetFocus() == hwnd) {
   239        int index = data->videodata->keyboard;
   240        window->flags |= SDL_WINDOW_INPUT_FOCUS;
   241        SDL_SetKeyboardFocus(index, data->window);
   242 
   243        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   244        RECT rect;
   245        GetClientRect(hwnd, &rect);
   246        ClientToScreen(hwnd, (LPPOINT) & rect);
   247        ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   248        ClipCursor(&rect);
   249        }
   250        }
   251      */
   252 
   253     /* All done! */
   254     window->driverdata = data;
   255     return 0;
   256 }
   257 
   258 static void
   259 SetWindowBordered(Display *display, int screen, Window window, SDL_bool border)
   260 {
   261     /*
   262      * this code used to check for KWM_WIN_DECORATION, but KDE hasn't
   263      *  supported it for years and years. It now respects _MOTIF_WM_HINTS.
   264      *  Gnome is similar: just use the Motif atom.
   265      */
   266 
   267     Atom WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", True);
   268     if (WM_HINTS != None) {
   269         /* Hints used by Motif compliant window managers */
   270         struct
   271         {
   272             unsigned long flags;
   273             unsigned long functions;
   274             unsigned long decorations;
   275             long input_mode;
   276             unsigned long status;
   277         } MWMHints = {
   278             (1L << 1), 0, border ? 1 : 0, 0, 0
   279         };
   280 
   281         XChangeProperty(display, window, WM_HINTS, WM_HINTS, 32,
   282                         PropModeReplace, (unsigned char *) &MWMHints,
   283                         sizeof(MWMHints) / 4);
   284     } else {  /* set the transient hints instead, if necessary */
   285         XSetTransientForHint(display, window, RootWindow(display, screen));
   286     }
   287 }
   288 
   289 int
   290 X11_CreateWindow(_THIS, SDL_Window * window)
   291 {
   292     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   293     SDL_DisplayData *displaydata =
   294         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   295     Display *display = data->display;
   296     int screen = displaydata->screen;
   297     Visual *visual;
   298     int depth;
   299     XSetWindowAttributes xattr;
   300     Window w;
   301     XSizeHints *sizehints;
   302     XWMHints *wmhints;
   303     XClassHint *classhints;
   304     Atom _NET_WM_WINDOW_TYPE;
   305     Atom _NET_WM_WINDOW_TYPE_NORMAL;
   306     Atom _NET_WM_PID;
   307     int wmstate_count;
   308     Atom wmstate_atoms[3];
   309     Uint32 fevent = 0;
   310 
   311 #if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   312     if (window->flags & SDL_WINDOW_OPENGL) {
   313         XVisualInfo *vinfo;
   314 
   315 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2        
   316         if (_this->gl_config.use_egl == 1) {
   317             vinfo = X11_GLES_GetVisual(_this, display, screen);
   318         } else
   319 #endif
   320         {
   321 #if SDL_VIDEO_OPENGL_GLX
   322             vinfo = X11_GL_GetVisual(_this, display, screen);
   323 #endif
   324         }
   325         if (!vinfo) {
   326             return -1;
   327         }
   328         visual = vinfo->visual;
   329         depth = vinfo->depth;
   330         XFree(vinfo);
   331     } else
   332 #endif
   333     {
   334         visual = displaydata->visual;
   335         depth = displaydata->depth;
   336     }
   337 
   338     xattr.override_redirect = False;
   339     xattr.background_pixel = 0;
   340     xattr.border_pixel = 0;
   341 
   342     if (visual->class == DirectColor) {
   343         XColor *colorcells;
   344         int i;
   345         int ncolors;
   346         int rmax, gmax, bmax;
   347         int rmask, gmask, bmask;
   348         int rshift, gshift, bshift;
   349 
   350         xattr.colormap =
   351             XCreateColormap(display, RootWindow(display, screen),
   352                             visual, AllocAll);
   353 
   354         /* If we can't create a colormap, then we must die */
   355         if (!xattr.colormap) {
   356             SDL_SetError("Could not create writable colormap");
   357             return -1;
   358         }
   359 
   360         /* OK, we got a colormap, now fill it in as best as we can */
   361         colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   362         if (!colorcells) {
   363             SDL_OutOfMemory();
   364             return -1;
   365         }
   366         ncolors = visual->map_entries;
   367         rmax = 0xffff;
   368         gmax = 0xffff;
   369         bmax = 0xffff;
   370 
   371         rshift = 0;
   372         rmask = visual->red_mask;
   373         while (0 == (rmask & 1)) {
   374             rshift++;
   375             rmask >>= 1;
   376         }
   377 
   378         gshift = 0;
   379         gmask = visual->green_mask;
   380         while (0 == (gmask & 1)) {
   381             gshift++;
   382             gmask >>= 1;
   383         }
   384 
   385         bshift = 0;
   386         bmask = visual->blue_mask;
   387         while (0 == (bmask & 1)) {
   388             bshift++;
   389             bmask >>= 1;
   390         }
   391 
   392         /* build the color table pixel values */
   393         for (i = 0; i < ncolors; i++) {
   394             Uint32 red = (rmax * i) / (ncolors - 1);
   395             Uint32 green = (gmax * i) / (ncolors - 1);
   396             Uint32 blue = (bmax * i) / (ncolors - 1);
   397 
   398             Uint32 rbits = (rmask * i) / (ncolors - 1);
   399             Uint32 gbits = (gmask * i) / (ncolors - 1);
   400             Uint32 bbits = (bmask * i) / (ncolors - 1);
   401 
   402             Uint32 pix =
   403                 (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   404 
   405             colorcells[i].pixel = pix;
   406 
   407             colorcells[i].red = red;
   408             colorcells[i].green = green;
   409             colorcells[i].blue = blue;
   410 
   411             colorcells[i].flags = DoRed | DoGreen | DoBlue;
   412         }
   413 
   414         XStoreColors(display, xattr.colormap, colorcells, ncolors);
   415 
   416         SDL_free(colorcells);
   417     } else {
   418         xattr.colormap =
   419             XCreateColormap(display, RootWindow(display, screen),
   420                             visual, AllocNone);
   421     }
   422 
   423     w = XCreateWindow(display, RootWindow(display, screen),
   424                       window->x, window->y, window->w, window->h,
   425                       0, depth, InputOutput, visual,
   426                       (CWOverrideRedirect | CWBackPixel | CWBorderPixel |
   427                        CWColormap), &xattr);
   428     if (!w) {
   429         SDL_SetError("Couldn't create window");
   430         return -1;
   431     }
   432 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   433     if ((window->flags & SDL_WINDOW_OPENGL) && (_this->gl_config.use_egl == 1)) {
   434         if (!_this->gles_data) {
   435             XDestroyWindow(display, w);
   436             return -1;
   437         }
   438 
   439         /* Create the GLES window surface */
   440         _this->gles_data->egl_surface =
   441             _this->gles_data->eglCreateWindowSurface(_this->gles_data->
   442                                                  egl_display,
   443                                                  _this->gles_data->egl_config,
   444                                                  (NativeWindowType) w, NULL);
   445 
   446         if (_this->gles_data->egl_surface == EGL_NO_SURFACE) {
   447             SDL_SetError("Could not create GLES window surface");
   448             XDestroyWindow(display, w);
   449             return -1;
   450         }
   451     }
   452 #endif
   453 
   454     SetWindowBordered(display, screen, w,
   455                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
   456 
   457     sizehints = XAllocSizeHints();
   458     /* Setup the normal size hints */
   459     sizehints->flags = 0;
   460     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   461         sizehints->min_width = sizehints->max_width = window->w;
   462         sizehints->min_height = sizehints->max_height = window->h;
   463         sizehints->flags |= (PMaxSize | PMinSize);
   464     }
   465     sizehints->x = window->x;
   466     sizehints->y = window->y;
   467     sizehints->flags |= USPosition;
   468 
   469     /* Setup the input hints so we get keyboard input */
   470     wmhints = XAllocWMHints();
   471     wmhints->input = True;
   472     wmhints->flags = InputHint;
   473 
   474     /* Setup the class hints so we can get an icon (AfterStep) */
   475     classhints = XAllocClassHint();
   476     classhints->res_name = data->classname;
   477     classhints->res_class = data->classname;
   478 
   479     /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */
   480     XSetWMProperties(display, w, NULL, NULL, NULL, 0, sizehints, wmhints, classhints);
   481 
   482     XFree(sizehints);
   483     XFree(wmhints);
   484     XFree(classhints);
   485     /* Set the PID related to the window for the given hostname, if possible */
   486     if (data->pid > 0) {
   487         _NET_WM_PID = XInternAtom(display, "_NET_WM_PID", False);
   488         XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace,
   489                         (unsigned char *)&data->pid, 1);
   490     }
   491 
   492     /* Set the window manager state */
   493     wmstate_count = X11_GetWMStateProperty(_this, window, wmstate_atoms);
   494     if (wmstate_count > 0) {
   495         XChangeProperty(display, w, data->_NET_WM_STATE, XA_ATOM, 32,
   496                         PropModeReplace,
   497                         (unsigned char *)wmstate_atoms, wmstate_count);
   498     } else {
   499         XDeleteProperty(display, w, data->_NET_WM_STATE);
   500     }
   501 
   502     /* Let the window manager know we're a "normal" window */
   503     _NET_WM_WINDOW_TYPE = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
   504     _NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
   505     XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
   506                     PropModeReplace,
   507                     (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1);
   508 
   509     /* Allow the window to be deleted by the window manager */
   510     XSetWMProtocols(display, w, &data->WM_DELETE_WINDOW, 1);
   511 
   512     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   513         XDestroyWindow(display, w);
   514         return -1;
   515     }
   516 
   517 #ifdef X_HAVE_UTF8_STRING
   518     if (SDL_X11_HAVE_UTF8) {
   519         pXGetICValues(((SDL_WindowData *) window->driverdata)->ic,
   520                       XNFilterEvents, &fevent, NULL);
   521     }
   522 #endif
   523 
   524     X11_Xinput2SelectTouch(_this, window);
   525 
   526     XSelectInput(display, w,
   527                  (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   528                  ExposureMask | ButtonPressMask | ButtonReleaseMask |
   529                  PointerMotionMask | KeyPressMask | KeyReleaseMask |
   530                  PropertyChangeMask | StructureNotifyMask |
   531                  KeymapStateMask | fevent));
   532 
   533     XFlush(display);
   534 
   535     return 0;
   536 }
   537 
   538 int
   539 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   540 {
   541     Window w = (Window) data;
   542 
   543     window->title = X11_GetWindowTitle(_this, w);
   544 
   545     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   546         return -1;
   547     }
   548     return 0;
   549 }
   550 
   551 char *
   552 X11_GetWindowTitle(_THIS, Window xwindow)
   553 {
   554     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   555     Display *display = data->display;
   556     int status, real_format;
   557     Atom real_type;
   558     unsigned long items_read, items_left;
   559     unsigned char *propdata;
   560     char *title = NULL;
   561 
   562     status = XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
   563                 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
   564                 &items_read, &items_left, &propdata);
   565     if (status == Success && propdata) {
   566         title = SDL_strdup(SDL_static_cast(char*, propdata));
   567         XFree(propdata);
   568     } else {
   569         status = XGetWindowProperty(display, xwindow, XA_WM_NAME,
   570                     0L, 8192L, False, XA_STRING, &real_type, &real_format,
   571                     &items_read, &items_left, &propdata);
   572         if (status == Success && propdata) {
   573             title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
   574         } else {
   575             title = SDL_strdup("");
   576         }
   577     }
   578     return title;
   579 }
   580 
   581 void
   582 X11_SetWindowTitle(_THIS, SDL_Window * window)
   583 {
   584     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   585     Display *display = data->videodata->display;
   586     XTextProperty titleprop, iconprop;
   587     Status status;
   588     const char *title = window->title;
   589     const char *icon = NULL;
   590 
   591 #ifdef X_HAVE_UTF8_STRING
   592     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   593     Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME;
   594 #endif
   595 
   596     if (title != NULL) {
   597         char *title_locale = SDL_iconv_utf8_locale(title);
   598         if (!title_locale) {
   599             SDL_OutOfMemory();
   600             return;
   601         }
   602         status = XStringListToTextProperty(&title_locale, 1, &titleprop);
   603         SDL_free(title_locale);
   604         if (status) {
   605             XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   606             XFree(titleprop.value);
   607         }
   608 #ifdef X_HAVE_UTF8_STRING
   609         if (SDL_X11_HAVE_UTF8) {
   610             status =
   611                 Xutf8TextListToTextProperty(display, (char **) &title, 1,
   612                                             XUTF8StringStyle, &titleprop);
   613             if (status == Success) {
   614                 XSetTextProperty(display, data->xwindow, &titleprop,
   615                                  _NET_WM_NAME);
   616                 XFree(titleprop.value);
   617             }
   618         }
   619 #endif
   620     }
   621     if (icon != NULL) {
   622         char *icon_locale = SDL_iconv_utf8_locale(icon);
   623         if (!icon_locale) {
   624             SDL_OutOfMemory();
   625             return;
   626         }
   627         status = XStringListToTextProperty(&icon_locale, 1, &iconprop);
   628         SDL_free(icon_locale);
   629         if (status) {
   630             XSetTextProperty(display, data->xwindow, &iconprop,
   631                              XA_WM_ICON_NAME);
   632             XFree(iconprop.value);
   633         }
   634 #ifdef X_HAVE_UTF8_STRING
   635         if (SDL_X11_HAVE_UTF8) {
   636             status =
   637                 Xutf8TextListToTextProperty(display, (char **) &icon, 1,
   638                                             XUTF8StringStyle, &iconprop);
   639             if (status == Success) {
   640                 XSetTextProperty(display, data->xwindow, &iconprop,
   641                                  _NET_WM_ICON_NAME);
   642                 XFree(iconprop.value);
   643             }
   644         }
   645 #endif
   646     }
   647     XFlush(display);
   648 }
   649 
   650 void
   651 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   652 {
   653     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   654     Display *display = data->videodata->display;
   655     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   656 
   657     if (icon) {
   658         SDL_PixelFormat format;
   659         SDL_Surface *surface;
   660         int propsize;
   661         long *propdata;
   662 
   663         /* Convert the icon to ARGB for modern window managers */
   664         SDL_InitFormat(&format, SDL_PIXELFORMAT_ARGB8888);
   665         surface = SDL_ConvertSurface(icon, &format, 0);
   666         if (!surface) {
   667             return;
   668         }
   669 
   670         /* Set the _NET_WM_ICON property */
   671         propsize = 2 + (icon->w * icon->h);
   672         propdata = SDL_malloc(propsize * sizeof(long));
   673         if (propdata) {
   674             int x, y;
   675             Uint32 *src;
   676             long *dst;
   677 
   678             propdata[0] = icon->w;
   679             propdata[1] = icon->h;
   680             dst = &propdata[2];
   681             for (y = 0; y < icon->h; ++y) {
   682                 src = (Uint32*)((Uint8*)surface->pixels + y * surface->pitch);
   683                 for (x = 0; x < icon->w; ++x) {
   684                     *dst++ = *src++;
   685                 }
   686             }
   687             XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   688                             32, PropModeReplace, (unsigned char *) propdata,
   689                             propsize);
   690         }
   691         SDL_FreeSurface(surface);
   692     } else {
   693         XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   694     }
   695     XFlush(display);
   696 }
   697 
   698 void
   699 X11_SetWindowPosition(_THIS, SDL_Window * window)
   700 {
   701     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   702     Display *display = data->videodata->display;
   703 
   704     XMoveWindow(display, data->xwindow, window->x, window->y);
   705     XFlush(display);
   706 }
   707 
   708 void
   709 X11_SetWindowSize(_THIS, SDL_Window * window)
   710 {
   711     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   712     Display *display = data->videodata->display;
   713 
   714     if (SDL_IsShapedWindow(window))
   715         X11_ResizeWindowShape(window);
   716     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   717          /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the XResizeWindow, thus
   718             we must set the size hints to adjust the window size.*/
   719          XSizeHints *sizehints = XAllocSizeHints();
   720          long userhints;
   721 
   722          XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   723 
   724          sizehints->min_width = sizehints->max_width = window->w;
   725          sizehints->min_height = sizehints->max_height = window->h;
   726 
   727          XSetWMNormalHints(display, data->xwindow, sizehints);
   728 
   729          XFree(sizehints);
   730     } else
   731         XResizeWindow(display, data->xwindow, window->w, window->h);
   732     XFlush(display);
   733 }
   734 
   735 void
   736 X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   737 {
   738     const SDL_bool focused = ((window->flags & SDL_WINDOW_INPUT_FOCUS) != 0);
   739     const SDL_bool visible = ((window->flags & SDL_WINDOW_HIDDEN) == 0);
   740     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   741     SDL_DisplayData *displaydata =
   742         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   743     Display *display = data->videodata->display;
   744     XEvent event;
   745 
   746     SetWindowBordered(display, displaydata->screen, data->xwindow, bordered);
   747     XFlush(display);
   748     XIfEvent(display, &event, &isConfigureNotify, (XPointer)&data->xwindow);
   749 
   750     if (visible) {
   751         XWindowAttributes attr;
   752         do {
   753             XSync(display, False);
   754             XGetWindowAttributes(display, data->xwindow, &attr);
   755         } while (attr.map_state != IsViewable);
   756 
   757         if (focused) {
   758             XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
   759         }
   760     }
   761 
   762     /* make sure these don't make it to the real event queue if they fired here. */
   763     XSync(display, False);
   764     XCheckIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
   765     XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   766 }
   767 
   768 void
   769 X11_ShowWindow(_THIS, SDL_Window * window)
   770 {
   771     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   772     Display *display = data->videodata->display;
   773     XEvent event;
   774 
   775     XMapRaised(display, data->xwindow);
   776     /* Blocking wait for "MapNotify" event.
   777      * We use XIfEvent because XWindowEvent takes a mask rather than a type, 
   778      * and XCheckTypedWindowEvent doesn't block */
   779     XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   780     XFlush(display);
   781 }
   782 
   783 void
   784 X11_HideWindow(_THIS, SDL_Window * window)
   785 {
   786     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   787     Display *display = data->videodata->display;
   788     XEvent event;
   789 
   790     XUnmapWindow(display, data->xwindow);
   791     /* Blocking wait for "UnmapNotify" event */
   792     XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);    
   793     XFlush(display);
   794 }
   795 
   796 void
   797 X11_RaiseWindow(_THIS, SDL_Window * window)
   798 {
   799     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   800     Display *display = data->videodata->display;
   801 
   802     XRaiseWindow(display, data->xwindow);
   803     XFlush(display);
   804 }
   805 
   806 static void
   807 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   808 {
   809     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   810     SDL_DisplayData *displaydata =
   811         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   812     Display *display = data->videodata->display;
   813     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   814     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   815     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   816     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   817 
   818     if (X11_IsWindowMapped(_this, window)) {
   819         XEvent e;
   820 
   821         SDL_zero(e);
   822         e.xany.type = ClientMessage;
   823         e.xclient.message_type = _NET_WM_STATE;
   824         e.xclient.format = 32;
   825         e.xclient.window = data->xwindow;
   826         e.xclient.data.l[0] =
   827             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   828         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
   829         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
   830         e.xclient.data.l[3] = 0l;
   831 
   832         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   833                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   834     } else {
   835         int count = 0;
   836         Atom atoms[3];
   837 
   838         if (window->flags & SDL_WINDOW_FULLSCREEN) {
   839             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   840         }
   841         if (maximized) {
   842             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   843             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   844         }
   845         if (count > 0) {
   846             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
   847                             PropModeReplace, (unsigned char *)atoms, count);
   848         } else {
   849             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
   850         }
   851     }
   852     XFlush(display);
   853 }
   854 
   855 void
   856 X11_MaximizeWindow(_THIS, SDL_Window * window)
   857 {
   858     SetWindowMaximized(_this, window, SDL_TRUE);
   859 }
   860 
   861 void
   862 X11_MinimizeWindow(_THIS, SDL_Window * window)
   863 {
   864     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   865     SDL_DisplayData *displaydata =
   866         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   867     Display *display = data->videodata->display;
   868  
   869     XIconifyWindow(display, data->xwindow, displaydata->screen);
   870     XFlush(display);
   871 }
   872 
   873 void
   874 X11_RestoreWindow(_THIS, SDL_Window * window)
   875 {
   876     SetWindowMaximized(_this, window, SDL_FALSE);
   877     X11_ShowWindow(_this, window);
   878 }
   879 
   880 static Bool
   881 isActionAllowed(SDL_WindowData *data, Atom action)
   882 {
   883     Atom _NET_WM_ALLOWED_ACTIONS = data->videodata->_NET_WM_ALLOWED_ACTIONS;
   884     Atom type;
   885     Display *display = data->videodata->display;
   886     int form;
   887     unsigned long remain;
   888     unsigned long len, i;
   889     Atom *list;
   890     Bool ret = False;
   891     if (XGetWindowProperty(display, data->xwindow, _NET_WM_ALLOWED_ACTIONS, 0, 1024, False, XA_ATOM, &type, &form, &len, &remain, (unsigned char **)&list) == Success)
   892     {
   893         for (i=0; i<len; ++i)
   894         {
   895             if (list[i] == action) {
   896                 ret = True;
   897                 break;
   898             }
   899         }
   900         XFree(list);
   901     }
   902     return ret;
   903 }
   904 
   905 /* This asks the Window Manager to handle fullscreen for us. Most don't do it right, though. */
   906 static void
   907 X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
   908 {
   909     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   910     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
   911     Display *display = data->videodata->display;
   912     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   913     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   914     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   915     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   916 
   917     if (X11_IsWindowMapped(_this, window)) {
   918         XEvent e;
   919 
   920         if (isActionAllowed(data, data->videodata->_NET_WM_ACTION_FULLSCREEN) == False)
   921         {
   922             /* We aren't allowed to go into fullscreen mode... */
   923             if ((window->flags & SDL_WINDOW_RESIZABLE) == 0) {
   924                 /* ...and we aren't resizable. Compiz refuses fullscreen toggle in this case. */
   925                 XSizeHints *sizehints = XAllocSizeHints();
   926                 long flags = 0;
   927                 XGetWMNormalHints(display, data->xwindow, sizehints, &flags);
   928                 /* set the resize flags on */
   929                 sizehints->flags |= PMinSize | PMaxSize;
   930                 if (fullscreen) {
   931                     /* we are going fullscreen so turn the flags off */
   932                     sizehints->flags ^= (PMinSize | PMaxSize);
   933                 } else {
   934                     /* Reset the min/max width height to make the window non-resizable again */
   935                     sizehints->min_width = sizehints->max_width = window->w;
   936                     sizehints->min_height = sizehints->max_height = window->h;
   937                 }
   938                 XSetWMNormalHints(display, data->xwindow, sizehints);
   939                 XFree(sizehints);
   940             }
   941         }
   942         
   943         SDL_zero(e);
   944         e.xany.type = ClientMessage;
   945         e.xclient.message_type = _NET_WM_STATE;
   946         e.xclient.format = 32;
   947         e.xclient.window = data->xwindow;
   948         e.xclient.data.l[0] =
   949             fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   950         e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
   951         e.xclient.data.l[3] = 0l;
   952 
   953         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   954                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   955     } else {
   956         int count = 0;
   957         Atom atoms[3];
   958 
   959         if (fullscreen) {
   960             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   961         }
   962         if (window->flags & SDL_WINDOW_MAXIMIZED) {
   963             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   964             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   965         }
   966         if (count > 0) {
   967             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
   968                             PropModeReplace, (unsigned char *)atoms, count);
   969         } else {
   970             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
   971         }
   972     }
   973     XFlush(display);
   974 }
   975 
   976 static __inline__ int
   977 maxint(const int a, const int b)
   978 {
   979     return (a > b ? a : b);
   980 }
   981 
   982 
   983 /* This handles fullscreen itself, outside the Window Manager. */
   984 static void
   985 X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
   986 {
   987     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   988     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
   989     Visual *visual = data->visual;
   990     Display *display = data->videodata->display;
   991     const int screen = displaydata->screen;
   992     Window root = RootWindow(display, screen);
   993     const int def_vis = (visual == DefaultVisual(display, screen));
   994     const int w = maxint(window->w, _display->current_mode.w);
   995     const int h = maxint(window->h, _display->current_mode.h);
   996     unsigned long xattrmask = 0;
   997     XSetWindowAttributes xattr;
   998     XEvent ev;
   999     SDL_Rect rect;
  1000 
  1001     if ( data->fswindow ) {
  1002         return;  /* already fullscreen, I hope. */
  1003     }
  1004 
  1005     X11_GetDisplayBounds(_this, _display, &rect);
  1006 
  1007     /* Ungrab the input so that we can move the mouse around */
  1008     XUngrabPointer(display, CurrentTime);
  1009 
  1010     #if SDL_VIDEO_DRIVER_X11_XINERAMA
  1011     /* !!! FIXME: there was some Xinerama code in 1.2 here to set x,y to the origin of a specific screen. */
  1012     #endif
  1013 
  1014     SDL_zero(xattr);
  1015     xattr.override_redirect = True;
  1016     xattrmask |= CWOverrideRedirect;
  1017     xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
  1018     xattrmask |= CWBackPixel;
  1019     xattr.border_pixel = 0;
  1020     xattrmask |= CWBorderPixel;
  1021     xattr.colormap = data->colormap;
  1022     xattrmask |= CWColormap;
  1023 
  1024     data->fswindow = XCreateWindow(display, root,
  1025                                    rect.x, rect.y, rect.w, rect.h, 0,
  1026                                    displaydata->depth, InputOutput,
  1027                                    visual, xattrmask, &xattr);
  1028 
  1029     XSelectInput(display, data->fswindow, StructureNotifyMask);
  1030 
  1031     XSetWindowBackground(display, data->fswindow, 0);
  1032     XClearWindow(display, data->fswindow);
  1033 
  1034     XMapRaised(display, data->fswindow);
  1035 
  1036     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1037     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
  1038     XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1039 
  1040 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
  1041     if ( displaydata->use_vidmode ) {
  1042         XF86VidModeLockModeSwitch(display, screen, True);
  1043     }
  1044 #endif
  1045 
  1046     XInstallColormap(display, data->colormap);
  1047 
  1048     SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
  1049     XFlush(display);
  1050     //XIfEvent(display, &ev, &isConfigureNotify, (XPointer)&data->xwindow);
  1051 
  1052     /* Center actual window within our cover-the-screen window. */
  1053     rect.x += (rect.w - window->w) / 2;
  1054     rect.y += (rect.h - window->h) / 2;
  1055     XReparentWindow(display, data->xwindow, data->fswindow, rect.x, rect.y);
  1056     XRaiseWindow(display, data->xwindow);
  1057 
  1058     /* Make sure the fswindow is in view by warping mouse to the corner */
  1059     XWarpPointer(display, None, root, 0, 0, 0, 0, 0, 0);
  1060     XFlush(display);
  1061 
  1062     /* Center mouse in the window. */
  1063     rect.x += (window->w / 2);
  1064     rect.y += (window->h / 2);
  1065     XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1066 
  1067     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1068     XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1069     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1070 
  1071     /* Wait to be visible, or XSetInputFocus() triggers an X error. */
  1072     while (SDL_TRUE) {
  1073         XWindowAttributes attr;
  1074         XSync(display, False);
  1075         XGetWindowAttributes(display, data->xwindow, &attr);
  1076         if (attr.map_state == IsViewable)
  1077             break;
  1078     }
  1079 
  1080     XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
  1081     window->flags |= SDL_WINDOW_INPUT_FOCUS;
  1082     SDL_SetKeyboardFocus(data->window);
  1083 
  1084     X11_SetWindowGrab(_this, window);
  1085 
  1086     XSync(display, False);
  1087 }
  1088 
  1089 static void
  1090 X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1091 {
  1092     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1093     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1094     Display *display = data->videodata->display;
  1095     const int screen = displaydata->screen;
  1096     Window root = RootWindow(display, screen);
  1097     XEvent ev;
  1098 
  1099     if (!data->fswindow)
  1100         return;  /* already not fullscreen, I hope. */
  1101 
  1102     XReparentWindow(display, data->xwindow, root, window->x, window->y);
  1103 
  1104 #if SDL_VIDEO_DRIVER_X11_VIDMODE
  1105     if ( displaydata->use_vidmode ) {
  1106         XF86VidModeLockModeSwitch(display, screen, False);
  1107     }
  1108 #endif
  1109 
  1110     XUnmapWindow(display, data->fswindow);
  1111     /* Wait to be unmapped. */
  1112     XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1113     XDestroyWindow(display, data->fswindow);
  1114     data->fswindow = 0;
  1115 
  1116     /* catch these events so we know the window is back in business. */
  1117     XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1118     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1119 
  1120     XSync(display, True);   /* Flush spurious mode change events */
  1121 
  1122     X11_SetWindowGrab(_this, window);
  1123 
  1124     SetWindowBordered(display, screen, data->xwindow,
  1125                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1126 
  1127     XFlush(display);
  1128 }
  1129 
  1130 
  1131 void
  1132 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1133 {
  1134     /* !!! FIXME: SDL_Hint? */
  1135     SDL_bool legacy = SDL_FALSE;
  1136     const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
  1137     if (env) {
  1138         legacy = SDL_atoi(env);
  1139     } else {
  1140         SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1141         SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1142         if ( displaydata->use_vidmode ) {
  1143             legacy = SDL_TRUE;  /* the new stuff only works with XRandR. */
  1144         } else if ( !videodata->net_wm ) {
  1145             legacy = SDL_TRUE;  /* The window manager doesn't support it */
  1146         } else {
  1147             /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
  1148             /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
  1149             legacy = SDL_FALSE;  /* try the new way. */
  1150         }
  1151     }
  1152 
  1153     if (legacy) {
  1154         if (fullscreen) {
  1155             X11_BeginWindowFullscreenLegacy(_this, window, _display);
  1156         } else {
  1157             X11_EndWindowFullscreenLegacy(_this, window, _display);
  1158         }
  1159     } else {
  1160         X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
  1161     }
  1162 }
  1163 
  1164 
  1165 int
  1166 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1167 {
  1168     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1169     Display *display = data->videodata->display;
  1170     Visual *visual = data->visual;
  1171     Colormap colormap = data->colormap;
  1172     XColor *colorcells;
  1173     int ncolors;
  1174     int rmask, gmask, bmask;
  1175     int rshift, gshift, bshift;
  1176     int i;
  1177 
  1178     if (visual->class != DirectColor) {
  1179         SDL_SetError("Window doesn't have DirectColor visual");
  1180         return -1;
  1181     }
  1182 
  1183     ncolors = visual->map_entries;
  1184     colorcells = SDL_malloc(ncolors * sizeof(XColor));
  1185     if (!colorcells) {
  1186         SDL_OutOfMemory();
  1187         return -1;
  1188     }
  1189 
  1190     rshift = 0;
  1191     rmask = visual->red_mask;
  1192     while (0 == (rmask & 1)) {
  1193         rshift++;
  1194         rmask >>= 1;
  1195     }
  1196 
  1197     gshift = 0;
  1198     gmask = visual->green_mask;
  1199     while (0 == (gmask & 1)) {
  1200         gshift++;
  1201         gmask >>= 1;
  1202     }
  1203 
  1204     bshift = 0;
  1205     bmask = visual->blue_mask;
  1206     while (0 == (bmask & 1)) {
  1207         bshift++;
  1208         bmask >>= 1;
  1209     }
  1210 
  1211     /* build the color table pixel values */
  1212     for (i = 0; i < ncolors; i++) {
  1213         Uint32 rbits = (rmask * i) / (ncolors - 1);
  1214         Uint32 gbits = (gmask * i) / (ncolors - 1);
  1215         Uint32 bbits = (bmask * i) / (ncolors - 1);
  1216         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
  1217 
  1218         colorcells[i].pixel = pix;
  1219 
  1220         colorcells[i].red = ramp[(0 * 256) + i];
  1221         colorcells[i].green = ramp[(1 * 256) + i];
  1222         colorcells[i].blue = ramp[(2 * 256) + i];
  1223 
  1224         colorcells[i].flags = DoRed | DoGreen | DoBlue;
  1225     }
  1226 
  1227     XStoreColors(display, colormap, colorcells, ncolors);
  1228     XFlush(display);
  1229     SDL_free(colorcells);
  1230 
  1231     return 0;
  1232 }
  1233 
  1234 void
  1235 X11_SetWindowGrab(_THIS, SDL_Window * window)
  1236 {
  1237     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1238     Display *display = data->videodata->display;
  1239     SDL_bool oldstyle_fullscreen;
  1240 
  1241     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1242     oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
  1243 
  1244     if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
  1245         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1246         /* Try to grab the mouse */
  1247         for (;;) {
  1248             int result =
  1249                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1250                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1251             if (result == GrabSuccess) {
  1252                 break;
  1253             }
  1254             SDL_Delay(100);
  1255         }
  1256 
  1257         /* Raise the window if we grab the mouse */
  1258         XRaiseWindow(display, data->xwindow);
  1259 
  1260         /* Now grab the keyboard */
  1261         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1262                       GrabModeAsync, CurrentTime);
  1263     } else {
  1264         XUngrabPointer(display, CurrentTime);
  1265         XUngrabKeyboard(display, CurrentTime);
  1266     }
  1267 }
  1268 
  1269 void
  1270 X11_DestroyWindow(_THIS, SDL_Window * window)
  1271 {
  1272     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1273     window->driverdata = NULL;
  1274 
  1275     if (data) {
  1276         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1277         Display *display = videodata->display;
  1278         int numwindows = videodata->numwindows;
  1279         SDL_WindowData **windowlist = videodata->windowlist;
  1280         int i;
  1281 
  1282         if (windowlist) {
  1283             for (i = 0; i < numwindows; ++i) {
  1284                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1285                     windowlist[i] = windowlist[numwindows - 1];
  1286                     windowlist[numwindows - 1] = NULL;
  1287                     videodata->numwindows--;
  1288                     break;
  1289                 }
  1290             }
  1291         }
  1292 #ifdef X_HAVE_UTF8_STRING
  1293         if (data->ic) {
  1294             XDestroyIC(data->ic);
  1295         }
  1296 #endif
  1297         if (data->created) {
  1298             XDestroyWindow(display, data->xwindow);
  1299             XFlush(display);
  1300         }
  1301         SDL_free(data);
  1302     }
  1303 }
  1304 
  1305 SDL_bool
  1306 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1307 {
  1308     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1309     Display *display = data->videodata->display;
  1310 
  1311     if (info->version.major == SDL_MAJOR_VERSION &&
  1312         info->version.minor == SDL_MINOR_VERSION) {
  1313         info->subsystem = SDL_SYSWM_X11;
  1314         info->info.x11.display = display;
  1315         info->info.x11.window = data->xwindow;
  1316         return SDL_TRUE;
  1317     } else {
  1318         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1319                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1320         return SDL_FALSE;
  1321     }
  1322 }
  1323 
  1324 #endif /* SDL_VIDEO_DRIVER_X11 */
  1325 
  1326 /* vi: set ts=4 sw=4 expandtab: */