src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 11 Oct 2012 14:43:13 -0700
changeset 6575 833a983f218e
parent 6568 1a6b0ae81937
child 6638 3d221da309d3
permissions -rw-r--r--
Only install/uninstall the colormap if we've created a DirectColor colormap.
     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_free(propdata);
   722         SDL_FreeSurface(surface);
   723     } else {
   724         XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   725     }
   726     XFlush(display);
   727 }
   728 
   729 void
   730 X11_SetWindowPosition(_THIS, SDL_Window * window)
   731 {
   732     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   733     Display *display = data->videodata->display;
   734 
   735     XMoveWindow(display, data->xwindow, window->x, window->y);
   736     XFlush(display);
   737 }
   738 
   739 void
   740 X11_SetWindowSize(_THIS, SDL_Window * window)
   741 {
   742     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   743     Display *display = data->videodata->display;
   744 
   745     if (SDL_IsShapedWindow(window)) {
   746         X11_ResizeWindowShape(window);
   747     }
   748     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   749          /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the XResizeWindow, thus
   750             we must set the size hints to adjust the window size.*/
   751          XSizeHints *sizehints = XAllocSizeHints();
   752          long userhints;
   753 
   754          XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   755 
   756          sizehints->min_width = sizehints->max_width = window->w;
   757          sizehints->min_height = sizehints->max_height = window->h;
   758 
   759          XSetWMNormalHints(display, data->xwindow, sizehints);
   760 
   761          XFree(sizehints);
   762 
   763         /* From Pierre-Loup:
   764            For the windowed resize problem; WMs each have their little quirks with
   765            that.  When you change the size hints, they get a ConfigureNotify event
   766            with the WM_NORMAL_SIZE_HINTS Atom.  They all save the hints then, but
   767            they don't all resize the window right away to enforce the new hints.
   768            Those who do properly do it are:
   769           
   770              - XFWM
   771              - metacity
   772              - KWin
   773 
   774            These are great.  Now, others are more problematic as you could observe
   775            first hand.  Compiz/Unity only falls into the code that does it on select
   776            actions, such as window move, raise, map, etc.
   777 
   778            WindowMaker is even more difficult and will _only_ do it on map.
   779 
   780            Awesome only does it on user-initiated moves as far as I can tell.
   781           
   782            Your raise workaround only fixes compiz/Unity.  With that all "modern"
   783            window managers are covered.  Trying to Hide/Show on windowed resize
   784            (UnMap/Map) fixes both Unity and WindowMaker, but introduces subtle
   785            problems with transitioning from Windowed to Fullscreen on Unity.  Since
   786            some window moves happen after the transitions to fullscreen, that forces
   787            SDL to fall from windowed to fullscreen repeatedly and it sometimes leaves
   788            itself in a state where the fullscreen window is slightly offset by what
   789            used to be the window decoration titlebar.
   790         */
   791         XRaiseWindow(display, data->xwindow);
   792     } else {
   793         XResizeWindow(display, data->xwindow, window->w, window->h);
   794     }
   795     XFlush(display);
   796 }
   797 
   798 void
   799 X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   800 {
   801     const SDL_bool focused = ((window->flags & SDL_WINDOW_INPUT_FOCUS) != 0);
   802     const SDL_bool visible = ((window->flags & SDL_WINDOW_HIDDEN) == 0);
   803     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   804     SDL_DisplayData *displaydata =
   805         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   806     Display *display = data->videodata->display;
   807     XEvent event;
   808 
   809     SetWindowBordered(display, displaydata->screen, data->xwindow, bordered);
   810     XFlush(display);
   811     XIfEvent(display, &event, &isConfigureNotify, (XPointer)&data->xwindow);
   812 
   813     if (visible) {
   814         XWindowAttributes attr;
   815         do {
   816             XSync(display, False);
   817             XGetWindowAttributes(display, data->xwindow, &attr);
   818         } while (attr.map_state != IsViewable);
   819 
   820         if (focused) {
   821             XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
   822         }
   823     }
   824 
   825     /* make sure these don't make it to the real event queue if they fired here. */
   826     XSync(display, False);
   827     XCheckIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
   828     XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   829 }
   830 
   831 void
   832 X11_ShowWindow(_THIS, SDL_Window * window)
   833 {
   834     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   835     Display *display = data->videodata->display;
   836     XEvent event;
   837 
   838     if (!X11_IsWindowMapped(_this, window)) {
   839         XMapRaised(display, data->xwindow);
   840         /* Blocking wait for "MapNotify" event.
   841          * We use XIfEvent because XWindowEvent takes a mask rather than a type, 
   842          * and XCheckTypedWindowEvent doesn't block */
   843         XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   844         XFlush(display);
   845     }
   846 }
   847 
   848 void
   849 X11_HideWindow(_THIS, SDL_Window * window)
   850 {
   851     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   852     Display *display = data->videodata->display;
   853     XEvent event;
   854 
   855     if (X11_IsWindowMapped(_this, window)) {
   856         XUnmapWindow(display, data->xwindow);
   857         /* Blocking wait for "UnmapNotify" event */
   858         XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);    
   859         XFlush(display);
   860     }
   861 }
   862 
   863 void
   864 X11_RaiseWindow(_THIS, SDL_Window * window)
   865 {
   866     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   867     Display *display = data->videodata->display;
   868 
   869     XRaiseWindow(display, data->xwindow);
   870     XFlush(display);
   871 }
   872 
   873 static void
   874 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   875 {
   876     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   877     SDL_DisplayData *displaydata =
   878         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   879     Display *display = data->videodata->display;
   880     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   881     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   882     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   883 
   884     if (X11_IsWindowMapped(_this, window)) {
   885         XEvent e;
   886 
   887         SDL_zero(e);
   888         e.xany.type = ClientMessage;
   889         e.xclient.message_type = _NET_WM_STATE;
   890         e.xclient.format = 32;
   891         e.xclient.window = data->xwindow;
   892         e.xclient.data.l[0] =
   893             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   894         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
   895         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
   896         e.xclient.data.l[3] = 0l;
   897 
   898         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   899                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   900     } else {
   901         Uint32 flags;
   902 
   903         flags = window->flags;
   904         if (maximized) {
   905             flags |= SDL_WINDOW_MAXIMIZED;
   906         } else {
   907             flags &= ~SDL_WINDOW_MAXIMIZED;
   908         }
   909         X11_SetNetWMState(_this, data->xwindow, flags);
   910     }
   911     XFlush(display);
   912 }
   913 
   914 void
   915 X11_MaximizeWindow(_THIS, SDL_Window * window)
   916 {
   917     SetWindowMaximized(_this, window, SDL_TRUE);
   918 }
   919 
   920 void
   921 X11_MinimizeWindow(_THIS, SDL_Window * window)
   922 {
   923     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   924     SDL_DisplayData *displaydata =
   925         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   926     Display *display = data->videodata->display;
   927  
   928     XIconifyWindow(display, data->xwindow, displaydata->screen);
   929     XFlush(display);
   930 }
   931 
   932 void
   933 X11_RestoreWindow(_THIS, SDL_Window * window)
   934 {
   935     SetWindowMaximized(_this, window, SDL_FALSE);
   936     X11_ShowWindow(_this, window);
   937 }
   938 
   939 /* This asks the Window Manager to handle fullscreen for us. Most don't do it right, though. */
   940 static void
   941 X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
   942 {
   943     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   944     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
   945     Display *display = data->videodata->display;
   946     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   947     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   948 
   949     if (X11_IsWindowMapped(_this, window)) {
   950         XEvent e;
   951 
   952         if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   953             /* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we
   954                can be resized to the fullscreen resolution (or reset so we're not resizable again) */
   955             XSizeHints *sizehints = XAllocSizeHints();
   956             long flags = 0;
   957             XGetWMNormalHints(display, data->xwindow, sizehints, &flags);
   958             /* set the resize flags on */
   959             if (fullscreen) {
   960                 /* we are going fullscreen so turn the flags off */
   961                 sizehints->flags &= ~(PMinSize | PMaxSize);
   962             } else {
   963                 /* Reset the min/max width height to make the window non-resizable again */
   964                 sizehints->flags |= PMinSize | PMaxSize;
   965                 sizehints->min_width = sizehints->max_width = window->windowed.w;
   966                 sizehints->min_height = sizehints->max_height = window->windowed.h;
   967             }
   968             XSetWMNormalHints(display, data->xwindow, sizehints);
   969             XFree(sizehints);
   970         }
   971 
   972         SDL_zero(e);
   973         e.xany.type = ClientMessage;
   974         e.xclient.message_type = _NET_WM_STATE;
   975         e.xclient.format = 32;
   976         e.xclient.window = data->xwindow;
   977         e.xclient.data.l[0] =
   978             fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   979         e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
   980         e.xclient.data.l[3] = 0l;
   981 
   982         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   983                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   984     } else {
   985         Uint32 flags;
   986 
   987         flags = window->flags;
   988         if (fullscreen) {
   989             flags |= SDL_WINDOW_FULLSCREEN;
   990         } else {
   991             flags &= ~SDL_WINDOW_FULLSCREEN;
   992         }
   993         X11_SetNetWMState(_this, data->xwindow, flags);
   994     }
   995 
   996     if (data->visual->class == DirectColor) {
   997         if ( fullscreen ) {
   998             XInstallColormap(display, data->colormap);
   999         } else {
  1000             XUninstallColormap(display, data->colormap);
  1001         }
  1002     }
  1003 
  1004     XFlush(display);
  1005 }
  1006 
  1007 static __inline__ int
  1008 maxint(const int a, const int b)
  1009 {
  1010     return (a > b ? a : b);
  1011 }
  1012 
  1013 
  1014 /* This handles fullscreen itself, outside the Window Manager. */
  1015 static void
  1016 X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1017 {
  1018     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1019     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1020     Visual *visual = data->visual;
  1021     Display *display = data->videodata->display;
  1022     const int screen = displaydata->screen;
  1023     Window root = RootWindow(display, screen);
  1024     const int def_vis = (visual == DefaultVisual(display, screen));
  1025     unsigned long xattrmask = 0;
  1026     XSetWindowAttributes xattr;
  1027     XEvent ev;
  1028     SDL_Rect rect;
  1029 
  1030     if ( data->fswindow ) {
  1031         return;  /* already fullscreen, I hope. */
  1032     }
  1033 
  1034     X11_GetDisplayBounds(_this, _display, &rect);
  1035 
  1036     SDL_zero(xattr);
  1037     xattr.override_redirect = True;
  1038     xattrmask |= CWOverrideRedirect;
  1039     xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
  1040     xattrmask |= CWBackPixel;
  1041     xattr.border_pixel = 0;
  1042     xattrmask |= CWBorderPixel;
  1043     xattr.colormap = data->colormap;
  1044     xattrmask |= CWColormap;
  1045 
  1046     data->fswindow = XCreateWindow(display, root,
  1047                                    rect.x, rect.y, rect.w, rect.h, 0,
  1048                                    displaydata->depth, InputOutput,
  1049                                    visual, xattrmask, &xattr);
  1050 
  1051     XSelectInput(display, data->fswindow, StructureNotifyMask);
  1052     XSetWindowBackground(display, data->fswindow, 0);
  1053     XInstallColormap(display, data->colormap);
  1054     XClearWindow(display, data->fswindow);
  1055     XMapRaised(display, data->fswindow);
  1056 
  1057     /* Make sure the fswindow is in view by warping mouse to the corner */
  1058     XUngrabPointer(display, CurrentTime);
  1059     XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1060 
  1061     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1062     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
  1063     XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1064 
  1065 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
  1066     if ( displaydata->use_vidmode ) {
  1067         XF86VidModeLockModeSwitch(display, screen, True);
  1068     }
  1069 #endif
  1070 
  1071     SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
  1072 
  1073     /* Center actual window within our cover-the-screen window. */
  1074     XReparentWindow(display, data->xwindow, data->fswindow,
  1075                     (rect.w - window->w) / 2, (rect.h - window->h) / 2);
  1076 
  1077     /* Center mouse in the fullscreen window. */
  1078     rect.x += (rect.w / 2);
  1079     rect.y += (rect.h / 2);
  1080     XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1081 
  1082     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1083     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1084     XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1085 
  1086     X11_SetWindowGrab(_this, window);
  1087 }
  1088 
  1089 static void
  1090 X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1091 {
  1092     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1093     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1094     Display *display = data->videodata->display;
  1095     const int screen = displaydata->screen;
  1096     Window root = RootWindow(display, screen);
  1097     Window fswindow = data->fswindow;
  1098     XEvent ev;
  1099 
  1100     if (!data->fswindow) {
  1101         return;  /* already not fullscreen, I hope. */
  1102     }
  1103 
  1104     data->fswindow = None;
  1105 
  1106 #if SDL_VIDEO_DRIVER_X11_VIDMODE
  1107     if ( displaydata->use_vidmode ) {
  1108         XF86VidModeLockModeSwitch(display, screen, False);
  1109     }
  1110 #endif
  1111 
  1112     X11_SetWindowGrab(_this, window);
  1113 
  1114     XReparentWindow(display, data->xwindow, root, window->x, window->y);
  1115 
  1116     /* flush these events so they don't confuse normal event handling */
  1117     XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1118     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1119 
  1120     SetWindowBordered(display, screen, data->xwindow,
  1121                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1122 
  1123     XUnmapWindow(display, fswindow);
  1124 
  1125     /* Wait to be unmapped. */
  1126     XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&fswindow);
  1127     XDestroyWindow(display, fswindow);
  1128 }
  1129 
  1130 
  1131 void
  1132 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1133 {
  1134     /* !!! FIXME: SDL_Hint? */
  1135     SDL_bool legacy = SDL_FALSE;
  1136     const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
  1137     if (env) {
  1138         legacy = SDL_atoi(env);
  1139     } else {
  1140         SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1141         SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1142         if ( displaydata->use_vidmode ) {
  1143             legacy = SDL_TRUE;  /* the new stuff only works with XRandR. */
  1144         } else if ( !videodata->net_wm ) {
  1145             legacy = SDL_TRUE;  /* The window manager doesn't support it */
  1146         } else {
  1147             /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
  1148             /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
  1149             legacy = SDL_FALSE;  /* try the new way. */
  1150         }
  1151     }
  1152 
  1153     if (legacy) {
  1154         if (fullscreen) {
  1155             X11_BeginWindowFullscreenLegacy(_this, window, _display);
  1156         } else {
  1157             X11_EndWindowFullscreenLegacy(_this, window, _display);
  1158         }
  1159     } else {
  1160         X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
  1161     }
  1162 }
  1163 
  1164 
  1165 int
  1166 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1167 {
  1168     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1169     Display *display = data->videodata->display;
  1170     Visual *visual = data->visual;
  1171     Colormap colormap = data->colormap;
  1172     XColor *colorcells;
  1173     int ncolors;
  1174     int rmask, gmask, bmask;
  1175     int rshift, gshift, bshift;
  1176     int i;
  1177 
  1178     if (visual->class != DirectColor) {
  1179         SDL_SetError("Window doesn't have DirectColor visual");
  1180         return -1;
  1181     }
  1182 
  1183     ncolors = visual->map_entries;
  1184     colorcells = SDL_malloc(ncolors * sizeof(XColor));
  1185     if (!colorcells) {
  1186         SDL_OutOfMemory();
  1187         return -1;
  1188     }
  1189 
  1190     rshift = 0;
  1191     rmask = visual->red_mask;
  1192     while (0 == (rmask & 1)) {
  1193         rshift++;
  1194         rmask >>= 1;
  1195     }
  1196 
  1197     gshift = 0;
  1198     gmask = visual->green_mask;
  1199     while (0 == (gmask & 1)) {
  1200         gshift++;
  1201         gmask >>= 1;
  1202     }
  1203 
  1204     bshift = 0;
  1205     bmask = visual->blue_mask;
  1206     while (0 == (bmask & 1)) {
  1207         bshift++;
  1208         bmask >>= 1;
  1209     }
  1210 
  1211     /* build the color table pixel values */
  1212     for (i = 0; i < ncolors; i++) {
  1213         Uint32 rbits = (rmask * i) / (ncolors - 1);
  1214         Uint32 gbits = (gmask * i) / (ncolors - 1);
  1215         Uint32 bbits = (bmask * i) / (ncolors - 1);
  1216         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
  1217 
  1218         colorcells[i].pixel = pix;
  1219 
  1220         colorcells[i].red = ramp[(0 * 256) + i];
  1221         colorcells[i].green = ramp[(1 * 256) + i];
  1222         colorcells[i].blue = ramp[(2 * 256) + i];
  1223 
  1224         colorcells[i].flags = DoRed | DoGreen | DoBlue;
  1225     }
  1226 
  1227     XStoreColors(display, colormap, colorcells, ncolors);
  1228     XFlush(display);
  1229     SDL_free(colorcells);
  1230 
  1231     return 0;
  1232 }
  1233 
  1234 void
  1235 X11_SetWindowGrab(_THIS, SDL_Window * window)
  1236 {
  1237     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1238     Display *display = data->videodata->display;
  1239     SDL_bool oldstyle_fullscreen;
  1240 
  1241     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1242     oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
  1243 
  1244     if (oldstyle_fullscreen ||
  1245         ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
  1246          (window->flags & SDL_WINDOW_INPUT_FOCUS))) {
  1247 
  1248         /* Try to grab the mouse */
  1249         for (;;) {
  1250             int result =
  1251                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1252                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1253             if (result == GrabSuccess) {
  1254                 break;
  1255             }
  1256             SDL_Delay(100);
  1257         }
  1258 
  1259         /* Raise the window if we grab the mouse */
  1260         XRaiseWindow(display, data->xwindow);
  1261 
  1262         /* Now grab the keyboard */
  1263         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1264                       GrabModeAsync, CurrentTime);
  1265     } else {
  1266         XUngrabPointer(display, CurrentTime);
  1267         XUngrabKeyboard(display, CurrentTime);
  1268     }
  1269     XSync(display, False);
  1270 }
  1271 
  1272 void
  1273 X11_DestroyWindow(_THIS, SDL_Window * window)
  1274 {
  1275     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1276     window->driverdata = NULL;
  1277 
  1278     if (data) {
  1279         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1280         Display *display = videodata->display;
  1281         int numwindows = videodata->numwindows;
  1282         SDL_WindowData **windowlist = videodata->windowlist;
  1283         int i;
  1284 
  1285         if (windowlist) {
  1286             for (i = 0; i < numwindows; ++i) {
  1287                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1288                     windowlist[i] = windowlist[numwindows - 1];
  1289                     windowlist[numwindows - 1] = NULL;
  1290                     videodata->numwindows--;
  1291                     break;
  1292                 }
  1293             }
  1294         }
  1295 #ifdef X_HAVE_UTF8_STRING
  1296         if (data->ic) {
  1297             XDestroyIC(data->ic);
  1298         }
  1299 #endif
  1300         if (data->created) {
  1301             XDestroyWindow(display, data->xwindow);
  1302             XFlush(display);
  1303         }
  1304         SDL_free(data);
  1305     }
  1306 }
  1307 
  1308 SDL_bool
  1309 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1310 {
  1311     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1312     Display *display = data->videodata->display;
  1313 
  1314     if (info->version.major == SDL_MAJOR_VERSION &&
  1315         info->version.minor == SDL_MINOR_VERSION) {
  1316         info->subsystem = SDL_SYSWM_X11;
  1317         info->info.x11.display = display;
  1318         info->info.x11.window = data->xwindow;
  1319         return SDL_TRUE;
  1320     } else {
  1321         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1322                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1323         return SDL_FALSE;
  1324     }
  1325 }
  1326 
  1327 #endif /* SDL_VIDEO_DRIVER_X11 */
  1328 
  1329 /* vi: set ts=4 sw=4 expandtab: */