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