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