src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 21 Jul 2010 21:53:41 -0700
changeset 4566 40c833d951a1
parent 4555 9e73d17638d3
child 4618 844b5ef4b149
permissions -rw-r--r--
Fixed memory corruption on AMD64
     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             XDeleteProperty(display, w, XA_WM_TRANSIENT_FOR);
   674         }
   675     }
   676 
   677     /* Set the input hints so we get keyboard input */
   678     wmhints = XAllocWMHints();
   679     if (wmhints) {
   680         wmhints->input = True;
   681         wmhints->flags = InputHint;
   682         XSetWMHints(display, w, wmhints);
   683         XFree(wmhints);
   684     }
   685 
   686     /* Set the class hints so we can get an icon (AfterStep) */
   687     classhints = XAllocClassHint();
   688     if (classhints != NULL) {
   689         classhints->res_name = data->classname;
   690         classhints->res_class = data->classname;
   691         XSetClassHint(display, w, classhints);
   692         XFree(classhints);
   693     }
   694 
   695     /* Set the window manager state */
   696     wmstate_count = X11_GetWMStateProperty(_this, window, wmstate_atoms);
   697     if (wmstate_count > 0) {
   698         XChangeProperty(display, w, data->_NET_WM_STATE, XA_ATOM, 32,
   699                         PropModeReplace,
   700                         (unsigned char *)wmstate_atoms, wmstate_count);
   701     } else {
   702         XDeleteProperty(display, w, data->_NET_WM_STATE);
   703     }
   704 
   705     /* Let the window manager know we're a "normal" window */
   706     _NET_WM_WINDOW_TYPE = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
   707     _NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
   708     XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
   709                     PropModeReplace,
   710                     (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1);
   711 
   712     /* Allow the window to be deleted by the window manager */
   713     XSetWMProtocols(display, w, &data->WM_DELETE_WINDOW, 1);
   714 
   715     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   716         XDestroyWindow(display, w);
   717         return -1;
   718     }
   719 #ifdef X_HAVE_UTF8_STRING
   720     {
   721         Uint32 fevent = 0;
   722         pXGetICValues(((SDL_WindowData *) window->driverdata)->ic,
   723                       XNFilterEvents, &fevent, NULL);
   724         XSelectInput(display, w,
   725                      (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   726                       ExposureMask | ButtonPressMask | ButtonReleaseMask |
   727                       PointerMotionMask | KeyPressMask | KeyReleaseMask |
   728                       PropertyChangeMask | StructureNotifyMask |
   729                       KeymapStateMask | fevent));
   730     }
   731 #else
   732     {
   733         XSelectInput(display, w,
   734                      (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   735                       ExposureMask | ButtonPressMask | ButtonReleaseMask |
   736                       PointerMotionMask | KeyPressMask | KeyReleaseMask |
   737                       PropertyChangeMask | StructureNotifyMask |
   738                       KeymapStateMask));
   739     }
   740 #endif
   741 
   742     return 0;
   743 }
   744 
   745 int
   746 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   747 {
   748     Window w = (Window) data;
   749 
   750     window->title = X11_GetWindowTitle(_this, w);
   751 
   752     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   753         return -1;
   754     }
   755     return 0;
   756 }
   757 
   758 char *
   759 X11_GetWindowTitle(_THIS, Window xwindow)
   760 {
   761     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   762     Display *display = data->display;
   763     int status, real_format;
   764     Atom real_type;
   765     unsigned long items_read, items_left;
   766     unsigned char *propdata;
   767     char *title = NULL;
   768 
   769     status = XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
   770                 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
   771                 &items_read, &items_left, &propdata);
   772     if (status == Success) {
   773         title = SDL_strdup(SDL_static_cast(char*, propdata));
   774         XFree(propdata);
   775     } else {
   776         status = XGetWindowProperty(display, xwindow, XA_WM_NAME,
   777                     0L, 8192L, False, XA_STRING, &real_type, &real_format,
   778                     &items_read, &items_left, &propdata);
   779         if (status == Success) {
   780             title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
   781         } else {
   782             title = SDL_strdup("");
   783         }
   784     }
   785     return title;
   786 }
   787 
   788 void
   789 X11_SetWindowTitle(_THIS, SDL_Window * window)
   790 {
   791     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   792     Display *display = data->videodata->display;
   793     XTextProperty titleprop, iconprop;
   794     Status status;
   795     const char *title = window->title;
   796     const char *icon = NULL;
   797 
   798 #ifdef X_HAVE_UTF8_STRING
   799     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   800     Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME;
   801 #endif
   802 
   803     if (title != NULL) {
   804         char *title_locale = SDL_iconv_utf8_locale(title);
   805         if (!title_locale) {
   806             SDL_OutOfMemory();
   807             return;
   808         }
   809         status = XStringListToTextProperty(&title_locale, 1, &titleprop);
   810         SDL_free(title_locale);
   811         if (status) {
   812             XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   813             XFree(titleprop.value);
   814         }
   815 #ifdef X_HAVE_UTF8_STRING
   816         if (SDL_X11_HAVE_UTF8) {
   817             status =
   818                 Xutf8TextListToTextProperty(display, (char **) &title, 1,
   819                                             XUTF8StringStyle, &titleprop);
   820             if (status == Success) {
   821                 XSetTextProperty(display, data->xwindow, &titleprop,
   822                                  _NET_WM_NAME);
   823                 XFree(titleprop.value);
   824             }
   825         }
   826 #endif
   827     }
   828     if (icon != NULL) {
   829         char *icon_locale = SDL_iconv_utf8_locale(icon);
   830         if (!icon_locale) {
   831             SDL_OutOfMemory();
   832             return;
   833         }
   834         status = XStringListToTextProperty(&icon_locale, 1, &iconprop);
   835         SDL_free(icon_locale);
   836         if (status) {
   837             XSetTextProperty(display, data->xwindow, &iconprop,
   838                              XA_WM_ICON_NAME);
   839             XFree(iconprop.value);
   840         }
   841 #ifdef X_HAVE_UTF8_STRING
   842         if (SDL_X11_HAVE_UTF8) {
   843             status =
   844                 Xutf8TextListToTextProperty(display, (char **) &icon, 1,
   845                                             XUTF8StringStyle, &iconprop);
   846             if (status == Success) {
   847                 XSetTextProperty(display, data->xwindow, &iconprop,
   848                                  _NET_WM_ICON_NAME);
   849                 XFree(iconprop.value);
   850             }
   851         }
   852 #endif
   853     }
   854 }
   855 
   856 void
   857 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   858 {
   859     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   860     Display *display = data->videodata->display;
   861     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   862 
   863     if (icon) {
   864         SDL_PixelFormat format;
   865         SDL_Surface *surface;
   866         int propsize;
   867         long *propdata;
   868 
   869         /* Convert the icon to ARGB for modern window managers */
   870         SDL_InitFormat(&format, 32, 0x00FF0000, 0x0000FF00, 0x000000FF,
   871                        0xFF000000);
   872         surface = SDL_ConvertSurface(icon, &format, 0);
   873         if (!surface) {
   874             return;
   875         }
   876 
   877         /* Set the _NET_WM_ICON property */
   878         propsize = 2 + (icon->w * icon->h);
   879         propdata = SDL_malloc(propsize * sizeof(long));
   880         if (propdata) {
   881             int x, y;
   882             Uint32 *src;
   883             long *dst;
   884 
   885             propdata[0] = icon->w;
   886             propdata[1] = icon->h;
   887             dst = &propdata[2];
   888             for (y = 0; y < icon->h; ++y) {
   889                 src = (Uint32*)((Uint8*)surface->pixels + y * surface->pitch);
   890                 for (x = 0; x < icon->w; ++x) {
   891                     *dst++ = *src++;
   892                 }
   893             }
   894             XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   895                             32, PropModeReplace, (unsigned char *) propdata,
   896                             propsize);
   897         }
   898         SDL_FreeSurface(surface);
   899     } else {
   900         XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   901     }
   902 }
   903 
   904 void
   905 X11_SetWindowPosition(_THIS, SDL_Window * window)
   906 {
   907     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   908     Display *display = data->videodata->display;
   909     SDL_bool oldstyle_fullscreen;
   910     int x, y;
   911 
   912     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
   913     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
   914 
   915     if (oldstyle_fullscreen
   916         || window->x == SDL_WINDOWPOS_CENTERED) {
   917         X11_GetDisplaySize(_this, window, &x, NULL);
   918         x = (x - window->w) / 2;
   919     } else {
   920         x = window->x;
   921     }
   922     if (oldstyle_fullscreen
   923         || window->y == SDL_WINDOWPOS_CENTERED) {
   924         X11_GetDisplaySize(_this, window, NULL, &y);
   925         y = (y - window->h) / 2;
   926     } else {
   927         y = window->y;
   928     }
   929     XMoveWindow(display, data->xwindow, x, y);
   930 }
   931 
   932 void
   933 X11_SetWindowSize(_THIS, SDL_Window * window)
   934 {
   935     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   936     Display *display = data->videodata->display;
   937 
   938     XResizeWindow(display, data->xwindow, window->w, window->h);
   939 }
   940 
   941 void
   942 X11_ShowWindow(_THIS, SDL_Window * window)
   943 {
   944     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   945     Display *display = data->videodata->display;
   946 
   947     XMapRaised(display, data->xwindow);
   948 }
   949 
   950 void
   951 X11_HideWindow(_THIS, SDL_Window * window)
   952 {
   953     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   954     Display *display = data->videodata->display;
   955 
   956     XUnmapWindow(display, data->xwindow);
   957 }
   958 
   959 void
   960 X11_RaiseWindow(_THIS, SDL_Window * window)
   961 {
   962     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   963     Display *display = data->videodata->display;
   964 
   965     XRaiseWindow(display, data->xwindow);
   966 }
   967 
   968 static void
   969 X11_SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   970 {
   971     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   972     SDL_DisplayData *displaydata =
   973         (SDL_DisplayData *) window->display->driverdata;
   974     Display *display = data->videodata->display;
   975     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   976     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   977     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   978     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   979 
   980     if (X11_IsWindowMapped(_this, window)) {
   981         XEvent e;
   982 
   983         SDL_zero(e);
   984         e.xany.type = ClientMessage;
   985         e.xclient.message_type = _NET_WM_STATE;
   986         e.xclient.format = 32;
   987         e.xclient.window = data->xwindow;
   988         e.xclient.data.l[0] =
   989             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   990         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
   991         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
   992         e.xclient.data.l[3] = 0l;
   993 
   994         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   995                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   996     } else {
   997         int count = 0;
   998         Atom atoms[3];
   999 
  1000         if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1001             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
  1002         }
  1003         if (maximized) {
  1004             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
  1005             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
  1006         }
  1007         if (count > 0) {
  1008             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
  1009                             PropModeReplace, (unsigned char *)atoms, count);
  1010         } else {
  1011             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
  1012         }
  1013     }
  1014 }
  1015 
  1016 void
  1017 X11_MaximizeWindow(_THIS, SDL_Window * window)
  1018 {
  1019     X11_SetWindowMaximized(_this, window, SDL_TRUE);
  1020 }
  1021 
  1022 void
  1023 X11_MinimizeWindow(_THIS, SDL_Window * window)
  1024 {
  1025     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1026     SDL_DisplayData *displaydata =
  1027         (SDL_DisplayData *) window->display->driverdata;
  1028     Display *display = data->videodata->display;
  1029  
  1030     XIconifyWindow(display, data->xwindow, displaydata->screen);
  1031 }
  1032 
  1033 void
  1034 X11_RestoreWindow(_THIS, SDL_Window * window)
  1035 {
  1036     X11_SetWindowMaximized(_this, window, SDL_FALSE);
  1037     X11_ShowWindow(_this, window);
  1038 }
  1039 
  1040 void
  1041 X11_SetWindowGrab(_THIS, SDL_Window * window)
  1042 {
  1043     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1044     Display *display = data->videodata->display;
  1045     SDL_bool oldstyle_fullscreen;
  1046 
  1047     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1048     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
  1049 
  1050     if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
  1051         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1052         /* Try to grab the mouse */
  1053         for (;;) {
  1054             int result =
  1055                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1056                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1057             if (result == GrabSuccess) {
  1058                 break;
  1059             }
  1060             SDL_Delay(100);
  1061         }
  1062 
  1063         /* Raise the window if we grab the mouse */
  1064         XRaiseWindow(display, data->xwindow);
  1065 
  1066         /* Now grab the keyboard */
  1067         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1068                       GrabModeAsync, CurrentTime);
  1069     } else {
  1070         XUngrabPointer(display, CurrentTime);
  1071         XUngrabKeyboard(display, CurrentTime);
  1072     }
  1073 }
  1074 
  1075 void
  1076 X11_DestroyWindow(_THIS, SDL_Window * window)
  1077 {
  1078     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1079     window->driverdata = NULL;
  1080 
  1081     if (data) {
  1082         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1083         Display *display = videodata->display;
  1084         int numwindows = videodata->numwindows;
  1085         SDL_WindowData **windowlist = videodata->windowlist;
  1086         int i;
  1087 
  1088         if (windowlist) {
  1089             for (i = 0; i < numwindows; ++i) {
  1090                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1091                     windowlist[i] = windowlist[numwindows - 1];
  1092                     windowlist[numwindows - 1] = NULL;
  1093                     videodata->numwindows--;
  1094                     break;
  1095                 }
  1096             }
  1097         }
  1098 #ifdef X_HAVE_UTF8_STRING
  1099         if (data->ic) {
  1100             XDestroyIC(data->ic);
  1101         }
  1102 #endif
  1103         if (data->created) {
  1104             XDestroyWindow(display, data->xwindow);
  1105         }
  1106         SDL_free(data);
  1107     }
  1108 }
  1109 
  1110 SDL_bool
  1111 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1112 {
  1113     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1114     Display *display = data->videodata->display;
  1115 
  1116     if (info->version.major == SDL_MAJOR_VERSION &&
  1117         info->version.minor == SDL_MINOR_VERSION) {
  1118         info->subsystem = SDL_SYSWM_X11;
  1119         info->info.x11.display = display;
  1120         info->info.x11.window = data->xwindow;
  1121         return SDL_TRUE;
  1122     } else {
  1123         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1124                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1125         return SDL_FALSE;
  1126     }
  1127 }
  1128 
  1129 /* vi: set ts=4 sw=4 expandtab: */