src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 11 Mar 2011 08:49:20 -0800
changeset 5466 006883d5fa51
parent 5386 762e67f81fc7
child 5478 6b65ff3cee62
permissions -rw-r--r--
Gamma support is back!

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