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