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