src/video/x11/SDL_x11window.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 13 Sep 2012 15:24:04 -0400
changeset 6423 339c0ccf6250
parent 6422 fd0ac1b56115
child 6462 5e09ac1aba80
permissions -rwxr-xr-x
Make the X11 SetBordered event tapdancing more robust, restore focus, etc.
     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 
    42 #define _NET_WM_STATE_REMOVE    0l
    43 #define _NET_WM_STATE_ADD       1l
    44 #define _NET_WM_STATE_TOGGLE    2l
    45 
    46 static SDL_bool
    47 X11_IsWindowOldFullscreen(_THIS, SDL_Window * window)
    48 {
    49     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    50 
    51     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
    52     if ((window->flags & SDL_WINDOW_FULLSCREEN) && !videodata->net_wm) {
    53         return SDL_TRUE;
    54     } else {
    55         return SDL_FALSE;
    56     }
    57 }
    58 
    59 static SDL_bool
    60 X11_IsWindowMapped(_THIS, SDL_Window * window)
    61 {
    62     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    63     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    64     XWindowAttributes attr;
    65 
    66     XGetWindowAttributes(videodata->display, data->xwindow, &attr);
    67     if (attr.map_state != IsUnmapped) {
    68         return SDL_TRUE;
    69     } else {
    70         return SDL_FALSE;
    71     }
    72 }
    73 
    74 static int
    75 X11_GetWMStateProperty(_THIS, SDL_Window * window, Atom atoms[3])
    76 {
    77     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    78     int count = 0;
    79 
    80     if (window->flags & SDL_WINDOW_FULLSCREEN) {
    81         atoms[count++] = data->_NET_WM_STATE_FULLSCREEN;
    82     }
    83     if (window->flags & SDL_WINDOW_MAXIMIZED) {
    84         atoms[count++] = data->_NET_WM_STATE_MAXIMIZED_VERT;
    85         atoms[count++] = data->_NET_WM_STATE_MAXIMIZED_HORZ;
    86     }
    87     return count;
    88 }
    89 
    90 static int
    91 SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
    92 {
    93     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    94     SDL_WindowData *data;
    95     int numwindows = videodata->numwindows;
    96     int windowlistlength = videodata->windowlistlength;
    97     SDL_WindowData **windowlist = videodata->windowlist;
    98 
    99     /* Allocate the window data */
   100     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   101     if (!data) {
   102         SDL_OutOfMemory();
   103         return -1;
   104     }
   105     data->window = window;
   106     data->xwindow = w;
   107 #ifdef X_HAVE_UTF8_STRING
   108     if (SDL_X11_HAVE_UTF8) {
   109         data->ic =
   110             pXCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w,
   111                        XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
   112                        XNResourceName, videodata->classname, XNResourceClass,
   113                        videodata->classname, NULL);
   114     }
   115 #endif
   116     data->created = created;
   117     data->videodata = videodata;
   118 
   119     /* Associate the data with the window */
   120 
   121     if (numwindows < windowlistlength) {
   122         windowlist[numwindows] = data;
   123         videodata->numwindows++;
   124     } else {
   125         windowlist =
   126             (SDL_WindowData **) SDL_realloc(windowlist,
   127                                             (numwindows +
   128                                              1) * sizeof(*windowlist));
   129         if (!windowlist) {
   130             SDL_OutOfMemory();
   131             SDL_free(data);
   132             return -1;
   133         }
   134         windowlist[numwindows] = data;
   135         videodata->numwindows++;
   136         videodata->windowlistlength++;
   137         videodata->windowlist = windowlist;
   138     }
   139 
   140     /* Fill in the SDL window with the window data */
   141     {
   142         XWindowAttributes attrib;
   143 
   144         XGetWindowAttributes(data->videodata->display, w, &attrib);
   145         window->x = attrib.x;
   146         window->y = attrib.y;
   147         window->w = attrib.width;
   148         window->h = attrib.height;
   149         if (attrib.map_state != IsUnmapped) {
   150             window->flags |= SDL_WINDOW_SHOWN;
   151         } else {
   152             window->flags &= ~SDL_WINDOW_SHOWN;
   153         }
   154         data->visual = attrib.visual;
   155         data->colormap = attrib.colormap;
   156     }
   157 
   158     {
   159         Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   160         Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   161         Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   162         Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   163         Atom actualType;
   164         int actualFormat;
   165         unsigned long i, numItems, bytesAfter;
   166         unsigned char *propertyValue = NULL;
   167         long maxLength = 1024;
   168 
   169         if (XGetWindowProperty(data->videodata->display, w, _NET_WM_STATE,
   170                                0l, maxLength, False, XA_ATOM, &actualType,
   171                                &actualFormat, &numItems, &bytesAfter,
   172                                &propertyValue) == Success) {
   173             Atom *atoms = (Atom *) propertyValue;
   174             int maximized = 0;
   175             int fullscreen = 0;
   176 
   177             for (i = 0; i < numItems; ++i) {
   178                 if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
   179                     maximized |= 1;
   180                 } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
   181                     maximized |= 2;
   182                 } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
   183                     fullscreen = 1;
   184                 }
   185             }
   186             if (maximized == 3) {
   187                 window->flags |= SDL_WINDOW_MAXIMIZED;
   188             }  else if (fullscreen == 1) {
   189                 window->flags |= SDL_WINDOW_FULLSCREEN;
   190             }
   191             XFree(propertyValue);
   192         }
   193     }
   194 
   195     {
   196         Window FocalWindow;
   197         int RevertTo=0;
   198         XGetInputFocus(data->videodata->display, &FocalWindow, &RevertTo);
   199         if (FocalWindow==w)
   200         {
   201             window->flags |= SDL_WINDOW_INPUT_FOCUS;
   202             SDL_SetKeyboardFocus(data->window);
   203         }
   204 
   205         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   206             /* Tell x11 to clip mouse */
   207         }
   208     }
   209 
   210     /* FIXME: How can I tell?
   211        {
   212        DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   213        if (style & WS_VISIBLE) {
   214        if (style & (WS_BORDER | WS_THICKFRAME)) {
   215        window->flags &= ~SDL_WINDOW_BORDERLESS;
   216        } else {
   217        window->flags |= SDL_WINDOW_BORDERLESS;
   218        }
   219        if (style & WS_THICKFRAME) {
   220        window->flags |= SDL_WINDOW_RESIZABLE;
   221        } else {
   222        window->flags &= ~SDL_WINDOW_RESIZABLE;
   223        }
   224        if (style & WS_MINIMIZE) {
   225        window->flags |= SDL_WINDOW_MINIMIZED;
   226        } else {
   227        window->flags &= ~SDL_WINDOW_MINIMIZED;
   228        }
   229        }
   230        if (GetFocus() == hwnd) {
   231        int index = data->videodata->keyboard;
   232        window->flags |= SDL_WINDOW_INPUT_FOCUS;
   233        SDL_SetKeyboardFocus(index, data->window);
   234 
   235        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   236        RECT rect;
   237        GetClientRect(hwnd, &rect);
   238        ClientToScreen(hwnd, (LPPOINT) & rect);
   239        ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   240        ClipCursor(&rect);
   241        }
   242        }
   243      */
   244 
   245     /* All done! */
   246     window->driverdata = data;
   247     return 0;
   248 }
   249 
   250 static void
   251 SetWindowBordered(Display *display, int screen, Window window, SDL_bool border)
   252 {
   253     /*
   254      * this code used to check for KWM_WIN_DECORATION, but KDE hasn't
   255      *  supported it for years and years. It now respects _MOTIF_WM_HINTS.
   256      *  Gnome is similar: just use the Motif atom.
   257      */
   258 
   259     Atom WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", True);
   260     if (WM_HINTS != None) {
   261         /* Hints used by Motif compliant window managers */
   262         struct
   263         {
   264             unsigned long flags;
   265             unsigned long functions;
   266             unsigned long decorations;
   267             long input_mode;
   268             unsigned long status;
   269         } MWMHints = {
   270             (1L << 1), 0, border ? 1 : 0, 0, 0
   271         };
   272 
   273         XChangeProperty(display, window, WM_HINTS, WM_HINTS, 32,
   274                         PropModeReplace, (unsigned char *) &MWMHints,
   275                         sizeof(MWMHints) / 4);
   276     } else {  /* set the transient hints instead, if necessary */
   277         XSetTransientForHint(display, window, RootWindow(display, screen));
   278     }
   279 }
   280 
   281 int
   282 X11_CreateWindow(_THIS, SDL_Window * window)
   283 {
   284     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   285     SDL_DisplayData *displaydata =
   286         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   287     Display *display = data->display;
   288     int screen = displaydata->screen;
   289     Visual *visual;
   290     int depth;
   291     XSetWindowAttributes xattr;
   292     Window w;
   293     XSizeHints sizehints;
   294     XWMHints wmhints;
   295     XClassHint classhints;
   296     Atom _NET_WM_WINDOW_TYPE;
   297     Atom _NET_WM_WINDOW_TYPE_NORMAL;
   298     Atom _NET_WM_PID;
   299     int wmstate_count;
   300     Atom wmstate_atoms[3];
   301     Uint32 fevent = 0;
   302 
   303 #if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   304     if (window->flags & SDL_WINDOW_OPENGL) {
   305         XVisualInfo *vinfo;
   306 
   307 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2        
   308         if (_this->gl_config.use_egl == 1) {
   309             vinfo = X11_GLES_GetVisual(_this, display, screen);
   310         } else
   311 #endif
   312         {
   313 #if SDL_VIDEO_OPENGL_GLX
   314             vinfo = X11_GL_GetVisual(_this, display, screen);
   315 #endif
   316         }
   317         if (!vinfo) {
   318             return -1;
   319         }
   320         visual = vinfo->visual;
   321         depth = vinfo->depth;
   322         XFree(vinfo);
   323     } else
   324 #endif
   325     {
   326         visual = displaydata->visual;
   327         depth = displaydata->depth;
   328     }
   329 
   330     xattr.override_redirect = False;
   331     xattr.background_pixel = 0;
   332     xattr.border_pixel = 0;
   333 
   334     if (visual->class == DirectColor) {
   335         XColor *colorcells;
   336         int i;
   337         int ncolors;
   338         int rmax, gmax, bmax;
   339         int rmask, gmask, bmask;
   340         int rshift, gshift, bshift;
   341 
   342         xattr.colormap =
   343             XCreateColormap(display, RootWindow(display, screen),
   344                             visual, AllocAll);
   345 
   346         /* If we can't create a colormap, then we must die */
   347         if (!xattr.colormap) {
   348             SDL_SetError("Could not create writable colormap");
   349             return -1;
   350         }
   351 
   352         /* OK, we got a colormap, now fill it in as best as we can */
   353         colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   354         if (!colorcells) {
   355             SDL_OutOfMemory();
   356             return -1;
   357         }
   358         ncolors = visual->map_entries;
   359         rmax = 0xffff;
   360         gmax = 0xffff;
   361         bmax = 0xffff;
   362 
   363         rshift = 0;
   364         rmask = visual->red_mask;
   365         while (0 == (rmask & 1)) {
   366             rshift++;
   367             rmask >>= 1;
   368         }
   369 
   370         gshift = 0;
   371         gmask = visual->green_mask;
   372         while (0 == (gmask & 1)) {
   373             gshift++;
   374             gmask >>= 1;
   375         }
   376 
   377         bshift = 0;
   378         bmask = visual->blue_mask;
   379         while (0 == (bmask & 1)) {
   380             bshift++;
   381             bmask >>= 1;
   382         }
   383 
   384         /* build the color table pixel values */
   385         for (i = 0; i < ncolors; i++) {
   386             Uint32 red = (rmax * i) / (ncolors - 1);
   387             Uint32 green = (gmax * i) / (ncolors - 1);
   388             Uint32 blue = (bmax * i) / (ncolors - 1);
   389 
   390             Uint32 rbits = (rmask * i) / (ncolors - 1);
   391             Uint32 gbits = (gmask * i) / (ncolors - 1);
   392             Uint32 bbits = (bmask * i) / (ncolors - 1);
   393 
   394             Uint32 pix =
   395                 (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   396 
   397             colorcells[i].pixel = pix;
   398 
   399             colorcells[i].red = red;
   400             colorcells[i].green = green;
   401             colorcells[i].blue = blue;
   402 
   403             colorcells[i].flags = DoRed | DoGreen | DoBlue;
   404         }
   405 
   406         XStoreColors(display, xattr.colormap, colorcells, ncolors);
   407 
   408         SDL_free(colorcells);
   409     } else {
   410         xattr.colormap =
   411             XCreateColormap(display, RootWindow(display, screen),
   412                             visual, AllocNone);
   413     }
   414 
   415     w = XCreateWindow(display, RootWindow(display, screen),
   416                       window->x, window->y, window->w, window->h,
   417                       0, depth, InputOutput, visual,
   418                       (CWOverrideRedirect | CWBackPixel | CWBorderPixel |
   419                        CWColormap), &xattr);
   420     if (!w) {
   421         SDL_SetError("Couldn't create window");
   422         return -1;
   423     }
   424 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   425     if ((window->flags & SDL_WINDOW_OPENGL) && (_this->gl_config.use_egl == 1)) {
   426         if (!_this->gles_data) {
   427             XDestroyWindow(display, w);
   428             return -1;
   429         }
   430 
   431         /* Create the GLES window surface */
   432         _this->gles_data->egl_surface =
   433             _this->gles_data->eglCreateWindowSurface(_this->gles_data->
   434                                                  egl_display,
   435                                                  _this->gles_data->egl_config,
   436                                                  (NativeWindowType) w, NULL);
   437 
   438         if (_this->gles_data->egl_surface == EGL_NO_SURFACE) {
   439             SDL_SetError("Could not create GLES window surface");
   440             XDestroyWindow(display, w);
   441             return -1;
   442         }
   443     }
   444 #endif
   445 
   446     SetWindowBordered(display, screen, w,
   447                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
   448 
   449     /* Setup the normal size hints */
   450     sizehints.flags = 0;
   451     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   452         sizehints.min_width = sizehints.max_width = window->w;
   453         sizehints.min_height = sizehints.max_height = window->h;
   454         sizehints.flags |= (PMaxSize | PMinSize);
   455     }
   456     sizehints.x = window->x;
   457     sizehints.y = window->y;
   458     sizehints.flags |= USPosition;
   459 
   460     /* Setup the input hints so we get keyboard input */
   461     wmhints.input = True;
   462     wmhints.flags = InputHint;
   463 
   464     /* Setup the class hints so we can get an icon (AfterStep) */
   465     classhints.res_name = data->classname;
   466     classhints.res_class = data->classname;
   467 
   468     /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */
   469     XSetWMProperties(display, w, NULL, NULL, NULL, 0, &sizehints, &wmhints, &classhints);
   470 
   471     /* Set the PID related to the window for the given hostname, if possible */
   472     if (data->pid > 0) {
   473         _NET_WM_PID = XInternAtom(display, "_NET_WM_PID", False);
   474         XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace,
   475                         (unsigned char *)&data->pid, 1);
   476     }
   477 
   478     /* Set the window manager state */
   479     wmstate_count = X11_GetWMStateProperty(_this, window, wmstate_atoms);
   480     if (wmstate_count > 0) {
   481         XChangeProperty(display, w, data->_NET_WM_STATE, XA_ATOM, 32,
   482                         PropModeReplace,
   483                         (unsigned char *)wmstate_atoms, wmstate_count);
   484     } else {
   485         XDeleteProperty(display, w, data->_NET_WM_STATE);
   486     }
   487 
   488     /* Let the window manager know we're a "normal" window */
   489     _NET_WM_WINDOW_TYPE = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
   490     _NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
   491     XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
   492                     PropModeReplace,
   493                     (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1);
   494 
   495     /* Allow the window to be deleted by the window manager */
   496     XSetWMProtocols(display, w, &data->WM_DELETE_WINDOW, 1);
   497 
   498     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   499         XDestroyWindow(display, w);
   500         return -1;
   501     }
   502 
   503 #ifdef X_HAVE_UTF8_STRING
   504     if (SDL_X11_HAVE_UTF8) {
   505         pXGetICValues(((SDL_WindowData *) window->driverdata)->ic,
   506                       XNFilterEvents, &fevent, NULL);
   507     }
   508 #endif
   509 
   510     X11_Xinput2SelectTouch(_this, window);
   511 
   512     XSelectInput(display, w,
   513                  (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   514                  ExposureMask | ButtonPressMask | ButtonReleaseMask |
   515                  PointerMotionMask | KeyPressMask | KeyReleaseMask |
   516                  PropertyChangeMask | StructureNotifyMask |
   517                  KeymapStateMask | fevent));
   518 
   519     XFlush(display);
   520 
   521     return 0;
   522 }
   523 
   524 int
   525 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   526 {
   527     Window w = (Window) data;
   528 
   529     window->title = X11_GetWindowTitle(_this, w);
   530 
   531     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   532         return -1;
   533     }
   534     return 0;
   535 }
   536 
   537 char *
   538 X11_GetWindowTitle(_THIS, Window xwindow)
   539 {
   540     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   541     Display *display = data->display;
   542     int status, real_format;
   543     Atom real_type;
   544     unsigned long items_read, items_left;
   545     unsigned char *propdata;
   546     char *title = NULL;
   547 
   548     status = XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
   549                 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
   550                 &items_read, &items_left, &propdata);
   551     if (status == Success && propdata) {
   552         title = SDL_strdup(SDL_static_cast(char*, propdata));
   553         XFree(propdata);
   554     } else {
   555         status = XGetWindowProperty(display, xwindow, XA_WM_NAME,
   556                     0L, 8192L, False, XA_STRING, &real_type, &real_format,
   557                     &items_read, &items_left, &propdata);
   558         if (status == Success && propdata) {
   559             title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
   560         } else {
   561             title = SDL_strdup("");
   562         }
   563     }
   564     return title;
   565 }
   566 
   567 void
   568 X11_SetWindowTitle(_THIS, SDL_Window * window)
   569 {
   570     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   571     Display *display = data->videodata->display;
   572     XTextProperty titleprop, iconprop;
   573     Status status;
   574     const char *title = window->title;
   575     const char *icon = NULL;
   576 
   577 #ifdef X_HAVE_UTF8_STRING
   578     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   579     Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME;
   580 #endif
   581 
   582     if (title != NULL) {
   583         char *title_locale = SDL_iconv_utf8_locale(title);
   584         if (!title_locale) {
   585             SDL_OutOfMemory();
   586             return;
   587         }
   588         status = XStringListToTextProperty(&title_locale, 1, &titleprop);
   589         SDL_free(title_locale);
   590         if (status) {
   591             XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   592             XFree(titleprop.value);
   593         }
   594 #ifdef X_HAVE_UTF8_STRING
   595         if (SDL_X11_HAVE_UTF8) {
   596             status =
   597                 Xutf8TextListToTextProperty(display, (char **) &title, 1,
   598                                             XUTF8StringStyle, &titleprop);
   599             if (status == Success) {
   600                 XSetTextProperty(display, data->xwindow, &titleprop,
   601                                  _NET_WM_NAME);
   602                 XFree(titleprop.value);
   603             }
   604         }
   605 #endif
   606     }
   607     if (icon != NULL) {
   608         char *icon_locale = SDL_iconv_utf8_locale(icon);
   609         if (!icon_locale) {
   610             SDL_OutOfMemory();
   611             return;
   612         }
   613         status = XStringListToTextProperty(&icon_locale, 1, &iconprop);
   614         SDL_free(icon_locale);
   615         if (status) {
   616             XSetTextProperty(display, data->xwindow, &iconprop,
   617                              XA_WM_ICON_NAME);
   618             XFree(iconprop.value);
   619         }
   620 #ifdef X_HAVE_UTF8_STRING
   621         if (SDL_X11_HAVE_UTF8) {
   622             status =
   623                 Xutf8TextListToTextProperty(display, (char **) &icon, 1,
   624                                             XUTF8StringStyle, &iconprop);
   625             if (status == Success) {
   626                 XSetTextProperty(display, data->xwindow, &iconprop,
   627                                  _NET_WM_ICON_NAME);
   628                 XFree(iconprop.value);
   629             }
   630         }
   631 #endif
   632     }
   633     XFlush(display);
   634 }
   635 
   636 void
   637 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   638 {
   639     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   640     Display *display = data->videodata->display;
   641     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   642 
   643     if (icon) {
   644         SDL_PixelFormat format;
   645         SDL_Surface *surface;
   646         int propsize;
   647         long *propdata;
   648 
   649         /* Convert the icon to ARGB for modern window managers */
   650         SDL_InitFormat(&format, SDL_PIXELFORMAT_ARGB8888);
   651         surface = SDL_ConvertSurface(icon, &format, 0);
   652         if (!surface) {
   653             return;
   654         }
   655 
   656         /* Set the _NET_WM_ICON property */
   657         propsize = 2 + (icon->w * icon->h);
   658         propdata = SDL_malloc(propsize * sizeof(long));
   659         if (propdata) {
   660             int x, y;
   661             Uint32 *src;
   662             long *dst;
   663 
   664             propdata[0] = icon->w;
   665             propdata[1] = icon->h;
   666             dst = &propdata[2];
   667             for (y = 0; y < icon->h; ++y) {
   668                 src = (Uint32*)((Uint8*)surface->pixels + y * surface->pitch);
   669                 for (x = 0; x < icon->w; ++x) {
   670                     *dst++ = *src++;
   671                 }
   672             }
   673             XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   674                             32, PropModeReplace, (unsigned char *) propdata,
   675                             propsize);
   676         }
   677         SDL_FreeSurface(surface);
   678     } else {
   679         XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   680     }
   681     XFlush(display);
   682 }
   683 
   684 void
   685 X11_SetWindowPosition(_THIS, SDL_Window * window)
   686 {
   687     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   688     Display *display = data->videodata->display;
   689 
   690     XMoveWindow(display, data->xwindow, window->x, window->y);
   691     XFlush(display);
   692 }
   693 
   694 void
   695 X11_SetWindowSize(_THIS, SDL_Window * window)
   696 {
   697     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   698     Display *display = data->videodata->display;
   699 
   700     if (SDL_IsShapedWindow(window))
   701         X11_ResizeWindowShape(window);
   702     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   703          /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the XResizeWindow, thus
   704             we must set the size hints to adjust the window size.*/
   705          XSizeHints *sizehints = XAllocSizeHints();
   706          long userhints;
   707 
   708          XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   709 
   710          sizehints->min_width = sizehints->max_width = window->w;
   711          sizehints->min_height = sizehints->max_height = window->h;
   712 
   713          XSetWMNormalHints(display, data->xwindow, sizehints);
   714 
   715          XFree(sizehints);
   716     } else
   717         XResizeWindow(display, data->xwindow, window->w, window->h);
   718     XFlush(display);
   719 }
   720 
   721 static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
   722 {
   723     return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
   724 }
   725 static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
   726 {
   727     return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
   728 }
   729 static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
   730 {
   731     return ev->type == ConfigureNotify && ev->xunmap.window == *((Window*)win);
   732 }
   733 
   734 void
   735 X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   736 {
   737     const SDL_bool focused = ((window->flags & SDL_WINDOW_INPUT_FOCUS) != 0);
   738     const SDL_bool visible = ((window->flags & SDL_WINDOW_HIDDEN) == 0);
   739     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   740     SDL_DisplayData *displaydata =
   741         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   742     Display *display = data->videodata->display;
   743     XEvent event;
   744 
   745     SetWindowBordered(display, displaydata->screen, data->xwindow, bordered);
   746     XFlush(display);
   747     XIfEvent(display, &event, &isConfigureNotify, (XPointer)&data->xwindow);
   748 
   749     if (visible) {
   750         XWindowAttributes attr;
   751         do {
   752             XSync(display, False);
   753             XGetWindowAttributes(display, data->xwindow, &attr);
   754         } while (attr.map_state != IsViewable);
   755 
   756         if (focused) {
   757             XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
   758         }
   759     }
   760 
   761     /* make sure these don't make it to the real event queue if they fired here. */
   762     XSync(display, False);
   763     XCheckIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
   764     XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   765 }
   766 
   767 void
   768 X11_ShowWindow(_THIS, SDL_Window * window)
   769 {
   770     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   771     Display *display = data->videodata->display;
   772     XEvent event;
   773 
   774     XMapRaised(display, data->xwindow);
   775     /* Blocking wait for "MapNotify" event.
   776      * We use XIfEvent because XWindowEvent takes a mask rather than a type, 
   777      * and XCheckTypedWindowEvent doesn't block */
   778     XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   779     XFlush(display);
   780 }
   781 
   782 void
   783 X11_HideWindow(_THIS, SDL_Window * window)
   784 {
   785     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   786     Display *display = data->videodata->display;
   787     XEvent event;
   788 
   789     XUnmapWindow(display, data->xwindow);
   790     /* Blocking wait for "UnmapNotify" event */
   791     XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);    
   792     XFlush(display);
   793 }
   794 
   795 void
   796 X11_RaiseWindow(_THIS, SDL_Window * window)
   797 {
   798     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   799     Display *display = data->videodata->display;
   800 
   801     XRaiseWindow(display, data->xwindow);
   802     XFlush(display);
   803 }
   804 
   805 static void
   806 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   807 {
   808     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   809     SDL_DisplayData *displaydata =
   810         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   811     Display *display = data->videodata->display;
   812     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   813     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   814     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   815     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   816 
   817     if (X11_IsWindowMapped(_this, window)) {
   818         XEvent e;
   819 
   820         SDL_zero(e);
   821         e.xany.type = ClientMessage;
   822         e.xclient.message_type = _NET_WM_STATE;
   823         e.xclient.format = 32;
   824         e.xclient.window = data->xwindow;
   825         e.xclient.data.l[0] =
   826             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   827         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
   828         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
   829         e.xclient.data.l[3] = 0l;
   830 
   831         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   832                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   833     } else {
   834         int count = 0;
   835         Atom atoms[3];
   836 
   837         if (window->flags & SDL_WINDOW_FULLSCREEN) {
   838             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   839         }
   840         if (maximized) {
   841             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   842             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   843         }
   844         if (count > 0) {
   845             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
   846                             PropModeReplace, (unsigned char *)atoms, count);
   847         } else {
   848             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
   849         }
   850     }
   851     XFlush(display);
   852 }
   853 
   854 void
   855 X11_MaximizeWindow(_THIS, SDL_Window * window)
   856 {
   857     SetWindowMaximized(_this, window, SDL_TRUE);
   858 }
   859 
   860 void
   861 X11_MinimizeWindow(_THIS, SDL_Window * window)
   862 {
   863     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   864     SDL_DisplayData *displaydata =
   865         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   866     Display *display = data->videodata->display;
   867  
   868     XIconifyWindow(display, data->xwindow, displaydata->screen);
   869     XFlush(display);
   870 }
   871 
   872 void
   873 X11_RestoreWindow(_THIS, SDL_Window * window)
   874 {
   875     SetWindowMaximized(_this, window, SDL_FALSE);
   876     X11_ShowWindow(_this, window);
   877 }
   878 
   879 void
   880 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
   881 {
   882     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   883     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
   884     Display *display = data->videodata->display;
   885     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   886     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   887     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   888     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   889 
   890     if (X11_IsWindowMapped(_this, window)) {
   891         XEvent e;
   892 
   893         SDL_zero(e);
   894         e.xany.type = ClientMessage;
   895         e.xclient.message_type = _NET_WM_STATE;
   896         e.xclient.format = 32;
   897         e.xclient.window = data->xwindow;
   898         e.xclient.data.l[0] =
   899             fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   900         e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
   901         e.xclient.data.l[3] = 0l;
   902 
   903         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   904                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   905     } else {
   906         int count = 0;
   907         Atom atoms[3];
   908 
   909         if (fullscreen) {
   910             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   911         }
   912         if (window->flags & SDL_WINDOW_MAXIMIZED) {
   913             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   914             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   915         }
   916         if (count > 0) {
   917             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
   918                             PropModeReplace, (unsigned char *)atoms, count);
   919         } else {
   920             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
   921         }
   922     }
   923     XFlush(display);
   924 }
   925 
   926 int
   927 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   928 {
   929     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   930     Display *display = data->videodata->display;
   931     Visual *visual = data->visual;
   932     Colormap colormap = data->colormap;
   933     XColor *colorcells;
   934     int ncolors;
   935     int rmask, gmask, bmask;
   936     int rshift, gshift, bshift;
   937     int i;
   938 
   939     if (visual->class != DirectColor) {
   940         SDL_SetError("Window doesn't have DirectColor visual");
   941         return -1;
   942     }
   943 
   944     ncolors = visual->map_entries;
   945     colorcells = SDL_malloc(ncolors * sizeof(XColor));
   946     if (!colorcells) {
   947         SDL_OutOfMemory();
   948         return -1;
   949     }
   950 
   951     rshift = 0;
   952     rmask = visual->red_mask;
   953     while (0 == (rmask & 1)) {
   954         rshift++;
   955         rmask >>= 1;
   956     }
   957 
   958     gshift = 0;
   959     gmask = visual->green_mask;
   960     while (0 == (gmask & 1)) {
   961         gshift++;
   962         gmask >>= 1;
   963     }
   964 
   965     bshift = 0;
   966     bmask = visual->blue_mask;
   967     while (0 == (bmask & 1)) {
   968         bshift++;
   969         bmask >>= 1;
   970     }
   971 
   972     /* build the color table pixel values */
   973     for (i = 0; i < ncolors; i++) {
   974         Uint32 rbits = (rmask * i) / (ncolors - 1);
   975         Uint32 gbits = (gmask * i) / (ncolors - 1);
   976         Uint32 bbits = (bmask * i) / (ncolors - 1);
   977         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   978 
   979         colorcells[i].pixel = pix;
   980 
   981         colorcells[i].red = ramp[(0 * 256) + i];
   982         colorcells[i].green = ramp[(1 * 256) + i];
   983         colorcells[i].blue = ramp[(2 * 256) + i];
   984 
   985         colorcells[i].flags = DoRed | DoGreen | DoBlue;
   986     }
   987 
   988     XStoreColors(display, colormap, colorcells, ncolors);
   989     XFlush(display);
   990     SDL_free(colorcells);
   991 
   992     return 0;
   993 }
   994 
   995 void
   996 X11_SetWindowGrab(_THIS, SDL_Window * window)
   997 {
   998     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   999     Display *display = data->videodata->display;
  1000     SDL_bool oldstyle_fullscreen;
  1001 
  1002     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1003     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
  1004 
  1005     if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
  1006         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1007         /* Try to grab the mouse */
  1008         for (;;) {
  1009             int result =
  1010                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1011                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1012             if (result == GrabSuccess) {
  1013                 break;
  1014             }
  1015             SDL_Delay(100);
  1016         }
  1017 
  1018         /* Raise the window if we grab the mouse */
  1019         XRaiseWindow(display, data->xwindow);
  1020 
  1021         /* Now grab the keyboard */
  1022         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1023                       GrabModeAsync, CurrentTime);
  1024     } else {
  1025         XUngrabPointer(display, CurrentTime);
  1026         XUngrabKeyboard(display, CurrentTime);
  1027     }
  1028 }
  1029 
  1030 void
  1031 X11_DestroyWindow(_THIS, SDL_Window * window)
  1032 {
  1033     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1034     window->driverdata = NULL;
  1035 
  1036     if (data) {
  1037         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1038         Display *display = videodata->display;
  1039         int numwindows = videodata->numwindows;
  1040         SDL_WindowData **windowlist = videodata->windowlist;
  1041         int i;
  1042 
  1043         if (windowlist) {
  1044             for (i = 0; i < numwindows; ++i) {
  1045                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1046                     windowlist[i] = windowlist[numwindows - 1];
  1047                     windowlist[numwindows - 1] = NULL;
  1048                     videodata->numwindows--;
  1049                     break;
  1050                 }
  1051             }
  1052         }
  1053 #ifdef X_HAVE_UTF8_STRING
  1054         if (data->ic) {
  1055             XDestroyIC(data->ic);
  1056         }
  1057 #endif
  1058         if (data->created) {
  1059             XDestroyWindow(display, data->xwindow);
  1060             XFlush(display);
  1061         }
  1062         SDL_free(data);
  1063     }
  1064 }
  1065 
  1066 SDL_bool
  1067 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1068 {
  1069     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1070     Display *display = data->videodata->display;
  1071 
  1072     if (info->version.major == SDL_MAJOR_VERSION &&
  1073         info->version.minor == SDL_MINOR_VERSION) {
  1074         info->subsystem = SDL_SYSWM_X11;
  1075         info->info.x11.display = display;
  1076         info->info.x11.window = data->xwindow;
  1077         return SDL_TRUE;
  1078     } else {
  1079         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1080                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1081         return SDL_FALSE;
  1082     }
  1083 }
  1084 
  1085 #endif /* SDL_VIDEO_DRIVER_X11 */
  1086 
  1087 /* vi: set ts=4 sw=4 expandtab: */