src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 27 Sep 2012 11:39:31 -0700
changeset 6473 a5adb68266d0
parent 6470 ca793191b67a
child 6475 71d39944810b
permissions -rwxr-xr-x
Use the legacy fullscreen code if the window manager doesn't support the NetWM protocol.
     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     int x = 0;
  1000     int y = 0;
  1001 
  1002     if ( data->fswindow ) {
  1003         return;  /* already fullscreen, I hope. */
  1004     }
  1005 
  1006     /* Ungrab the input so that we can move the mouse around */
  1007     XUngrabPointer(display, CurrentTime);
  1008 
  1009     #if SDL_VIDEO_DRIVER_X11_XINERAMA
  1010     /* !!! FIXME: there was some Xinerama code in 1.2 here to set x,y to the origin of a specific screen. */
  1011     #endif
  1012 
  1013     SDL_zero(xattr);
  1014     xattr.override_redirect = True;
  1015     xattrmask |= CWOverrideRedirect;
  1016     xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
  1017     xattrmask |= CWBackPixel;
  1018     xattr.border_pixel = 0;
  1019     xattrmask |= CWBorderPixel;
  1020     xattr.colormap = data->colormap;
  1021     xattrmask |= CWColormap;
  1022 
  1023     data->fswindow = XCreateWindow(display, root, x, y, w, h, 0,
  1024                                    displaydata->depth, InputOutput,
  1025                                    visual, xattrmask, &xattr);
  1026 
  1027     XSelectInput(display, data->fswindow, StructureNotifyMask);
  1028 
  1029     XSetWindowBackground(display, data->fswindow, 0);
  1030     XClearWindow(display, data->fswindow);
  1031 
  1032     XMapRaised(display, data->fswindow);
  1033 
  1034     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1035     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
  1036     XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1037 
  1038 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
  1039     if ( displaydata->use_vidmode ) {
  1040         XF86VidModeLockModeSwitch(display, screen, True);
  1041     }
  1042 #endif
  1043 
  1044     XInstallColormap(display, data->colormap);
  1045 
  1046     SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
  1047     XFlush(display);
  1048     //XIfEvent(display, &ev, &isConfigureNotify, (XPointer)&data->xwindow);
  1049 
  1050     /* Center actual window within our cover-the-screen window. */
  1051     x += (w - window->w) / 2;
  1052     y += (h - window->h) / 2;
  1053     XReparentWindow(display, data->xwindow, data->fswindow, x, y);
  1054     XRaiseWindow(display, data->xwindow);
  1055 
  1056     /* Make sure the fswindow is in view by warping mouse to the corner */
  1057     XWarpPointer(display, None, root, 0, 0, 0, 0, 0, 0);
  1058     XFlush(display);
  1059 
  1060     /* Center mouse in the window. */
  1061     x += (window->w / 2);
  1062     y += (window->h / 2);
  1063     XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
  1064 
  1065     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1066     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1067 
  1068     /* Wait to be visible, or XSetInputFocus() triggers an X error. */
  1069     while (SDL_TRUE) {
  1070         XWindowAttributes attr;
  1071         XSync(display, False);
  1072         XGetWindowAttributes(display, data->xwindow, &attr);
  1073         if (attr.map_state == IsViewable)
  1074             break;
  1075     }
  1076 
  1077     XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
  1078     window->flags |= SDL_WINDOW_INPUT_FOCUS;
  1079     SDL_SetKeyboardFocus(data->window);
  1080 
  1081     X11_SetWindowGrab(_this, window);
  1082 
  1083     XSync(display, False);
  1084 }
  1085 
  1086 static void
  1087 X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1088 {
  1089     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1090     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1091     Display *display = data->videodata->display;
  1092     const int screen = displaydata->screen;
  1093     Window root = RootWindow(display, screen);
  1094     XEvent ev;
  1095 
  1096     if (!data->fswindow)
  1097         return;  /* already not fullscreen, I hope. */
  1098 
  1099     XReparentWindow(display, data->xwindow, root, window->x, window->y);
  1100 
  1101 #if SDL_VIDEO_DRIVER_X11_VIDMODE
  1102     if ( displaydata->use_vidmode ) {
  1103         XF86VidModeLockModeSwitch(display, screen, False);
  1104     }
  1105 #endif
  1106 
  1107     XUnmapWindow(display, data->fswindow);
  1108     /* Wait to be unmapped. */
  1109     XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1110     XDestroyWindow(display, data->fswindow);
  1111     data->fswindow = 0;
  1112 
  1113     /* catch these events so we know the window is back in business. */
  1114     XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1115     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1116 
  1117     XSync(display, True);   /* Flush spurious mode change events */
  1118 
  1119     X11_SetWindowGrab(_this, window);
  1120 
  1121     SetWindowBordered(display, screen, data->xwindow,
  1122                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1123 
  1124     XFlush(display);
  1125 }
  1126 
  1127 
  1128 void
  1129 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1130 {
  1131     /* !!! FIXME: SDL_Hint? */
  1132     SDL_bool legacy = SDL_FALSE;
  1133     const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
  1134     if (env) {
  1135         legacy = SDL_atoi(env);
  1136     } else {
  1137         SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1138         SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1139         if ( displaydata->use_vidmode ) {
  1140             legacy = SDL_TRUE;  /* the new stuff only works with XRandR. */
  1141         } else if ( !videodata->net_wm ) {
  1142             legacy = SDL_TRUE;  /* The window manager doesn't support it */
  1143         } else {
  1144             /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
  1145             /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
  1146             legacy = SDL_FALSE;  /* try the new way. */
  1147         }
  1148     }
  1149 
  1150     if (legacy) {
  1151         if (fullscreen) {
  1152             X11_BeginWindowFullscreenLegacy(_this, window, _display);
  1153         } else {
  1154             X11_EndWindowFullscreenLegacy(_this, window, _display);
  1155         }
  1156     } else {
  1157         X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
  1158     }
  1159 }
  1160 
  1161 
  1162 int
  1163 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1164 {
  1165     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1166     Display *display = data->videodata->display;
  1167     Visual *visual = data->visual;
  1168     Colormap colormap = data->colormap;
  1169     XColor *colorcells;
  1170     int ncolors;
  1171     int rmask, gmask, bmask;
  1172     int rshift, gshift, bshift;
  1173     int i;
  1174 
  1175     if (visual->class != DirectColor) {
  1176         SDL_SetError("Window doesn't have DirectColor visual");
  1177         return -1;
  1178     }
  1179 
  1180     ncolors = visual->map_entries;
  1181     colorcells = SDL_malloc(ncolors * sizeof(XColor));
  1182     if (!colorcells) {
  1183         SDL_OutOfMemory();
  1184         return -1;
  1185     }
  1186 
  1187     rshift = 0;
  1188     rmask = visual->red_mask;
  1189     while (0 == (rmask & 1)) {
  1190         rshift++;
  1191         rmask >>= 1;
  1192     }
  1193 
  1194     gshift = 0;
  1195     gmask = visual->green_mask;
  1196     while (0 == (gmask & 1)) {
  1197         gshift++;
  1198         gmask >>= 1;
  1199     }
  1200 
  1201     bshift = 0;
  1202     bmask = visual->blue_mask;
  1203     while (0 == (bmask & 1)) {
  1204         bshift++;
  1205         bmask >>= 1;
  1206     }
  1207 
  1208     /* build the color table pixel values */
  1209     for (i = 0; i < ncolors; i++) {
  1210         Uint32 rbits = (rmask * i) / (ncolors - 1);
  1211         Uint32 gbits = (gmask * i) / (ncolors - 1);
  1212         Uint32 bbits = (bmask * i) / (ncolors - 1);
  1213         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
  1214 
  1215         colorcells[i].pixel = pix;
  1216 
  1217         colorcells[i].red = ramp[(0 * 256) + i];
  1218         colorcells[i].green = ramp[(1 * 256) + i];
  1219         colorcells[i].blue = ramp[(2 * 256) + i];
  1220 
  1221         colorcells[i].flags = DoRed | DoGreen | DoBlue;
  1222     }
  1223 
  1224     XStoreColors(display, colormap, colorcells, ncolors);
  1225     XFlush(display);
  1226     SDL_free(colorcells);
  1227 
  1228     return 0;
  1229 }
  1230 
  1231 void
  1232 X11_SetWindowGrab(_THIS, SDL_Window * window)
  1233 {
  1234     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1235     Display *display = data->videodata->display;
  1236     SDL_bool oldstyle_fullscreen;
  1237 
  1238     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1239     oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
  1240 
  1241     if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
  1242         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1243         /* Try to grab the mouse */
  1244         for (;;) {
  1245             int result =
  1246                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1247                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1248             if (result == GrabSuccess) {
  1249                 break;
  1250             }
  1251             SDL_Delay(100);
  1252         }
  1253 
  1254         /* Raise the window if we grab the mouse */
  1255         XRaiseWindow(display, data->xwindow);
  1256 
  1257         /* Now grab the keyboard */
  1258         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1259                       GrabModeAsync, CurrentTime);
  1260     } else {
  1261         XUngrabPointer(display, CurrentTime);
  1262         XUngrabKeyboard(display, CurrentTime);
  1263     }
  1264 }
  1265 
  1266 void
  1267 X11_DestroyWindow(_THIS, SDL_Window * window)
  1268 {
  1269     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1270     window->driverdata = NULL;
  1271 
  1272     if (data) {
  1273         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1274         Display *display = videodata->display;
  1275         int numwindows = videodata->numwindows;
  1276         SDL_WindowData **windowlist = videodata->windowlist;
  1277         int i;
  1278 
  1279         if (windowlist) {
  1280             for (i = 0; i < numwindows; ++i) {
  1281                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1282                     windowlist[i] = windowlist[numwindows - 1];
  1283                     windowlist[numwindows - 1] = NULL;
  1284                     videodata->numwindows--;
  1285                     break;
  1286                 }
  1287             }
  1288         }
  1289 #ifdef X_HAVE_UTF8_STRING
  1290         if (data->ic) {
  1291             XDestroyIC(data->ic);
  1292         }
  1293 #endif
  1294         if (data->created) {
  1295             XDestroyWindow(display, data->xwindow);
  1296             XFlush(display);
  1297         }
  1298         SDL_free(data);
  1299     }
  1300 }
  1301 
  1302 SDL_bool
  1303 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1304 {
  1305     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1306     Display *display = data->videodata->display;
  1307 
  1308     if (info->version.major == SDL_MAJOR_VERSION &&
  1309         info->version.minor == SDL_MINOR_VERSION) {
  1310         info->subsystem = SDL_SYSWM_X11;
  1311         info->info.x11.display = display;
  1312         info->info.x11.window = data->xwindow;
  1313         return SDL_TRUE;
  1314     } else {
  1315         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1316                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1317         return SDL_FALSE;
  1318     }
  1319 }
  1320 
  1321 #endif /* SDL_VIDEO_DRIVER_X11 */
  1322 
  1323 /* vi: set ts=4 sw=4 expandtab: */