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