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