src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 18 Jul 2012 15:17:27 -0700
changeset 6370 93187f7f7d5d
parent 6369 a92fbd27127b
child 6373 494e0436525f
permissions -rwxr-xr-x
Improved simultaneous support for OpenGL and OpenGL ES

From Scott Percival

Okay, I think I have something for this. Tested it on GL and GLES
machines, it seems to work okay.

- Add a new SDL GL attribute SDL_GL_CONTEXT_EGL:
- Only useful for the X11 video driver at the moment
- Set to 1 for an EGL context, 0 to use the default for the video driver
- Default is 0, unless library is built for EGL only
- Should be set after SDL init, but before window/context
creation (i.e. same place you'd specify attributes for major/minor GL
version)
- After a lot of agony pondering the least-terrible way to go about
it, made it so that X11_GL_LoadLibrary and X11_GLES_LoadLibrary check
SDL_GL_CONTEXT_EGL. If no GL context exists yet, and the attribute
choice doesn't match with the checking function, then it changes all
the function pointers in the video driver and passes control on to the
new LoadLibrary method.
- Likewise, make X11_CreateWindow check this attribute before firing
off a call to X11_GL_GetVisual/X11_GLES_GetVisual
- Added a sanity check to the start of X11_GL_LoadLibrary
- Tidied up SDL_x11opengles.h
- Moved ownership of the gles_data structure over to
X11_GLES_LoadLibrary/UnloadLibrary
- Should incorporate the 3 fixes posted by Andre Heider

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