src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 30 Jul 2010 00:55:00 -0700
changeset 4628 fad859023468
parent 4618 844b5ef4b149
child 4862 7b1d35d98294
permissions -rw-r--r--
When querying the display size for a fullscreen window, the display size is the size of the fullscreen video mode.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "../SDL_sysvideo.h"
    25 #include "../SDL_pixels_c.h"
    26 #include "../../events/SDL_keyboard_c.h"
    27 #include "../../events/SDL_mouse_c.h"
    28 
    29 #include "SDL_x11video.h"
    30 #include "SDL_x11mouse.h"
    31 #include "SDL_x11gamma.h"
    32 #include "../Xext/extensions/StdCmap.h"
    33 
    34 #ifdef SDL_VIDEO_DRIVER_PANDORA
    35 #include "SDL_x11opengles.h"
    36 #endif
    37 
    38 #include "SDL_timer.h"
    39 #include "SDL_syswm.h"
    40 
    41 #define _NET_WM_STATE_REMOVE    0l
    42 #define _NET_WM_STATE_ADD       1l
    43 #define _NET_WM_STATE_TOGGLE    2l
    44 
    45 static SDL_bool
    46 X11_IsWindowOldFullscreen(_THIS, SDL_Window * window)
    47 {
    48     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    49 
    50     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
    51     if ((window->flags & SDL_WINDOW_FULLSCREEN) && !videodata->net_wm) {
    52         return SDL_TRUE;
    53     } else {
    54         return SDL_FALSE;
    55     }
    56 }
    57 
    58 static SDL_bool
    59 X11_IsWindowMapped(_THIS, SDL_Window * window)
    60 {
    61     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    62     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    63     XWindowAttributes attr;
    64 
    65     XGetWindowAttributes(videodata->display, data->xwindow, &attr);
    66     if (attr.map_state != IsUnmapped) {
    67         return SDL_TRUE;
    68     } else {
    69         return SDL_FALSE;
    70     }
    71 }
    72 
    73 static int
    74 X11_GetWMStateProperty(_THIS, SDL_Window * window, Atom atoms[3])
    75 {
    76     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    77     int count = 0;
    78 
    79     if (window->flags & SDL_WINDOW_FULLSCREEN) {
    80         atoms[count++] = data->_NET_WM_STATE_FULLSCREEN;
    81     }
    82     if (window->flags & SDL_WINDOW_MAXIMIZED) {
    83         atoms[count++] = data->_NET_WM_STATE_MAXIMIZED_VERT;
    84         atoms[count++] = data->_NET_WM_STATE_MAXIMIZED_HORZ;
    85     }
    86     return count;
    87 }
    88 
    89 static void
    90 X11_GetDisplaySize(_THIS, SDL_Window * window, int *w, int *h)
    91 {
    92     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    93     SDL_DisplayData *displaydata =
    94         (SDL_DisplayData *) window->display->driverdata;
    95     XWindowAttributes attr;
    96 
    97     XGetWindowAttributes(data->display, RootWindow(data->display, displaydata->screen), &attr);
    98     if (window->flags & SDL_WINDOW_FULLSCREEN) {
    99         /* The bounds when this window is visible is the fullscreen mode */
   100         SDL_DisplayMode fullscreen_mode;
   101         if (SDL_GetWindowDisplayMode(window, &fullscreen_mode) == 0) {
   102             attr.width = fullscreen_mode.w;
   103             attr.height = fullscreen_mode.h;
   104         }
   105     }
   106     if (w) {
   107         *w = attr.width;
   108     }
   109     if (h) {
   110         *h = attr.height;
   111     }
   112 }
   113 
   114 static int
   115 SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
   116 {
   117     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   118     SDL_WindowData *data;
   119     int numwindows = videodata->numwindows;
   120     int windowlistlength = videodata->windowlistlength;
   121     SDL_WindowData **windowlist = videodata->windowlist;
   122 
   123     /* Allocate the window data */
   124     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   125     if (!data) {
   126         SDL_OutOfMemory();
   127         return -1;
   128     }
   129     data->window = window;
   130     data->xwindow = w;
   131 #ifdef X_HAVE_UTF8_STRING
   132     if (SDL_X11_HAVE_UTF8) {
   133         data->ic =
   134             pXCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w,
   135                        XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
   136                        XNResourceName, videodata->classname, XNResourceClass,
   137                        videodata->classname, NULL);
   138     }
   139 #endif
   140     data->created = created;
   141     data->videodata = videodata;
   142 
   143     /* Associate the data with the window */
   144 
   145     if (numwindows < windowlistlength) {
   146         windowlist[numwindows] = data;
   147         videodata->numwindows++;
   148     } else {
   149         windowlist =
   150             (SDL_WindowData **) SDL_realloc(windowlist,
   151                                             (numwindows +
   152                                              1) * sizeof(*windowlist));
   153         if (!windowlist) {
   154             SDL_OutOfMemory();
   155             SDL_free(data);
   156             return -1;
   157         }
   158         windowlist[numwindows] = data;
   159         videodata->numwindows++;
   160         videodata->windowlistlength++;
   161         videodata->windowlist = windowlist;
   162     }
   163 
   164     /* Fill in the SDL window with the window data */
   165     {
   166         XWindowAttributes attrib;
   167 
   168         XGetWindowAttributes(data->videodata->display, w, &attrib);
   169         window->x = attrib.x;
   170         window->y = attrib.y;
   171         window->w = attrib.width;
   172         window->h = attrib.height;
   173         if (attrib.map_state != IsUnmapped) {
   174             window->flags |= SDL_WINDOW_SHOWN;
   175         } else {
   176             window->flags &= ~SDL_WINDOW_SHOWN;
   177         }
   178     }
   179 
   180     {
   181         Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   182         Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   183         Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   184         Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   185         Atom actualType;
   186         int actualFormat;
   187         unsigned long i, numItems, bytesAfter;
   188         unsigned char *propertyValue = NULL;
   189         long maxLength = 1024;
   190 
   191         if (XGetWindowProperty(data->videodata->display, w, _NET_WM_STATE,
   192                                0l, maxLength, False, XA_ATOM, &actualType,
   193                                &actualFormat, &numItems, &bytesAfter,
   194                                &propertyValue) == Success) {
   195             Atom *atoms = (Atom *) propertyValue;
   196             int maximized = 0;
   197             int fullscreen = 0;
   198 
   199             for (i = 0; i < numItems; ++i) {
   200                 if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
   201                     maximized |= 1;
   202                 } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
   203                     maximized |= 2;
   204                 } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
   205                     fullscreen = 1;
   206                 }
   207             }
   208             if (maximized == 3) {
   209                 window->flags |= SDL_WINDOW_MAXIMIZED;
   210             }  else if (fullscreen == 1) {
   211                 window->flags |= SDL_WINDOW_FULLSCREEN;
   212             }
   213             XFree(propertyValue);
   214         }
   215     }
   216 
   217     /* FIXME: How can I tell?
   218        {
   219        DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   220        if (style & WS_VISIBLE) {
   221        if (style & (WS_BORDER | WS_THICKFRAME)) {
   222        window->flags &= ~SDL_WINDOW_BORDERLESS;
   223        } else {
   224        window->flags |= SDL_WINDOW_BORDERLESS;
   225        }
   226        if (style & WS_THICKFRAME) {
   227        window->flags |= SDL_WINDOW_RESIZABLE;
   228        } else {
   229        window->flags &= ~SDL_WINDOW_RESIZABLE;
   230        }
   231        if (style & WS_MINIMIZE) {
   232        window->flags |= SDL_WINDOW_MINIMIZED;
   233        } else {
   234        window->flags &= ~SDL_WINDOW_MINIMIZED;
   235        }
   236        }
   237        if (GetFocus() == hwnd) {
   238        int index = data->videodata->keyboard;
   239        window->flags |= SDL_WINDOW_INPUT_FOCUS;
   240        SDL_SetKeyboardFocus(index, data->window);
   241 
   242        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   243        RECT rect;
   244        GetClientRect(hwnd, &rect);
   245        ClientToScreen(hwnd, (LPPOINT) & rect);
   246        ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   247        ClipCursor(&rect);
   248        }
   249        }
   250      */
   251 
   252     /* All done! */
   253     window->driverdata = data;
   254     return 0;
   255 }
   256 
   257 int
   258 X11_CreateWindow(_THIS, SDL_Window * window)
   259 {
   260     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   261     SDL_DisplayData *displaydata =
   262         (SDL_DisplayData *) window->display->driverdata;
   263     Display *display = data->display;
   264     int screen = displaydata->screen;
   265     Visual *visual;
   266     int depth;
   267     XSetWindowAttributes xattr;
   268     int x, y;
   269     Window w;
   270     XSizeHints *sizehints;
   271     XWMHints *wmhints;
   272     XClassHint *classhints;
   273     SDL_bool oldstyle_fullscreen;
   274     Atom _NET_WM_WINDOW_TYPE;
   275     Atom _NET_WM_WINDOW_TYPE_NORMAL;
   276     int wmstate_count;
   277     Atom wmstate_atoms[3];
   278 
   279     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
   280     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
   281 
   282 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   283 /* FIXME
   284     if ( use_xinerama ) {
   285         x = xinerama_info.x_org;
   286         y = xinerama_info.y_org;
   287     }
   288 */
   289 #endif
   290 #ifdef SDL_VIDEO_OPENGL_GLX
   291     if (window->flags & SDL_WINDOW_OPENGL) {
   292         XVisualInfo *vinfo;
   293 
   294         vinfo = X11_GL_GetVisual(_this, display, screen);
   295         if (!vinfo) {
   296             return -1;
   297         }
   298         visual = vinfo->visual;
   299         depth = vinfo->depth;
   300         XFree(vinfo);
   301     } else
   302 #endif
   303 #ifdef SDL_VIDEO_DRIVER_PANDORA
   304     if (window->flags & SDL_WINDOW_OPENGL) {
   305         XVisualInfo *vinfo;
   306 
   307         vinfo = X11_GLES_GetVisual(_this, display, screen);
   308         if (!vinfo) {
   309             return -1;
   310         }
   311         visual = vinfo->visual;
   312         depth = vinfo->depth;
   313         XFree(vinfo);
   314     } else
   315 #endif
   316     {
   317         visual = displaydata->visual;
   318         depth = displaydata->depth;
   319     }
   320 
   321     if (oldstyle_fullscreen) {
   322         xattr.override_redirect = True;
   323     } else {
   324         xattr.override_redirect = False;
   325     }
   326     xattr.background_pixel = 0;
   327     xattr.border_pixel = 0;
   328 
   329     if (visual->class == PseudoColor) {
   330         printf("asking for PseudoColor\n");
   331 
   332 /*      Status status; */
   333         XColor *colorcells;
   334         Colormap colormap;
   335         Sint32 pix;
   336         Sint32 ncolors;
   337         Sint32 nbits;
   338         Sint32 rmax, gmax, bmax;
   339         Sint32 rwidth, gwidth, bwidth;
   340         Sint32 rmask, gmask, bmask;
   341         Sint32 rshift, gshift, bshift;
   342         Sint32 r, g, b;
   343 
   344         /* Is the colormap we need already registered in SDL? */
   345         if ((colormap =
   346             X11_LookupColormap(display, screen, visual->visualid))) {
   347             xattr.colormap = colormap;
   348 /*             printf("found existing colormap\n"); */
   349         } else {
   350             /* The colormap is not known to SDL so we will create it */
   351             colormap = XCreateColormap(display, RootWindow(display, screen),
   352                                        visual, AllocAll);
   353 /*             printf("colormap = %x\n", colormap); */
   354 
   355             /* If we can't create a colormap, then we must die */
   356             if (!colormap) {
   357                 SDL_SetError
   358                     ("Couldn't create window: Could not create writable colormap");
   359                 return -1;
   360             }
   361 
   362             /* OK, we got a colormap, now fill it in as best as we can */
   363 
   364             colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   365             if (NULL == colorcells) {
   366                 SDL_SetError("out of memory in X11_CreateWindow");
   367                 return -1;
   368             }
   369 
   370             ncolors = visual->map_entries;
   371             nbits = visual->bits_per_rgb;
   372 
   373 /* 	    printf("ncolors = %d nbits = %d\n", ncolors, nbits); */
   374 
   375             /* what if ncolors != (1 << nbits)? That can happen on a
   376                true PseudoColor display.  I'm assuming that we will
   377                always have ncolors == (1 << nbits) */
   378 
   379             /* I'm making a lot of assumptions here. */
   380 
   381             /* Compute the width of each field. If there is one extra
   382                bit, give it to green. If there are two extra bits give
   383                them to red and greed.  We can get extra bits when the
   384                number of bits per pixel is not a multiple of 3. For
   385                example when we have 16 bits per pixel and need a 5/6/5
   386                layout for the RGB fields */
   387 
   388             rwidth = (nbits / 3) + (((nbits % 3) == 2) ? 1 : 0);
   389             gwidth = (nbits / 3) + (((nbits % 3) >= 1) ? 1 : 0);
   390             bwidth = (nbits / 3);
   391 
   392             rshift = gwidth + bwidth;
   393             gshift = bwidth;
   394             bshift = 0;
   395 
   396             rmax = 1 << rwidth;
   397             gmax = 1 << gwidth;
   398             bmax = 1 << bwidth;
   399 
   400             rmask = rmax - 1;
   401             gmask = gmax - 1;
   402             bmask = bmax - 1;
   403 
   404 /*             printf("red   mask = %4x shift = %4d width = %d\n", rmask, rshift, rwidth); */
   405 /*             printf("green mask = %4x shift = %4d width = %d\n", gmask, gshift, gwidth); */
   406 /*             printf("blue  mask = %4x shift = %4d width = %d\n", bmask, bshift, bwidth); */
   407 
   408             /* build the color table pixel values */
   409             pix = 0;
   410             for (r = 0; r < rmax; r++) {
   411                 for (g = 0; g < gmax; g++) {
   412                     for (b = 0; b < bmax; b++) {
   413                         colorcells[pix].pixel =
   414                             (r << rshift) | (g << gshift) | (b << bshift);
   415                         colorcells[pix].red = (0xffff * r) / rmask;
   416                         colorcells[pix].green = (0xffff * g) / gmask;
   417                         colorcells[pix].blue = (0xffff * b) / bmask;
   418 /* 		  printf("%4x:%4x [%4x %4x %4x]\n",  */
   419 /* 			 pix,  */
   420 /* 			 colorcells[pix].pixel, */
   421 /* 			 colorcells[pix].red, */
   422 /* 			 colorcells[pix].green, */
   423 /* 			 colorcells[pix].blue); */
   424                         pix++;
   425                     }
   426                 }
   427             }
   428 
   429 /*             status = */
   430 /*                 XStoreColors(display, colormap, colorcells, ncolors); */
   431 
   432             xattr.colormap = colormap;
   433             X11_TrackColormap(display, screen, colormap, visual, NULL);
   434 
   435             SDL_free(colorcells);
   436         }
   437     } else if (visual->class == DirectColor) {
   438         Status status;
   439         XColor *colorcells;
   440         Colormap colormap;
   441         int i;
   442         int ncolors;
   443         int rmax, gmax, bmax;
   444         int rmask, gmask, bmask;
   445         int rshift, gshift, bshift;
   446 
   447         /* Is the colormap we need already registered in SDL? */
   448         if ((colormap =
   449              X11_LookupColormap(display, screen, visual->visualid))) {
   450             xattr.colormap = colormap;
   451 /*             printf("found existing colormap\n"); */
   452         } else {
   453             /* The colormap is not known to SDL so we will create it */
   454             colormap = XCreateColormap(display, RootWindow(display, screen),
   455                                        visual, AllocAll);
   456 /*             printf("colormap = %x\n", colormap); */
   457 
   458             /* If we can't create a colormap, then we must die */
   459             if (!colormap) {
   460                 SDL_SetError
   461                     ("Couldn't create window: Could not create writable colormap");
   462                 return -1;
   463             }
   464 
   465             /* OK, we got a colormap, now fill it in as best as we can */
   466             colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   467             if (NULL == colorcells) {
   468                 SDL_SetError("out of memory in X11_CreateWindow");
   469                 return -1;
   470             }
   471             ncolors = visual->map_entries;
   472             rmax = 0xffff;
   473             gmax = 0xffff;
   474             bmax = 0xffff;
   475 
   476             rshift = 0;
   477             rmask = visual->red_mask;
   478             while (0 == (rmask & 1)) {
   479                 rshift++;
   480                 rmask >>= 1;
   481             }
   482 
   483 /*             printf("rmask = %4x rshift = %4d\n", rmask, rshift); */
   484 
   485             gshift = 0;
   486             gmask = visual->green_mask;
   487             while (0 == (gmask & 1)) {
   488                 gshift++;
   489                 gmask >>= 1;
   490             }
   491 
   492 /*             printf("gmask = %4x gshift = %4d\n", gmask, gshift); */
   493 
   494             bshift = 0;
   495             bmask = visual->blue_mask;
   496             while (0 == (bmask & 1)) {
   497                 bshift++;
   498                 bmask >>= 1;
   499             }
   500 
   501 /*             printf("bmask = %4x bshift = %4d\n", bmask, bshift); */
   502 
   503             /* build the color table pixel values */
   504             for (i = 0; i < ncolors; i++) {
   505                 Uint32 red = (rmax * i) / (ncolors - 1);
   506                 Uint32 green = (gmax * i) / (ncolors - 1);
   507                 Uint32 blue = (bmax * i) / (ncolors - 1);
   508 
   509                 Uint32 rbits = (rmask * i) / (ncolors - 1);
   510                 Uint32 gbits = (gmask * i) / (ncolors - 1);
   511                 Uint32 bbits = (bmask * i) / (ncolors - 1);
   512 
   513                 Uint32 pix =
   514                     (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   515 
   516                 colorcells[i].pixel = pix;
   517 
   518                 colorcells[i].red = red;
   519                 colorcells[i].green = green;
   520                 colorcells[i].blue = blue;
   521 
   522                 colorcells[i].flags = DoRed | DoGreen | DoBlue;
   523 /* 		printf("%2d:%4x [%4x %4x %4x]\n", i, pix, red, green, blue); */
   524             }
   525 
   526             status =
   527                 XStoreColors(display, colormap, colorcells, ncolors);
   528 
   529             xattr.colormap = colormap;
   530             X11_TrackColormap(display, screen, colormap, visual, colorcells);
   531 
   532             SDL_free(colorcells);
   533         }
   534     } else {
   535         xattr.colormap =
   536             XCreateColormap(display, RootWindow(display, screen),
   537                             visual, AllocNone);
   538     }
   539 
   540     if (oldstyle_fullscreen
   541         || window->x == SDL_WINDOWPOS_CENTERED) {
   542         X11_GetDisplaySize(_this, window, &x, NULL);
   543         x = (x - window->w) / 2;
   544     } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
   545         x = 0;
   546     } else {
   547         x = window->x;
   548     }
   549     if (oldstyle_fullscreen
   550         || window->y == SDL_WINDOWPOS_CENTERED) {
   551         X11_GetDisplaySize(_this, window, NULL, &y);
   552         y = (y - window->h) / 2;
   553     } else if (window->y == SDL_WINDOWPOS_UNDEFINED) {
   554         y = 0;
   555     } else {
   556         y = window->y;
   557     }
   558 
   559     w = XCreateWindow(display, RootWindow(display, screen), x, y,
   560                       window->w, window->h, 0, depth, InputOutput, visual,
   561                       (CWOverrideRedirect | CWBackPixel | CWBorderPixel |
   562                        CWColormap), &xattr);
   563     if (!w) {
   564         SDL_SetError("Couldn't create window");
   565         return -1;
   566     }
   567 #if SDL_VIDEO_DRIVER_PANDORA
   568     /* Create the GLES window surface */
   569     _this->gles_data->egl_surface =
   570         _this->gles_data->eglCreateWindowSurface(_this->gles_data->
   571                                                  egl_display,
   572                                                  _this->gles_data->egl_config,
   573                                                  (NativeWindowType) w, NULL);
   574 
   575     if (_this->gles_data->egl_surface == EGL_NO_SURFACE) {
   576         SDL_SetError("Could not create GLES window surface");
   577         return -1;
   578     }
   579 #endif
   580 
   581     sizehints = XAllocSizeHints();
   582     if (sizehints) {
   583         if (!(window->flags & SDL_WINDOW_RESIZABLE)
   584             || oldstyle_fullscreen) {
   585             sizehints->min_width = sizehints->max_width = window->w;
   586             sizehints->min_height = sizehints->max_height = window->h;
   587             sizehints->flags = PMaxSize | PMinSize;
   588         }
   589         if (!oldstyle_fullscreen
   590             && window->x != SDL_WINDOWPOS_UNDEFINED
   591             && window->y != SDL_WINDOWPOS_UNDEFINED) {
   592             sizehints->x = x;
   593             sizehints->y = y;
   594             sizehints->flags |= USPosition;
   595         }
   596         XSetWMNormalHints(display, w, sizehints);
   597         XFree(sizehints);
   598     }
   599 
   600     if ((window->flags & SDL_WINDOW_BORDERLESS) || oldstyle_fullscreen) {
   601         SDL_bool set;
   602         Atom WM_HINTS;
   603 
   604         /* We haven't modified the window manager hints yet */
   605         set = SDL_FALSE;
   606 
   607         /* First try to set MWM hints */
   608         WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", True);
   609         if (WM_HINTS != None) {
   610             /* Hints used by Motif compliant window managers */
   611             struct
   612             {
   613                 unsigned long flags;
   614                 unsigned long functions;
   615                 unsigned long decorations;
   616                 long input_mode;
   617                 unsigned long status;
   618             } MWMHints = {
   619             (1L << 1), 0, 0, 0, 0};
   620 
   621             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   622                             PropModeReplace, (unsigned char *) &MWMHints,
   623                             sizeof(MWMHints) / 4);
   624             set = SDL_TRUE;
   625         }
   626         /* Now try to set KWM hints */
   627         WM_HINTS = XInternAtom(display, "KWM_WIN_DECORATION", True);
   628         if (WM_HINTS != None) {
   629             long KWMHints = 0;
   630 
   631             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   632                             PropModeReplace,
   633                             (unsigned char *) &KWMHints,
   634                             sizeof(KWMHints) / 4);
   635             set = SDL_TRUE;
   636         }
   637         /* Now try to set GNOME hints */
   638         WM_HINTS = XInternAtom(display, "_WIN_HINTS", True);
   639         if (WM_HINTS != None) {
   640             long GNOMEHints = 0;
   641 
   642             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   643                             PropModeReplace,
   644                             (unsigned char *) &GNOMEHints,
   645                             sizeof(GNOMEHints) / 4);
   646             set = SDL_TRUE;
   647         }
   648         /* Finally set the transient hints if necessary */
   649         if (!set) {
   650             XSetTransientForHint(display, w, RootWindow(display, screen));
   651         }
   652     } else {
   653         SDL_bool set;
   654         Atom WM_HINTS;
   655 
   656         /* We haven't modified the window manager hints yet */
   657         set = SDL_FALSE;
   658 
   659         /* First try to unset MWM hints */
   660         WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", True);
   661         if (WM_HINTS != None) {
   662             XDeleteProperty(display, w, WM_HINTS);
   663             set = SDL_TRUE;
   664         }
   665         /* Now try to unset KWM hints */
   666         WM_HINTS = XInternAtom(display, "KWM_WIN_DECORATION", True);
   667         if (WM_HINTS != None) {
   668             XDeleteProperty(display, w, WM_HINTS);
   669             set = SDL_TRUE;
   670         }
   671         /* Now try to unset GNOME hints */
   672         WM_HINTS = XInternAtom(display, "_WIN_HINTS", True);
   673         if (WM_HINTS != None) {
   674             XDeleteProperty(display, w, WM_HINTS);
   675             set = SDL_TRUE;
   676         }
   677         /* Finally unset the transient hints if necessary */
   678         if (!set) {
   679             XDeleteProperty(display, w, XA_WM_TRANSIENT_FOR);
   680         }
   681     }
   682 
   683     /* Set the input hints so we get keyboard input */
   684     wmhints = XAllocWMHints();
   685     if (wmhints) {
   686         wmhints->input = True;
   687         wmhints->flags = InputHint;
   688         XSetWMHints(display, w, wmhints);
   689         XFree(wmhints);
   690     }
   691 
   692     /* Set the class hints so we can get an icon (AfterStep) */
   693     classhints = XAllocClassHint();
   694     if (classhints != NULL) {
   695         classhints->res_name = data->classname;
   696         classhints->res_class = data->classname;
   697         XSetClassHint(display, w, classhints);
   698         XFree(classhints);
   699     }
   700 
   701     /* Set the window manager state */
   702     wmstate_count = X11_GetWMStateProperty(_this, window, wmstate_atoms);
   703     if (wmstate_count > 0) {
   704         XChangeProperty(display, w, data->_NET_WM_STATE, XA_ATOM, 32,
   705                         PropModeReplace,
   706                         (unsigned char *)wmstate_atoms, wmstate_count);
   707     } else {
   708         XDeleteProperty(display, w, data->_NET_WM_STATE);
   709     }
   710 
   711     /* Let the window manager know we're a "normal" window */
   712     _NET_WM_WINDOW_TYPE = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
   713     _NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
   714     XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
   715                     PropModeReplace,
   716                     (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1);
   717 
   718     /* Allow the window to be deleted by the window manager */
   719     XSetWMProtocols(display, w, &data->WM_DELETE_WINDOW, 1);
   720 
   721     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   722         XDestroyWindow(display, w);
   723         return -1;
   724     }
   725 #ifdef X_HAVE_UTF8_STRING
   726     {
   727         Uint32 fevent = 0;
   728         pXGetICValues(((SDL_WindowData *) window->driverdata)->ic,
   729                       XNFilterEvents, &fevent, NULL);
   730         XSelectInput(display, w,
   731                      (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   732                       ExposureMask | ButtonPressMask | ButtonReleaseMask |
   733                       PointerMotionMask | KeyPressMask | KeyReleaseMask |
   734                       PropertyChangeMask | StructureNotifyMask |
   735                       KeymapStateMask | fevent));
   736     }
   737 #else
   738     {
   739         XSelectInput(display, w,
   740                      (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   741                       ExposureMask | ButtonPressMask | ButtonReleaseMask |
   742                       PointerMotionMask | KeyPressMask | KeyReleaseMask |
   743                       PropertyChangeMask | StructureNotifyMask |
   744                       KeymapStateMask));
   745     }
   746 #endif
   747 
   748     return 0;
   749 }
   750 
   751 int
   752 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   753 {
   754     Window w = (Window) data;
   755 
   756     window->title = X11_GetWindowTitle(_this, w);
   757 
   758     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   759         return -1;
   760     }
   761     return 0;
   762 }
   763 
   764 char *
   765 X11_GetWindowTitle(_THIS, Window xwindow)
   766 {
   767     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   768     Display *display = data->display;
   769     int status, real_format;
   770     Atom real_type;
   771     unsigned long items_read, items_left;
   772     unsigned char *propdata;
   773     char *title = NULL;
   774 
   775     status = XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
   776                 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
   777                 &items_read, &items_left, &propdata);
   778     if (status == Success) {
   779         title = SDL_strdup(SDL_static_cast(char*, propdata));
   780         XFree(propdata);
   781     } else {
   782         status = XGetWindowProperty(display, xwindow, XA_WM_NAME,
   783                     0L, 8192L, False, XA_STRING, &real_type, &real_format,
   784                     &items_read, &items_left, &propdata);
   785         if (status == Success) {
   786             title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
   787         } else {
   788             title = SDL_strdup("");
   789         }
   790     }
   791     return title;
   792 }
   793 
   794 void
   795 X11_SetWindowTitle(_THIS, SDL_Window * window)
   796 {
   797     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   798     Display *display = data->videodata->display;
   799     XTextProperty titleprop, iconprop;
   800     Status status;
   801     const char *title = window->title;
   802     const char *icon = NULL;
   803 
   804 #ifdef X_HAVE_UTF8_STRING
   805     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   806     Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME;
   807 #endif
   808 
   809     if (title != NULL) {
   810         char *title_locale = SDL_iconv_utf8_locale(title);
   811         if (!title_locale) {
   812             SDL_OutOfMemory();
   813             return;
   814         }
   815         status = XStringListToTextProperty(&title_locale, 1, &titleprop);
   816         SDL_free(title_locale);
   817         if (status) {
   818             XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   819             XFree(titleprop.value);
   820         }
   821 #ifdef X_HAVE_UTF8_STRING
   822         if (SDL_X11_HAVE_UTF8) {
   823             status =
   824                 Xutf8TextListToTextProperty(display, (char **) &title, 1,
   825                                             XUTF8StringStyle, &titleprop);
   826             if (status == Success) {
   827                 XSetTextProperty(display, data->xwindow, &titleprop,
   828                                  _NET_WM_NAME);
   829                 XFree(titleprop.value);
   830             }
   831         }
   832 #endif
   833     }
   834     if (icon != NULL) {
   835         char *icon_locale = SDL_iconv_utf8_locale(icon);
   836         if (!icon_locale) {
   837             SDL_OutOfMemory();
   838             return;
   839         }
   840         status = XStringListToTextProperty(&icon_locale, 1, &iconprop);
   841         SDL_free(icon_locale);
   842         if (status) {
   843             XSetTextProperty(display, data->xwindow, &iconprop,
   844                              XA_WM_ICON_NAME);
   845             XFree(iconprop.value);
   846         }
   847 #ifdef X_HAVE_UTF8_STRING
   848         if (SDL_X11_HAVE_UTF8) {
   849             status =
   850                 Xutf8TextListToTextProperty(display, (char **) &icon, 1,
   851                                             XUTF8StringStyle, &iconprop);
   852             if (status == Success) {
   853                 XSetTextProperty(display, data->xwindow, &iconprop,
   854                                  _NET_WM_ICON_NAME);
   855                 XFree(iconprop.value);
   856             }
   857         }
   858 #endif
   859     }
   860 }
   861 
   862 void
   863 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   864 {
   865     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   866     Display *display = data->videodata->display;
   867     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   868 
   869     if (icon) {
   870         SDL_PixelFormat format;
   871         SDL_Surface *surface;
   872         int propsize;
   873         long *propdata;
   874 
   875         /* Convert the icon to ARGB for modern window managers */
   876         SDL_InitFormat(&format, 32, 0x00FF0000, 0x0000FF00, 0x000000FF,
   877                        0xFF000000);
   878         surface = SDL_ConvertSurface(icon, &format, 0);
   879         if (!surface) {
   880             return;
   881         }
   882 
   883         /* Set the _NET_WM_ICON property */
   884         propsize = 2 + (icon->w * icon->h);
   885         propdata = SDL_malloc(propsize * sizeof(long));
   886         if (propdata) {
   887             int x, y;
   888             Uint32 *src;
   889             long *dst;
   890 
   891             propdata[0] = icon->w;
   892             propdata[1] = icon->h;
   893             dst = &propdata[2];
   894             for (y = 0; y < icon->h; ++y) {
   895                 src = (Uint32*)((Uint8*)surface->pixels + y * surface->pitch);
   896                 for (x = 0; x < icon->w; ++x) {
   897                     *dst++ = *src++;
   898                 }
   899             }
   900             XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   901                             32, PropModeReplace, (unsigned char *) propdata,
   902                             propsize);
   903         }
   904         SDL_FreeSurface(surface);
   905     } else {
   906         XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   907     }
   908 }
   909 
   910 void
   911 X11_SetWindowPosition(_THIS, SDL_Window * window)
   912 {
   913     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   914     Display *display = data->videodata->display;
   915     SDL_bool oldstyle_fullscreen;
   916     int x, y;
   917 
   918     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
   919     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
   920 
   921     if (oldstyle_fullscreen
   922         || window->x == SDL_WINDOWPOS_CENTERED) {
   923         X11_GetDisplaySize(_this, window, &x, NULL);
   924         x = (x - window->w) / 2;
   925     } else {
   926         x = window->x;
   927     }
   928     if (oldstyle_fullscreen
   929         || window->y == SDL_WINDOWPOS_CENTERED) {
   930         X11_GetDisplaySize(_this, window, NULL, &y);
   931         y = (y - window->h) / 2;
   932     } else {
   933         y = window->y;
   934     }
   935     XMoveWindow(display, data->xwindow, x, y);
   936 }
   937 
   938 void
   939 X11_SetWindowSize(_THIS, SDL_Window * window)
   940 {
   941     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   942     Display *display = data->videodata->display;
   943 
   944     XResizeWindow(display, data->xwindow, window->w, window->h);
   945 }
   946 
   947 void
   948 X11_ShowWindow(_THIS, SDL_Window * window)
   949 {
   950     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   951     Display *display = data->videodata->display;
   952 
   953     XMapRaised(display, data->xwindow);
   954 }
   955 
   956 void
   957 X11_HideWindow(_THIS, SDL_Window * window)
   958 {
   959     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   960     Display *display = data->videodata->display;
   961 
   962     XUnmapWindow(display, data->xwindow);
   963 }
   964 
   965 void
   966 X11_RaiseWindow(_THIS, SDL_Window * window)
   967 {
   968     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   969     Display *display = data->videodata->display;
   970 
   971     XRaiseWindow(display, data->xwindow);
   972 }
   973 
   974 static void
   975 X11_SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   976 {
   977     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   978     SDL_DisplayData *displaydata =
   979         (SDL_DisplayData *) window->display->driverdata;
   980     Display *display = data->videodata->display;
   981     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   982     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   983     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   984     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   985 
   986     if (X11_IsWindowMapped(_this, window)) {
   987         XEvent e;
   988 
   989         SDL_zero(e);
   990         e.xany.type = ClientMessage;
   991         e.xclient.message_type = _NET_WM_STATE;
   992         e.xclient.format = 32;
   993         e.xclient.window = data->xwindow;
   994         e.xclient.data.l[0] =
   995             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   996         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
   997         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
   998         e.xclient.data.l[3] = 0l;
   999 
  1000         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1001                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1002     } else {
  1003         int count = 0;
  1004         Atom atoms[3];
  1005 
  1006         if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1007             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
  1008         }
  1009         if (maximized) {
  1010             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
  1011             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
  1012         }
  1013         if (count > 0) {
  1014             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
  1015                             PropModeReplace, (unsigned char *)atoms, count);
  1016         } else {
  1017             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
  1018         }
  1019     }
  1020 }
  1021 
  1022 void
  1023 X11_MaximizeWindow(_THIS, SDL_Window * window)
  1024 {
  1025     X11_SetWindowMaximized(_this, window, SDL_TRUE);
  1026 }
  1027 
  1028 void
  1029 X11_MinimizeWindow(_THIS, SDL_Window * window)
  1030 {
  1031     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1032     SDL_DisplayData *displaydata =
  1033         (SDL_DisplayData *) window->display->driverdata;
  1034     Display *display = data->videodata->display;
  1035  
  1036     XIconifyWindow(display, data->xwindow, displaydata->screen);
  1037 }
  1038 
  1039 void
  1040 X11_RestoreWindow(_THIS, SDL_Window * window)
  1041 {
  1042     X11_SetWindowMaximized(_this, window, SDL_FALSE);
  1043     X11_ShowWindow(_this, window);
  1044 }
  1045 
  1046 void
  1047 X11_SetWindowGrab(_THIS, SDL_Window * window)
  1048 {
  1049     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1050     Display *display = data->videodata->display;
  1051     SDL_bool oldstyle_fullscreen;
  1052 
  1053     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1054     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
  1055 
  1056     if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
  1057         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1058         /* Try to grab the mouse */
  1059         for (;;) {
  1060             int result =
  1061                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1062                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1063             if (result == GrabSuccess) {
  1064                 break;
  1065             }
  1066             SDL_Delay(100);
  1067         }
  1068 
  1069         /* Raise the window if we grab the mouse */
  1070         XRaiseWindow(display, data->xwindow);
  1071 
  1072         /* Now grab the keyboard */
  1073         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1074                       GrabModeAsync, CurrentTime);
  1075     } else {
  1076         XUngrabPointer(display, CurrentTime);
  1077         XUngrabKeyboard(display, CurrentTime);
  1078     }
  1079 }
  1080 
  1081 void
  1082 X11_DestroyWindow(_THIS, SDL_Window * window)
  1083 {
  1084     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1085     window->driverdata = NULL;
  1086 
  1087     if (data) {
  1088         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1089         Display *display = videodata->display;
  1090         int numwindows = videodata->numwindows;
  1091         SDL_WindowData **windowlist = videodata->windowlist;
  1092         int i;
  1093 
  1094         if (windowlist) {
  1095             for (i = 0; i < numwindows; ++i) {
  1096                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1097                     windowlist[i] = windowlist[numwindows - 1];
  1098                     windowlist[numwindows - 1] = NULL;
  1099                     videodata->numwindows--;
  1100                     break;
  1101                 }
  1102             }
  1103         }
  1104 #ifdef X_HAVE_UTF8_STRING
  1105         if (data->ic) {
  1106             XDestroyIC(data->ic);
  1107         }
  1108 #endif
  1109         if (data->created) {
  1110             XDestroyWindow(display, data->xwindow);
  1111         }
  1112         SDL_free(data);
  1113     }
  1114 }
  1115 
  1116 SDL_bool
  1117 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1118 {
  1119     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1120     Display *display = data->videodata->display;
  1121 
  1122     if (info->version.major == SDL_MAJOR_VERSION &&
  1123         info->version.minor == SDL_MINOR_VERSION) {
  1124         info->subsystem = SDL_SYSWM_X11;
  1125         info->info.x11.display = display;
  1126         info->info.x11.window = data->xwindow;
  1127         return SDL_TRUE;
  1128     } else {
  1129         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1130                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1131         return SDL_FALSE;
  1132     }
  1133 }
  1134 
  1135 /* vi: set ts=4 sw=4 expandtab: */