src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 08 Apr 2011 13:03:26 -0700
changeset 5535 96594ac5fd1a
parent 5531 477f550f6efd
child 5981 75caa8a7d559
permissions -rw-r--r--
SDL 1.3 is now under the zlib license.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_X11
    24 
    25 #include "../SDL_sysvideo.h"
    26 #include "../SDL_pixels_c.h"
    27 #include "../../events/SDL_keyboard_c.h"
    28 #include "../../events/SDL_mouse_c.h"
    29 
    30 #include "SDL_x11video.h"
    31 #include "SDL_x11mouse.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 *) SDL_GetDisplayForWindow(window)->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         data->colormap = attrib.colormap;
   180     }
   181 
   182     {
   183         Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   184         Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   185         Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   186         Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   187         Atom actualType;
   188         int actualFormat;
   189         unsigned long i, numItems, bytesAfter;
   190         unsigned char *propertyValue = NULL;
   191         long maxLength = 1024;
   192 
   193         if (XGetWindowProperty(data->videodata->display, w, _NET_WM_STATE,
   194                                0l, maxLength, False, XA_ATOM, &actualType,
   195                                &actualFormat, &numItems, &bytesAfter,
   196                                &propertyValue) == Success) {
   197             Atom *atoms = (Atom *) propertyValue;
   198             int maximized = 0;
   199             int fullscreen = 0;
   200 
   201             for (i = 0; i < numItems; ++i) {
   202                 if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
   203                     maximized |= 1;
   204                 } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
   205                     maximized |= 2;
   206                 } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
   207                     fullscreen = 1;
   208                 }
   209             }
   210             if (maximized == 3) {
   211                 window->flags |= SDL_WINDOW_MAXIMIZED;
   212             }  else if (fullscreen == 1) {
   213                 window->flags |= SDL_WINDOW_FULLSCREEN;
   214             }
   215             XFree(propertyValue);
   216         }
   217     }
   218 
   219     /* FIXME: How can I tell?
   220        {
   221        DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   222        if (style & WS_VISIBLE) {
   223        if (style & (WS_BORDER | WS_THICKFRAME)) {
   224        window->flags &= ~SDL_WINDOW_BORDERLESS;
   225        } else {
   226        window->flags |= SDL_WINDOW_BORDERLESS;
   227        }
   228        if (style & WS_THICKFRAME) {
   229        window->flags |= SDL_WINDOW_RESIZABLE;
   230        } else {
   231        window->flags &= ~SDL_WINDOW_RESIZABLE;
   232        }
   233        if (style & WS_MINIMIZE) {
   234        window->flags |= SDL_WINDOW_MINIMIZED;
   235        } else {
   236        window->flags &= ~SDL_WINDOW_MINIMIZED;
   237        }
   238        }
   239        if (GetFocus() == hwnd) {
   240        int index = data->videodata->keyboard;
   241        window->flags |= SDL_WINDOW_INPUT_FOCUS;
   242        SDL_SetKeyboardFocus(index, data->window);
   243 
   244        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   245        RECT rect;
   246        GetClientRect(hwnd, &rect);
   247        ClientToScreen(hwnd, (LPPOINT) & rect);
   248        ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   249        ClipCursor(&rect);
   250        }
   251        }
   252      */
   253 
   254     /* All done! */
   255     window->driverdata = data;
   256     return 0;
   257 }
   258 
   259 int
   260 X11_CreateWindow(_THIS, SDL_Window * window)
   261 {
   262     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   263     SDL_DisplayData *displaydata =
   264         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   265     Display *display = data->display;
   266     int screen = displaydata->screen;
   267     Visual *visual;
   268     int depth;
   269     XSetWindowAttributes xattr;
   270     Window w;
   271     XSizeHints *sizehints;
   272     XWMHints *wmhints;
   273     XClassHint *classhints;
   274     Atom _NET_WM_WINDOW_TYPE;
   275     Atom _NET_WM_WINDOW_TYPE_NORMAL;
   276     int wmstate_count;
   277     Atom wmstate_atoms[3];
   278 
   279 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   280 /* FIXME
   281     if ( use_xinerama ) {
   282         x = xinerama_info.x_org;
   283         y = xinerama_info.y_org;
   284     }
   285 */
   286 #endif
   287 #if SDL_VIDEO_OPENGL_GLX
   288     if (window->flags & SDL_WINDOW_OPENGL) {
   289         XVisualInfo *vinfo;
   290 
   291         vinfo = X11_GL_GetVisual(_this, display, screen);
   292         if (!vinfo) {
   293             return -1;
   294         }
   295         visual = vinfo->visual;
   296         depth = vinfo->depth;
   297         XFree(vinfo);
   298     } else
   299 #endif
   300 #ifdef SDL_VIDEO_DRIVER_PANDORA
   301     if (window->flags & SDL_WINDOW_OPENGL) {
   302         XVisualInfo *vinfo;
   303 
   304         vinfo = X11_GLES_GetVisual(_this, display, screen);
   305         if (!vinfo) {
   306             return -1;
   307         }
   308         visual = vinfo->visual;
   309         depth = vinfo->depth;
   310         XFree(vinfo);
   311     } else
   312 #endif
   313     {
   314         visual = displaydata->visual;
   315         depth = displaydata->depth;
   316     }
   317 
   318     xattr.override_redirect = False;
   319     xattr.background_pixel = 0;
   320     xattr.border_pixel = 0;
   321 
   322     if (visual->class == DirectColor) {
   323         Status status;
   324         XColor *colorcells;
   325         int i;
   326         int ncolors;
   327         int rmax, gmax, bmax;
   328         int rmask, gmask, bmask;
   329         int rshift, gshift, bshift;
   330 
   331         xattr.colormap =
   332             XCreateColormap(display, RootWindow(display, screen),
   333                             visual, AllocAll);
   334 
   335         /* If we can't create a colormap, then we must die */
   336         if (!xattr.colormap) {
   337             SDL_SetError("Could not create writable colormap");
   338             return -1;
   339         }
   340 
   341         /* OK, we got a colormap, now fill it in as best as we can */
   342         colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   343         if (!colorcells) {
   344             SDL_OutOfMemory();
   345             return -1;
   346         }
   347         ncolors = visual->map_entries;
   348         rmax = 0xffff;
   349         gmax = 0xffff;
   350         bmax = 0xffff;
   351 
   352         rshift = 0;
   353         rmask = visual->red_mask;
   354         while (0 == (rmask & 1)) {
   355             rshift++;
   356             rmask >>= 1;
   357         }
   358 
   359         gshift = 0;
   360         gmask = visual->green_mask;
   361         while (0 == (gmask & 1)) {
   362             gshift++;
   363             gmask >>= 1;
   364         }
   365 
   366         bshift = 0;
   367         bmask = visual->blue_mask;
   368         while (0 == (bmask & 1)) {
   369             bshift++;
   370             bmask >>= 1;
   371         }
   372 
   373         /* build the color table pixel values */
   374         for (i = 0; i < ncolors; i++) {
   375             Uint32 red = (rmax * i) / (ncolors - 1);
   376             Uint32 green = (gmax * i) / (ncolors - 1);
   377             Uint32 blue = (bmax * i) / (ncolors - 1);
   378 
   379             Uint32 rbits = (rmask * i) / (ncolors - 1);
   380             Uint32 gbits = (gmask * i) / (ncolors - 1);
   381             Uint32 bbits = (bmask * i) / (ncolors - 1);
   382 
   383             Uint32 pix =
   384                 (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   385 
   386             colorcells[i].pixel = pix;
   387 
   388             colorcells[i].red = red;
   389             colorcells[i].green = green;
   390             colorcells[i].blue = blue;
   391 
   392             colorcells[i].flags = DoRed | DoGreen | DoBlue;
   393         }
   394 
   395         XStoreColors(display, xattr.colormap, colorcells, ncolors);
   396 
   397         SDL_free(colorcells);
   398     } else {
   399         xattr.colormap =
   400             XCreateColormap(display, RootWindow(display, screen),
   401                             visual, AllocNone);
   402     }
   403 
   404     w = XCreateWindow(display, RootWindow(display, screen),
   405                       window->x, window->y, window->w, window->h,
   406                       0, depth, InputOutput, visual,
   407                       (CWOverrideRedirect | CWBackPixel | CWBorderPixel |
   408                        CWColormap), &xattr);
   409     if (!w) {
   410         SDL_SetError("Couldn't create window");
   411         return -1;
   412     }
   413 #if SDL_VIDEO_DRIVER_PANDORA
   414     /* Create the GLES window surface */
   415     _this->gles_data->egl_surface =
   416         _this->gles_data->eglCreateWindowSurface(_this->gles_data->
   417                                                  egl_display,
   418                                                  _this->gles_data->egl_config,
   419                                                  (NativeWindowType) w, NULL);
   420 
   421     if (_this->gles_data->egl_surface == EGL_NO_SURFACE) {
   422         SDL_SetError("Could not create GLES window surface");
   423         return -1;
   424     }
   425 #endif
   426 
   427     sizehints = XAllocSizeHints();
   428     if (sizehints) {
   429         if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   430             sizehints->min_width = sizehints->max_width = window->w;
   431             sizehints->min_height = sizehints->max_height = window->h;
   432             sizehints->flags = PMaxSize | PMinSize;
   433         }
   434         sizehints->x = window->x;
   435         sizehints->y = window->y;
   436         sizehints->flags |= USPosition;
   437         XSetWMNormalHints(display, w, sizehints);
   438         XFree(sizehints);
   439     }
   440 
   441     if (window->flags & SDL_WINDOW_BORDERLESS) {
   442         SDL_bool set;
   443         Atom WM_HINTS;
   444 
   445         /* We haven't modified the window manager hints yet */
   446         set = SDL_FALSE;
   447 
   448         /* First try to set MWM hints */
   449         WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", True);
   450         if (WM_HINTS != None) {
   451             /* Hints used by Motif compliant window managers */
   452             struct
   453             {
   454                 unsigned long flags;
   455                 unsigned long functions;
   456                 unsigned long decorations;
   457                 long input_mode;
   458                 unsigned long status;
   459             } MWMHints = {
   460             (1L << 1), 0, 0, 0, 0};
   461 
   462             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   463                             PropModeReplace, (unsigned char *) &MWMHints,
   464                             sizeof(MWMHints) / 4);
   465             set = SDL_TRUE;
   466         }
   467         /* Now try to set KWM hints */
   468         WM_HINTS = XInternAtom(display, "KWM_WIN_DECORATION", True);
   469         if (WM_HINTS != None) {
   470             long KWMHints = 0;
   471 
   472             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   473                             PropModeReplace,
   474                             (unsigned char *) &KWMHints,
   475                             sizeof(KWMHints) / 4);
   476             set = SDL_TRUE;
   477         }
   478         /* Now try to set GNOME hints */
   479         WM_HINTS = XInternAtom(display, "_WIN_HINTS", True);
   480         if (WM_HINTS != None) {
   481             long GNOMEHints = 0;
   482 
   483             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   484                             PropModeReplace,
   485                             (unsigned char *) &GNOMEHints,
   486                             sizeof(GNOMEHints) / 4);
   487             set = SDL_TRUE;
   488         }
   489         /* Finally set the transient hints if necessary */
   490         if (!set) {
   491             XSetTransientForHint(display, w, RootWindow(display, screen));
   492         }
   493     } else {
   494         SDL_bool set;
   495         Atom WM_HINTS;
   496 
   497         /* We haven't modified the window manager hints yet */
   498         set = SDL_FALSE;
   499 
   500         /* First try to unset MWM hints */
   501         WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", True);
   502         if (WM_HINTS != None) {
   503             XDeleteProperty(display, w, WM_HINTS);
   504             set = SDL_TRUE;
   505         }
   506         /* Now try to unset KWM hints */
   507         WM_HINTS = XInternAtom(display, "KWM_WIN_DECORATION", True);
   508         if (WM_HINTS != None) {
   509             XDeleteProperty(display, w, WM_HINTS);
   510             set = SDL_TRUE;
   511         }
   512         /* Now try to unset GNOME hints */
   513         WM_HINTS = XInternAtom(display, "_WIN_HINTS", True);
   514         if (WM_HINTS != None) {
   515             XDeleteProperty(display, w, WM_HINTS);
   516             set = SDL_TRUE;
   517         }
   518         /* Finally unset the transient hints if necessary */
   519         if (!set) {
   520             XDeleteProperty(display, w, XA_WM_TRANSIENT_FOR);
   521         }
   522     }
   523 
   524     /* Set the input hints so we get keyboard input */
   525     wmhints = XAllocWMHints();
   526     if (wmhints) {
   527         wmhints->input = True;
   528         wmhints->flags = InputHint;
   529         XSetWMHints(display, w, wmhints);
   530         XFree(wmhints);
   531     }
   532 
   533     /* Set the class hints so we can get an icon (AfterStep) */
   534     classhints = XAllocClassHint();
   535     if (classhints != NULL) {
   536         classhints->res_name = data->classname;
   537         classhints->res_class = data->classname;
   538         XSetClassHint(display, w, classhints);
   539         XFree(classhints);
   540     }
   541 
   542     /* Set the window manager state */
   543     wmstate_count = X11_GetWMStateProperty(_this, window, wmstate_atoms);
   544     if (wmstate_count > 0) {
   545         XChangeProperty(display, w, data->_NET_WM_STATE, XA_ATOM, 32,
   546                         PropModeReplace,
   547                         (unsigned char *)wmstate_atoms, wmstate_count);
   548     } else {
   549         XDeleteProperty(display, w, data->_NET_WM_STATE);
   550     }
   551 
   552     /* Let the window manager know we're a "normal" window */
   553     _NET_WM_WINDOW_TYPE = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
   554     _NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
   555     XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
   556                     PropModeReplace,
   557                     (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1);
   558 
   559     /* Allow the window to be deleted by the window manager */
   560     XSetWMProtocols(display, w, &data->WM_DELETE_WINDOW, 1);
   561 
   562     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   563         XDestroyWindow(display, w);
   564         return -1;
   565     }
   566 
   567 #ifdef X_HAVE_UTF8_STRING
   568     {
   569         Uint32 fevent = 0;
   570         pXGetICValues(((SDL_WindowData *) window->driverdata)->ic,
   571                       XNFilterEvents, &fevent, NULL);
   572         XSelectInput(display, w,
   573                      (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   574                       ExposureMask | ButtonPressMask | ButtonReleaseMask |
   575                       PointerMotionMask | KeyPressMask | KeyReleaseMask |
   576                       PropertyChangeMask | StructureNotifyMask |
   577                       KeymapStateMask | fevent));
   578     }
   579 #else
   580     {
   581         XSelectInput(display, w,
   582                      (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   583                       ExposureMask | ButtonPressMask | ButtonReleaseMask |
   584                       PointerMotionMask | KeyPressMask | KeyReleaseMask |
   585                       PropertyChangeMask | StructureNotifyMask |
   586                       KeymapStateMask));
   587     }
   588 #endif
   589 
   590     XFlush(display);
   591 
   592     return 0;
   593 }
   594 
   595 int
   596 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   597 {
   598     Window w = (Window) data;
   599 
   600     window->title = X11_GetWindowTitle(_this, w);
   601 
   602     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   603         return -1;
   604     }
   605     return 0;
   606 }
   607 
   608 char *
   609 X11_GetWindowTitle(_THIS, Window xwindow)
   610 {
   611     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   612     Display *display = data->display;
   613     int status, real_format;
   614     Atom real_type;
   615     unsigned long items_read, items_left;
   616     unsigned char *propdata;
   617     char *title = NULL;
   618 
   619     status = XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
   620                 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
   621                 &items_read, &items_left, &propdata);
   622     if (status == Success) {
   623         title = SDL_strdup(SDL_static_cast(char*, propdata));
   624         XFree(propdata);
   625     } else {
   626         status = XGetWindowProperty(display, xwindow, XA_WM_NAME,
   627                     0L, 8192L, False, XA_STRING, &real_type, &real_format,
   628                     &items_read, &items_left, &propdata);
   629         if (status == Success) {
   630             title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
   631         } else {
   632             title = SDL_strdup("");
   633         }
   634     }
   635     return title;
   636 }
   637 
   638 void
   639 X11_SetWindowTitle(_THIS, SDL_Window * window)
   640 {
   641     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   642     Display *display = data->videodata->display;
   643     XTextProperty titleprop, iconprop;
   644     Status status;
   645     const char *title = window->title;
   646     const char *icon = NULL;
   647 
   648 #ifdef X_HAVE_UTF8_STRING
   649     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   650     Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME;
   651 #endif
   652 
   653     if (title != NULL) {
   654         char *title_locale = SDL_iconv_utf8_locale(title);
   655         if (!title_locale) {
   656             SDL_OutOfMemory();
   657             return;
   658         }
   659         status = XStringListToTextProperty(&title_locale, 1, &titleprop);
   660         SDL_free(title_locale);
   661         if (status) {
   662             XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   663             XFree(titleprop.value);
   664         }
   665 #ifdef X_HAVE_UTF8_STRING
   666         if (SDL_X11_HAVE_UTF8) {
   667             status =
   668                 Xutf8TextListToTextProperty(display, (char **) &title, 1,
   669                                             XUTF8StringStyle, &titleprop);
   670             if (status == Success) {
   671                 XSetTextProperty(display, data->xwindow, &titleprop,
   672                                  _NET_WM_NAME);
   673                 XFree(titleprop.value);
   674             }
   675         }
   676 #endif
   677     }
   678     if (icon != NULL) {
   679         char *icon_locale = SDL_iconv_utf8_locale(icon);
   680         if (!icon_locale) {
   681             SDL_OutOfMemory();
   682             return;
   683         }
   684         status = XStringListToTextProperty(&icon_locale, 1, &iconprop);
   685         SDL_free(icon_locale);
   686         if (status) {
   687             XSetTextProperty(display, data->xwindow, &iconprop,
   688                              XA_WM_ICON_NAME);
   689             XFree(iconprop.value);
   690         }
   691 #ifdef X_HAVE_UTF8_STRING
   692         if (SDL_X11_HAVE_UTF8) {
   693             status =
   694                 Xutf8TextListToTextProperty(display, (char **) &icon, 1,
   695                                             XUTF8StringStyle, &iconprop);
   696             if (status == Success) {
   697                 XSetTextProperty(display, data->xwindow, &iconprop,
   698                                  _NET_WM_ICON_NAME);
   699                 XFree(iconprop.value);
   700             }
   701         }
   702 #endif
   703     }
   704     XFlush(display);
   705 }
   706 
   707 void
   708 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   709 {
   710     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   711     Display *display = data->videodata->display;
   712     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   713 
   714     if (icon) {
   715         SDL_PixelFormat format;
   716         SDL_Surface *surface;
   717         int propsize;
   718         long *propdata;
   719 
   720         /* Convert the icon to ARGB for modern window managers */
   721         SDL_InitFormat(&format, SDL_PIXELFORMAT_ARGB8888);
   722         surface = SDL_ConvertSurface(icon, &format, 0);
   723         if (!surface) {
   724             return;
   725         }
   726 
   727         /* Set the _NET_WM_ICON property */
   728         propsize = 2 + (icon->w * icon->h);
   729         propdata = SDL_malloc(propsize * sizeof(long));
   730         if (propdata) {
   731             int x, y;
   732             Uint32 *src;
   733             long *dst;
   734 
   735             propdata[0] = icon->w;
   736             propdata[1] = icon->h;
   737             dst = &propdata[2];
   738             for (y = 0; y < icon->h; ++y) {
   739                 src = (Uint32*)((Uint8*)surface->pixels + y * surface->pitch);
   740                 for (x = 0; x < icon->w; ++x) {
   741                     *dst++ = *src++;
   742                 }
   743             }
   744             XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   745                             32, PropModeReplace, (unsigned char *) propdata,
   746                             propsize);
   747         }
   748         SDL_FreeSurface(surface);
   749     } else {
   750         XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   751     }
   752     XFlush(display);
   753 }
   754 
   755 void
   756 X11_SetWindowPosition(_THIS, SDL_Window * window)
   757 {
   758     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   759     Display *display = data->videodata->display;
   760     int x, y;
   761 
   762     XMoveWindow(display, data->xwindow, window->x, window->y);
   763     XFlush(display);
   764 }
   765 
   766 void
   767 X11_SetWindowSize(_THIS, SDL_Window * window)
   768 {
   769     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   770     Display *display = data->videodata->display;
   771 
   772     if (SDL_IsShapedWindow(window))
   773         X11_ResizeWindowShape(window);
   774     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   775          /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the XResizeWindow, thus
   776             we must set the size hints to adjust the window size.*/
   777          XSizeHints *sizehints = XAllocSizeHints();
   778          long userhints;
   779 
   780          XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   781 
   782          sizehints->min_width = sizehints->max_height = window->w;
   783          sizehints->min_height = sizehints->max_height = window->h;
   784 
   785          XSetWMNormalHints(display, data->xwindow, sizehints);
   786 
   787          XFree(sizehints);
   788     } else
   789         XResizeWindow(display, data->xwindow, window->w, window->h);
   790     XFlush(display);
   791 }
   792 
   793 void
   794 X11_ShowWindow(_THIS, SDL_Window * window)
   795 {
   796     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   797     Display *display = data->videodata->display;
   798 
   799     XMapRaised(display, data->xwindow);
   800     XFlush(display);
   801 }
   802 
   803 void
   804 X11_HideWindow(_THIS, SDL_Window * window)
   805 {
   806     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   807     Display *display = data->videodata->display;
   808 
   809     XUnmapWindow(display, data->xwindow);
   810     XFlush(display);
   811 }
   812 
   813 void
   814 X11_RaiseWindow(_THIS, SDL_Window * window)
   815 {
   816     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   817     Display *display = data->videodata->display;
   818 
   819     XRaiseWindow(display, data->xwindow);
   820     XFlush(display);
   821 }
   822 
   823 static void
   824 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   825 {
   826     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   827     SDL_DisplayData *displaydata =
   828         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   829     Display *display = data->videodata->display;
   830     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   831     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   832     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   833     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   834 
   835     if (X11_IsWindowMapped(_this, window)) {
   836         XEvent e;
   837 
   838         SDL_zero(e);
   839         e.xany.type = ClientMessage;
   840         e.xclient.message_type = _NET_WM_STATE;
   841         e.xclient.format = 32;
   842         e.xclient.window = data->xwindow;
   843         e.xclient.data.l[0] =
   844             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   845         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
   846         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
   847         e.xclient.data.l[3] = 0l;
   848 
   849         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   850                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   851     } else {
   852         int count = 0;
   853         Atom atoms[3];
   854 
   855         if (window->flags & SDL_WINDOW_FULLSCREEN) {
   856             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   857         }
   858         if (maximized) {
   859             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   860             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   861         }
   862         if (count > 0) {
   863             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
   864                             PropModeReplace, (unsigned char *)atoms, count);
   865         } else {
   866             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
   867         }
   868     }
   869     XFlush(display);
   870 }
   871 
   872 void
   873 X11_MaximizeWindow(_THIS, SDL_Window * window)
   874 {
   875     SetWindowMaximized(_this, window, SDL_TRUE);
   876 }
   877 
   878 void
   879 X11_MinimizeWindow(_THIS, SDL_Window * window)
   880 {
   881     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   882     SDL_DisplayData *displaydata =
   883         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   884     Display *display = data->videodata->display;
   885  
   886     XIconifyWindow(display, data->xwindow, displaydata->screen);
   887     XFlush(display);
   888 }
   889 
   890 void
   891 X11_RestoreWindow(_THIS, SDL_Window * window)
   892 {
   893     SetWindowMaximized(_this, window, SDL_FALSE);
   894     X11_ShowWindow(_this, window);
   895 }
   896 
   897 void
   898 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
   899 {
   900     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   901     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
   902     Display *display = data->videodata->display;
   903     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   904     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   905     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   906     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   907 
   908     if (X11_IsWindowMapped(_this, window)) {
   909         XEvent e;
   910 
   911         SDL_zero(e);
   912         e.xany.type = ClientMessage;
   913         e.xclient.message_type = _NET_WM_STATE;
   914         e.xclient.format = 32;
   915         e.xclient.window = data->xwindow;
   916         e.xclient.data.l[0] =
   917             fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   918         e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
   919         e.xclient.data.l[3] = 0l;
   920 
   921         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   922                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   923     } else {
   924         int count = 0;
   925         Atom atoms[3];
   926 
   927         if (fullscreen) {
   928             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   929         }
   930         if (window->flags & SDL_WINDOW_MAXIMIZED) {
   931             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   932             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   933         }
   934         if (count > 0) {
   935             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
   936                             PropModeReplace, (unsigned char *)atoms, count);
   937         } else {
   938             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
   939         }
   940     }
   941     XFlush(display);
   942 }
   943 
   944 int
   945 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   946 {
   947     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   948     Display *display = data->videodata->display;
   949     Visual *visual = data->visual;
   950     Colormap colormap = data->colormap;
   951     XColor *colorcells;
   952     int ncolors;
   953     int rmask, gmask, bmask;
   954     int rshift, gshift, bshift;
   955     int i, j;
   956 
   957     if (visual->class != DirectColor) {
   958         SDL_SetError("Window doesn't have DirectColor visual");
   959         return -1;
   960     }
   961 
   962     ncolors = visual->map_entries;
   963     colorcells = SDL_malloc(ncolors * sizeof(XColor));
   964     if (!colorcells) {
   965         SDL_OutOfMemory();
   966         return -1;
   967     }
   968 
   969     rshift = 0;
   970     rmask = visual->red_mask;
   971     while (0 == (rmask & 1)) {
   972         rshift++;
   973         rmask >>= 1;
   974     }
   975 
   976     gshift = 0;
   977     gmask = visual->green_mask;
   978     while (0 == (gmask & 1)) {
   979         gshift++;
   980         gmask >>= 1;
   981     }
   982 
   983     bshift = 0;
   984     bmask = visual->blue_mask;
   985     while (0 == (bmask & 1)) {
   986         bshift++;
   987         bmask >>= 1;
   988     }
   989 
   990     /* build the color table pixel values */
   991     for (i = 0; i < ncolors; i++) {
   992         Uint32 rbits = (rmask * i) / (ncolors - 1);
   993         Uint32 gbits = (gmask * i) / (ncolors - 1);
   994         Uint32 bbits = (bmask * i) / (ncolors - 1);
   995         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   996 
   997         colorcells[i].pixel = pix;
   998 
   999         colorcells[i].red = ramp[(0 * 256) + i];
  1000         colorcells[i].green = ramp[(1 * 256) + i];
  1001         colorcells[i].blue = ramp[(2 * 256) + i];
  1002 
  1003         colorcells[i].flags = DoRed | DoGreen | DoBlue;
  1004     }
  1005 
  1006     XStoreColors(display, colormap, colorcells, ncolors);
  1007     XFlush(display);
  1008     SDL_free(colorcells);
  1009 
  1010     return 0;
  1011 }
  1012 
  1013 void
  1014 X11_SetWindowGrab(_THIS, SDL_Window * window)
  1015 {
  1016     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1017     Display *display = data->videodata->display;
  1018     SDL_bool oldstyle_fullscreen;
  1019 
  1020     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1021     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
  1022 
  1023     if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
  1024         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1025         /* Try to grab the mouse */
  1026         for (;;) {
  1027             int result =
  1028                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1029                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1030             if (result == GrabSuccess) {
  1031                 break;
  1032             }
  1033             SDL_Delay(100);
  1034         }
  1035 
  1036         /* Raise the window if we grab the mouse */
  1037         XRaiseWindow(display, data->xwindow);
  1038 
  1039         /* Now grab the keyboard */
  1040         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1041                       GrabModeAsync, CurrentTime);
  1042     } else {
  1043         XUngrabPointer(display, CurrentTime);
  1044         XUngrabKeyboard(display, CurrentTime);
  1045     }
  1046 }
  1047 
  1048 void
  1049 X11_DestroyWindow(_THIS, SDL_Window * window)
  1050 {
  1051     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1052     window->driverdata = NULL;
  1053 
  1054     if (data) {
  1055         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1056         Display *display = videodata->display;
  1057         int numwindows = videodata->numwindows;
  1058         SDL_WindowData **windowlist = videodata->windowlist;
  1059         int i;
  1060 
  1061         if (windowlist) {
  1062             for (i = 0; i < numwindows; ++i) {
  1063                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1064                     windowlist[i] = windowlist[numwindows - 1];
  1065                     windowlist[numwindows - 1] = NULL;
  1066                     videodata->numwindows--;
  1067                     break;
  1068                 }
  1069             }
  1070         }
  1071 #ifdef X_HAVE_UTF8_STRING
  1072         if (data->ic) {
  1073             XDestroyIC(data->ic);
  1074         }
  1075 #endif
  1076         if (data->created) {
  1077             XDestroyWindow(display, data->xwindow);
  1078             XFlush(display);
  1079         }
  1080         SDL_free(data);
  1081     }
  1082 }
  1083 
  1084 SDL_bool
  1085 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1086 {
  1087     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1088     Display *display = data->videodata->display;
  1089 
  1090     if (info->version.major == SDL_MAJOR_VERSION &&
  1091         info->version.minor == SDL_MINOR_VERSION) {
  1092         info->subsystem = SDL_SYSWM_X11;
  1093         info->info.x11.display = display;
  1094         info->info.x11.window = data->xwindow;
  1095         return SDL_TRUE;
  1096     } else {
  1097         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1098                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1099         return SDL_FALSE;
  1100     }
  1101 }
  1102 
  1103 #endif /* SDL_VIDEO_DRIVER_X11 */
  1104 
  1105 /* vi: set ts=4 sw=4 expandtab: */