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