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