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