src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 27 Sep 2012 13:23:34 -0700
changeset 6475 71d39944810b
parent 6473 a5adb68266d0
child 6477 1e99ebaf0b14
permissions -rwxr-xr-x
Fixed fullscreen origin for multi-head displays
     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     const int w = maxint(window->w, _display->current_mode.w);
   995     const int h = maxint(window->h, _display->current_mode.h);
   996     unsigned long xattrmask = 0;
   997     XSetWindowAttributes xattr;
   998     XEvent ev;
   999     SDL_Rect rect;
  1000 
  1001     if ( data->fswindow ) {
  1002         return;  /* already fullscreen, I hope. */
  1003     }
  1004 
  1005     X11_GetDisplayBounds(_this, _display, &rect);
  1006 
  1007     /* Ungrab the input so that we can move the mouse around */
  1008     XUngrabPointer(display, CurrentTime);
  1009 
  1010     #if SDL_VIDEO_DRIVER_X11_XINERAMA
  1011     /* !!! FIXME: there was some Xinerama code in 1.2 here to set x,y to the origin of a specific screen. */
  1012     #endif
  1013 
  1014     SDL_zero(xattr);
  1015     xattr.override_redirect = True;
  1016     xattrmask |= CWOverrideRedirect;
  1017     xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
  1018     xattrmask |= CWBackPixel;
  1019     xattr.border_pixel = 0;
  1020     xattrmask |= CWBorderPixel;
  1021     xattr.colormap = data->colormap;
  1022     xattrmask |= CWColormap;
  1023 
  1024     data->fswindow = XCreateWindow(display, root,
  1025                                    rect.x, rect.y, rect.w, rect.h, 0,
  1026                                    displaydata->depth, InputOutput,
  1027                                    visual, xattrmask, &xattr);
  1028 
  1029     XSelectInput(display, data->fswindow, StructureNotifyMask);
  1030 
  1031     XSetWindowBackground(display, data->fswindow, 0);
  1032     XClearWindow(display, data->fswindow);
  1033 
  1034     XMapRaised(display, data->fswindow);
  1035 
  1036     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1037     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
  1038     XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1039 
  1040 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
  1041     if ( displaydata->use_vidmode ) {
  1042         XF86VidModeLockModeSwitch(display, screen, True);
  1043     }
  1044 #endif
  1045 
  1046     XInstallColormap(display, data->colormap);
  1047 
  1048     SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
  1049     XFlush(display);
  1050     //XIfEvent(display, &ev, &isConfigureNotify, (XPointer)&data->xwindow);
  1051 
  1052     /* Center actual window within our cover-the-screen window. */
  1053     rect.x += (rect.w - window->w) / 2;
  1054     rect.y += (rect.h - window->h) / 2;
  1055     XReparentWindow(display, data->xwindow, data->fswindow, rect.x, rect.y);
  1056     XRaiseWindow(display, data->xwindow);
  1057 
  1058     /* Make sure the fswindow is in view by warping mouse to the corner */
  1059     XWarpPointer(display, None, root, 0, 0, 0, 0, 0, 0);
  1060     XFlush(display);
  1061 
  1062     /* Center mouse in the window. */
  1063     rect.x += (window->w / 2);
  1064     rect.y += (window->h / 2);
  1065     XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1066 
  1067     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1068     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1069 
  1070     /* Wait to be visible, or XSetInputFocus() triggers an X error. */
  1071     while (SDL_TRUE) {
  1072         XWindowAttributes attr;
  1073         XSync(display, False);
  1074         XGetWindowAttributes(display, data->xwindow, &attr);
  1075         if (attr.map_state == IsViewable)
  1076             break;
  1077     }
  1078 
  1079     XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
  1080     window->flags |= SDL_WINDOW_INPUT_FOCUS;
  1081     SDL_SetKeyboardFocus(data->window);
  1082 
  1083     X11_SetWindowGrab(_this, window);
  1084 
  1085     XSync(display, False);
  1086 }
  1087 
  1088 static void
  1089 X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1090 {
  1091     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1092     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1093     Display *display = data->videodata->display;
  1094     const int screen = displaydata->screen;
  1095     Window root = RootWindow(display, screen);
  1096     XEvent ev;
  1097 
  1098     if (!data->fswindow)
  1099         return;  /* already not fullscreen, I hope. */
  1100 
  1101     XReparentWindow(display, data->xwindow, root, window->x, window->y);
  1102 
  1103 #if SDL_VIDEO_DRIVER_X11_VIDMODE
  1104     if ( displaydata->use_vidmode ) {
  1105         XF86VidModeLockModeSwitch(display, screen, False);
  1106     }
  1107 #endif
  1108 
  1109     XUnmapWindow(display, data->fswindow);
  1110     /* Wait to be unmapped. */
  1111     XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1112     XDestroyWindow(display, data->fswindow);
  1113     data->fswindow = 0;
  1114 
  1115     /* catch these events so we know the window is back in business. */
  1116     XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1117     XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1118 
  1119     XSync(display, True);   /* Flush spurious mode change events */
  1120 
  1121     X11_SetWindowGrab(_this, window);
  1122 
  1123     SetWindowBordered(display, screen, data->xwindow,
  1124                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1125 
  1126     XFlush(display);
  1127 }
  1128 
  1129 
  1130 void
  1131 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1132 {
  1133     /* !!! FIXME: SDL_Hint? */
  1134     SDL_bool legacy = SDL_FALSE;
  1135     const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
  1136     if (env) {
  1137         legacy = SDL_atoi(env);
  1138     } else {
  1139         SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1140         SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1141         if ( displaydata->use_vidmode ) {
  1142             legacy = SDL_TRUE;  /* the new stuff only works with XRandR. */
  1143         } else if ( !videodata->net_wm ) {
  1144             legacy = SDL_TRUE;  /* The window manager doesn't support it */
  1145         } else {
  1146             /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
  1147             /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
  1148             legacy = SDL_FALSE;  /* try the new way. */
  1149         }
  1150     }
  1151 
  1152     if (legacy) {
  1153         if (fullscreen) {
  1154             X11_BeginWindowFullscreenLegacy(_this, window, _display);
  1155         } else {
  1156             X11_EndWindowFullscreenLegacy(_this, window, _display);
  1157         }
  1158     } else {
  1159         X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
  1160     }
  1161 }
  1162 
  1163 
  1164 int
  1165 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1166 {
  1167     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1168     Display *display = data->videodata->display;
  1169     Visual *visual = data->visual;
  1170     Colormap colormap = data->colormap;
  1171     XColor *colorcells;
  1172     int ncolors;
  1173     int rmask, gmask, bmask;
  1174     int rshift, gshift, bshift;
  1175     int i;
  1176 
  1177     if (visual->class != DirectColor) {
  1178         SDL_SetError("Window doesn't have DirectColor visual");
  1179         return -1;
  1180     }
  1181 
  1182     ncolors = visual->map_entries;
  1183     colorcells = SDL_malloc(ncolors * sizeof(XColor));
  1184     if (!colorcells) {
  1185         SDL_OutOfMemory();
  1186         return -1;
  1187     }
  1188 
  1189     rshift = 0;
  1190     rmask = visual->red_mask;
  1191     while (0 == (rmask & 1)) {
  1192         rshift++;
  1193         rmask >>= 1;
  1194     }
  1195 
  1196     gshift = 0;
  1197     gmask = visual->green_mask;
  1198     while (0 == (gmask & 1)) {
  1199         gshift++;
  1200         gmask >>= 1;
  1201     }
  1202 
  1203     bshift = 0;
  1204     bmask = visual->blue_mask;
  1205     while (0 == (bmask & 1)) {
  1206         bshift++;
  1207         bmask >>= 1;
  1208     }
  1209 
  1210     /* build the color table pixel values */
  1211     for (i = 0; i < ncolors; i++) {
  1212         Uint32 rbits = (rmask * i) / (ncolors - 1);
  1213         Uint32 gbits = (gmask * i) / (ncolors - 1);
  1214         Uint32 bbits = (bmask * i) / (ncolors - 1);
  1215         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
  1216 
  1217         colorcells[i].pixel = pix;
  1218 
  1219         colorcells[i].red = ramp[(0 * 256) + i];
  1220         colorcells[i].green = ramp[(1 * 256) + i];
  1221         colorcells[i].blue = ramp[(2 * 256) + i];
  1222 
  1223         colorcells[i].flags = DoRed | DoGreen | DoBlue;
  1224     }
  1225 
  1226     XStoreColors(display, colormap, colorcells, ncolors);
  1227     XFlush(display);
  1228     SDL_free(colorcells);
  1229 
  1230     return 0;
  1231 }
  1232 
  1233 void
  1234 X11_SetWindowGrab(_THIS, SDL_Window * window)
  1235 {
  1236     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1237     Display *display = data->videodata->display;
  1238     SDL_bool oldstyle_fullscreen;
  1239 
  1240     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1241     oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
  1242 
  1243     if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
  1244         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1245         /* Try to grab the mouse */
  1246         for (;;) {
  1247             int result =
  1248                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1249                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1250             if (result == GrabSuccess) {
  1251                 break;
  1252             }
  1253             SDL_Delay(100);
  1254         }
  1255 
  1256         /* Raise the window if we grab the mouse */
  1257         XRaiseWindow(display, data->xwindow);
  1258 
  1259         /* Now grab the keyboard */
  1260         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1261                       GrabModeAsync, CurrentTime);
  1262     } else {
  1263         XUngrabPointer(display, CurrentTime);
  1264         XUngrabKeyboard(display, CurrentTime);
  1265     }
  1266 }
  1267 
  1268 void
  1269 X11_DestroyWindow(_THIS, SDL_Window * window)
  1270 {
  1271     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1272     window->driverdata = NULL;
  1273 
  1274     if (data) {
  1275         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1276         Display *display = videodata->display;
  1277         int numwindows = videodata->numwindows;
  1278         SDL_WindowData **windowlist = videodata->windowlist;
  1279         int i;
  1280 
  1281         if (windowlist) {
  1282             for (i = 0; i < numwindows; ++i) {
  1283                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1284                     windowlist[i] = windowlist[numwindows - 1];
  1285                     windowlist[numwindows - 1] = NULL;
  1286                     videodata->numwindows--;
  1287                     break;
  1288                 }
  1289             }
  1290         }
  1291 #ifdef X_HAVE_UTF8_STRING
  1292         if (data->ic) {
  1293             XDestroyIC(data->ic);
  1294         }
  1295 #endif
  1296         if (data->created) {
  1297             XDestroyWindow(display, data->xwindow);
  1298             XFlush(display);
  1299         }
  1300         SDL_free(data);
  1301     }
  1302 }
  1303 
  1304 SDL_bool
  1305 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1306 {
  1307     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1308     Display *display = data->videodata->display;
  1309 
  1310     if (info->version.major == SDL_MAJOR_VERSION &&
  1311         info->version.minor == SDL_MINOR_VERSION) {
  1312         info->subsystem = SDL_SYSWM_X11;
  1313         info->info.x11.display = display;
  1314         info->info.x11.window = data->xwindow;
  1315         return SDL_TRUE;
  1316     } else {
  1317         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1318                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1319         return SDL_FALSE;
  1320     }
  1321 }
  1322 
  1323 #endif /* SDL_VIDEO_DRIVER_X11 */
  1324 
  1325 /* vi: set ts=4 sw=4 expandtab: */