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