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