src/video/x11/SDL_x11window.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 27 Sep 2012 03:36:13 -0400
changeset 6467 ec5a04e921d4
parent 6466 ebe165c00fab
child 6470 ca793191b67a
permissions -rwxr-xr-x
X11: Attempt to go fullscreen the way SDL 1.2 did it.

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