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