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