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