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