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