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