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