src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 17 Jul 2010 18:44:34 -0700
changeset 4528 f06faa886423
parent 4524 a256e1dadf3f
child 4555 9e73d17638d3
permissions -rw-r--r--
Fixed bug 1022

Fixed the X11 icon on 64-bit systems
     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         long *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             int x, y;
   883             Uint32 *src;
   884             long *dst;
   885 
   886             propdata[0] = icon->w;
   887             propdata[1] = icon->h;
   888             dst = &propdata[2];
   889             for (y = 0; y < icon->h; ++y) {
   890                 src = (Uint32*)((Uint8*)surface->pixels + y * surface->pitch);
   891                 for (x = 0; x < icon->w; ++x) {
   892                     *dst++ = *src++;
   893                 }
   894             }
   895             XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   896                             32, PropModeReplace, (unsigned char *) propdata,
   897                             propsize);
   898         }
   899         SDL_FreeSurface(surface);
   900     } else {
   901         XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   902     }
   903 }
   904 
   905 void
   906 X11_SetWindowPosition(_THIS, SDL_Window * window)
   907 {
   908     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   909     Display *display = data->videodata->display;
   910     SDL_bool oldstyle_fullscreen;
   911     int x, y;
   912 
   913     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
   914     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
   915 
   916     if (oldstyle_fullscreen
   917         || window->x == SDL_WINDOWPOS_CENTERED) {
   918         X11_GetDisplaySize(_this, window, &x, NULL);
   919         x = (x - window->w) / 2;
   920     } else {
   921         x = window->x;
   922     }
   923     if (oldstyle_fullscreen
   924         || window->y == SDL_WINDOWPOS_CENTERED) {
   925         X11_GetDisplaySize(_this, window, NULL, &y);
   926         y = (y - window->h) / 2;
   927     } else {
   928         y = window->y;
   929     }
   930     XMoveWindow(display, data->xwindow, x, y);
   931 }
   932 
   933 void
   934 X11_SetWindowSize(_THIS, SDL_Window * window)
   935 {
   936     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   937     Display *display = data->videodata->display;
   938 
   939     XResizeWindow(display, data->xwindow, window->w, window->h);
   940 }
   941 
   942 void
   943 X11_ShowWindow(_THIS, SDL_Window * window)
   944 {
   945     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   946     Display *display = data->videodata->display;
   947 
   948     XMapRaised(display, data->xwindow);
   949 }
   950 
   951 void
   952 X11_HideWindow(_THIS, SDL_Window * window)
   953 {
   954     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   955     Display *display = data->videodata->display;
   956 
   957     XUnmapWindow(display, data->xwindow);
   958 }
   959 
   960 void
   961 X11_RaiseWindow(_THIS, SDL_Window * window)
   962 {
   963     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   964     Display *display = data->videodata->display;
   965 
   966     XRaiseWindow(display, data->xwindow);
   967 }
   968 
   969 static void
   970 X11_SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   971 {
   972     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   973     SDL_DisplayData *displaydata =
   974         (SDL_DisplayData *) window->display->driverdata;
   975     Display *display = data->videodata->display;
   976     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   977     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   978     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   979     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   980 
   981     if (X11_IsWindowMapped(_this, window)) {
   982         XEvent e;
   983 
   984         SDL_zero(e);
   985         e.xany.type = ClientMessage;
   986         e.xclient.message_type = _NET_WM_STATE;
   987         e.xclient.format = 32;
   988         e.xclient.window = data->xwindow;
   989         e.xclient.data.l[0] =
   990             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   991         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
   992         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
   993         e.xclient.data.l[3] = 0l;
   994 
   995         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   996                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   997     } else {
   998         int count = 0;
   999         Atom atoms[3];
  1000 
  1001         if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1002             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
  1003         }
  1004         if (maximized) {
  1005             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
  1006             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
  1007         }
  1008         if (count > 0) {
  1009             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
  1010                             PropModeReplace, (unsigned char *)atoms, count);
  1011         } else {
  1012             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
  1013         }
  1014     }
  1015 }
  1016 
  1017 void
  1018 X11_MaximizeWindow(_THIS, SDL_Window * window)
  1019 {
  1020     X11_SetWindowMaximized(_this, window, SDL_TRUE);
  1021 }
  1022 
  1023 void
  1024 X11_MinimizeWindow(_THIS, SDL_Window * window)
  1025 {
  1026     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1027     SDL_DisplayData *displaydata =
  1028         (SDL_DisplayData *) window->display->driverdata;
  1029     Display *display = data->videodata->display;
  1030  
  1031     XIconifyWindow(display, data->xwindow, displaydata->screen);
  1032 }
  1033 
  1034 void
  1035 X11_RestoreWindow(_THIS, SDL_Window * window)
  1036 {
  1037     X11_SetWindowMaximized(_this, window, SDL_FALSE);
  1038     X11_ShowWindow(_this, window);
  1039 }
  1040 
  1041 void
  1042 X11_SetWindowGrab(_THIS, SDL_Window * window)
  1043 {
  1044     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1045     Display *display = data->videodata->display;
  1046     SDL_bool oldstyle_fullscreen;
  1047 
  1048     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1049     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
  1050 
  1051     if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
  1052         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1053         /* Try to grab the mouse */
  1054         for (;;) {
  1055             int result =
  1056                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1057                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1058             if (result == GrabSuccess) {
  1059                 break;
  1060             }
  1061             SDL_Delay(100);
  1062         }
  1063 
  1064         /* Raise the window if we grab the mouse */
  1065         XRaiseWindow(display, data->xwindow);
  1066 
  1067         /* Now grab the keyboard */
  1068         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1069                       GrabModeAsync, CurrentTime);
  1070     } else {
  1071         XUngrabPointer(display, CurrentTime);
  1072         XUngrabKeyboard(display, CurrentTime);
  1073     }
  1074 }
  1075 
  1076 void
  1077 X11_DestroyWindow(_THIS, SDL_Window * window)
  1078 {
  1079     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1080     window->driverdata = NULL;
  1081 
  1082     if (data) {
  1083         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1084         Display *display = videodata->display;
  1085         int numwindows = videodata->numwindows;
  1086         SDL_WindowData **windowlist = videodata->windowlist;
  1087         int i;
  1088 
  1089         if (windowlist) {
  1090             for (i = 0; i < numwindows; ++i) {
  1091                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1092                     windowlist[i] = windowlist[numwindows - 1];
  1093                     windowlist[numwindows - 1] = NULL;
  1094                     videodata->numwindows--;
  1095                     break;
  1096                 }
  1097             }
  1098         }
  1099 #ifdef X_HAVE_UTF8_STRING
  1100         if (data->ic) {
  1101             XDestroyIC(data->ic);
  1102         }
  1103 #endif
  1104         if (data->created) {
  1105             XDestroyWindow(display, data->xwindow);
  1106         }
  1107         SDL_free(data);
  1108     }
  1109 }
  1110 
  1111 SDL_bool
  1112 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1113 {
  1114     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1115     Display *display = data->videodata->display;
  1116 
  1117     if (info->version.major == SDL_MAJOR_VERSION &&
  1118         info->version.minor == SDL_MINOR_VERSION) {
  1119         info->subsystem = SDL_SYSWM_X11;
  1120         info->info.x11.display = display;
  1121         info->info.x11.window = data->xwindow;
  1122         return SDL_TRUE;
  1123     } else {
  1124         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1125                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1126         return SDL_FALSE;
  1127     }
  1128 }
  1129 
  1130 /* vi: set ts=4 sw=4 expandtab: */