src/video/x11/SDL_x11window.c
author Ryan C. Gordon <icculus@icculus.org>
Sat, 03 Aug 2013 02:20:00 -0400
changeset 7566 b14d00c30095
parent 7523 9e9ab1dc3811
child 7617 918703f5cff8
permissions -rw-r--r--
Some fixes for SDL_MaximizeWindow().

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