src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 14 Aug 2017 10:28:47 -0700
changeset 11288 47a5a4999180
parent 11151 7cfe088fafba
child 11334 749cb40916f2
permissions -rw-r--r--
Fixed bug 2500 - X11: SDL tries (and fails) to hide foreign windows

Alvin

I'm interested in this bug as well. I have experienced it when trying to embed an SDL_Window into a FLTK application. To do this, I create a FLTK window (window inside a window - think video player) and then use SDL_CreateWindowFrom() on the inner most window's Xlib Window*. After which, I create a renderer.

In my situation I am using the FLTK GUI toolkit.

What I have experienced is that the SDL_CreateRender() will recreate the window in order to properly setup OpenGL capability. As part of this process, the window is hidden and a call is executed that waits indefinitely for an acknowledgement that the window was indeed unmapped. This is where my program hangs.

Please correct me if I am wrong, but should SDL2 not make Xlib calls that effect the Xlib Window in this situation (e.g. When SDL_CreateWindowFrom() is used)? The toolkit being used typically assumes responsibility and, I presume, tracks all Xlib Windows it creates.

On line src/video/SDL_video.c:1372 the comment associated with setting SDL_WINDOW_FOREIGN reads:

/* Can't destroy and re-create foreign windows, hrm */

Since I do not know the reason for hiding the window in the first place, the attached patch simply does not wait for a response when X11_XWithdrawWindow() and X11_XMapRaised() are issued by X11_HideWindow() and X11_ShowWindow(), respectively. I presume that the GUI toolkit (GTK, FLTK, etc.) has or will consume the acknowledging event as it is managing the Xlib Window (or it thinks it is).

I have tested the patch against hg d09d4b578e77 and I have successfully tested:
* Embedding the SDL_Window inside a FLTK application.
* Calling SDL_SetWindowSize() when FLTK resizes the window (e.g. dragging cursor on the edge of the window).
* Filling the renderer's default target blue and drawing a red fill square at the centre (exciting, I know!)
* Calling SDL_Quit() when the application terminates

I do not receive any Xlib erorr messages (BadWindow, etc.) in any of those situations.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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_internal.h"
    22 
    23 #if SDL_VIDEO_DRIVER_X11
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_hints.h"
    27 #include "../SDL_sysvideo.h"
    28 #include "../SDL_pixels_c.h"
    29 #include "../../events/SDL_keyboard_c.h"
    30 #include "../../events/SDL_mouse_c.h"
    31 
    32 #include "SDL_x11video.h"
    33 #include "SDL_x11mouse.h"
    34 #include "SDL_x11shape.h"
    35 #include "SDL_x11xinput2.h"
    36 
    37 #if SDL_VIDEO_OPENGL_EGL
    38 #include "SDL_x11opengles.h"
    39 #endif
    40 
    41 #include "SDL_timer.h"
    42 #include "SDL_syswm.h"
    43 #include "SDL_log.h"
    44 
    45 #define _NET_WM_STATE_REMOVE    0l
    46 #define _NET_WM_STATE_ADD       1l
    47 
    48 static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
    49 {
    50     return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
    51 }
    52 static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
    53 {
    54     return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
    55 }
    56 
    57 /*
    58 static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
    59 {
    60     return ev->type == ConfigureNotify && ev->xconfigure.window == *((Window*)win);
    61 }
    62 static Bool
    63 X11_XIfEventTimeout(Display *display, XEvent *event_return, Bool (*predicate)(), XPointer arg, int timeoutMS)
    64 {
    65     Uint32 start = SDL_GetTicks();
    66 
    67     while (!X11_XCheckIfEvent(display, event_return, predicate, arg)) {
    68         if (SDL_TICKS_PASSED(SDL_GetTicks(), start + timeoutMS)) {
    69             return False;
    70         }
    71     }
    72     return True;
    73 }
    74 */
    75 
    76 static SDL_bool
    77 X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
    78 {
    79     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    80     return (data->fswindow != 0);
    81 }
    82 
    83 static SDL_bool
    84 X11_IsWindowMapped(_THIS, SDL_Window * window)
    85 {
    86     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    87     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    88     XWindowAttributes attr;
    89 
    90     X11_XGetWindowAttributes(videodata->display, data->xwindow, &attr);
    91     if (attr.map_state != IsUnmapped) {
    92         return SDL_TRUE;
    93     } else {
    94         return SDL_FALSE;
    95     }
    96 }
    97 
    98 #if 0
    99 static SDL_bool
   100 X11_IsActionAllowed(SDL_Window *window, Atom action)
   101 {
   102     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   103     Atom _NET_WM_ALLOWED_ACTIONS = data->videodata->_NET_WM_ALLOWED_ACTIONS;
   104     Atom type;
   105     Display *display = data->videodata->display;
   106     int form;
   107     unsigned long remain;
   108     unsigned long len, i;
   109     Atom *list;
   110     SDL_bool ret = SDL_FALSE;
   111 
   112     if (X11_XGetWindowProperty(display, data->xwindow, _NET_WM_ALLOWED_ACTIONS, 0, 1024, False, XA_ATOM, &type, &form, &len, &remain, (unsigned char **)&list) == Success)
   113     {
   114         for (i=0; i<len; ++i)
   115         {
   116             if (list[i] == action) {
   117                 ret = SDL_TRUE;
   118                 break;
   119             }
   120         }
   121         X11_XFree(list);
   122     }
   123     return ret;
   124 }
   125 #endif /* 0 */
   126 
   127 void
   128 X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags)
   129 {
   130     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   131     Display *display = videodata->display;
   132     /* !!! FIXME: just dereference videodata below instead of copying to locals. */
   133     Atom _NET_WM_STATE = videodata->_NET_WM_STATE;
   134     /* Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN; */
   135     Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED;
   136     Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   137     Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   138     Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN;
   139     Atom _NET_WM_STATE_ABOVE = videodata->_NET_WM_STATE_ABOVE;
   140     Atom _NET_WM_STATE_SKIP_TASKBAR = videodata->_NET_WM_STATE_SKIP_TASKBAR;
   141     Atom _NET_WM_STATE_SKIP_PAGER = videodata->_NET_WM_STATE_SKIP_PAGER;
   142     Atom atoms[16];
   143     int count = 0;
   144 
   145     /* The window manager sets this property, we shouldn't set it.
   146        If we did, this would indicate to the window manager that we don't
   147        actually want to be mapped during X11_XMapRaised(), which would be bad.
   148      *
   149     if (flags & SDL_WINDOW_HIDDEN) {
   150         atoms[count++] = _NET_WM_STATE_HIDDEN;
   151     }
   152     */
   153 
   154     if (flags & SDL_WINDOW_ALWAYS_ON_TOP) {
   155         atoms[count++] = _NET_WM_STATE_ABOVE;
   156     }
   157     if (flags & SDL_WINDOW_SKIP_TASKBAR) {
   158         atoms[count++] = _NET_WM_STATE_SKIP_TASKBAR;
   159         atoms[count++] = _NET_WM_STATE_SKIP_PAGER;
   160     }
   161     if (flags & SDL_WINDOW_INPUT_FOCUS) {
   162         atoms[count++] = _NET_WM_STATE_FOCUSED;
   163     }
   164     if (flags & SDL_WINDOW_MAXIMIZED) {
   165         atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   166         atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   167     }
   168     if (flags & SDL_WINDOW_FULLSCREEN) {
   169         atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   170     }
   171 
   172     SDL_assert(count <= SDL_arraysize(atoms));
   173 
   174     if (count > 0) {
   175         X11_XChangeProperty(display, xwindow, _NET_WM_STATE, XA_ATOM, 32,
   176                         PropModeReplace, (unsigned char *)atoms, count);
   177     } else {
   178         X11_XDeleteProperty(display, xwindow, _NET_WM_STATE);
   179     }
   180 }
   181 
   182 Uint32
   183 X11_GetNetWMState(_THIS, Window xwindow)
   184 {
   185     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   186     Display *display = videodata->display;
   187     Atom _NET_WM_STATE = videodata->_NET_WM_STATE;
   188     Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN;
   189     Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED;
   190     Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   191     Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   192     Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN;
   193     Atom actualType;
   194     int actualFormat;
   195     unsigned long i, numItems, bytesAfter;
   196     unsigned char *propertyValue = NULL;
   197     long maxLength = 1024;
   198     Uint32 flags = 0;
   199 
   200     if (X11_XGetWindowProperty(display, xwindow, _NET_WM_STATE,
   201                            0l, maxLength, False, XA_ATOM, &actualType,
   202                            &actualFormat, &numItems, &bytesAfter,
   203                            &propertyValue) == Success) {
   204         Atom *atoms = (Atom *) propertyValue;
   205         int maximized = 0;
   206         int fullscreen = 0;
   207 
   208         for (i = 0; i < numItems; ++i) {
   209             if (atoms[i] == _NET_WM_STATE_HIDDEN) {
   210                 flags |= SDL_WINDOW_HIDDEN;
   211             } else if (atoms[i] == _NET_WM_STATE_FOCUSED) {
   212                 flags |= SDL_WINDOW_INPUT_FOCUS;
   213             } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
   214                 maximized |= 1;
   215             } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
   216                 maximized |= 2;
   217             } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
   218                 fullscreen = 1;
   219             }
   220         }
   221         if (maximized == 3) {
   222             flags |= SDL_WINDOW_MAXIMIZED;
   223         }
   224 
   225         if (fullscreen == 1) {
   226             flags |= SDL_WINDOW_FULLSCREEN;
   227         }
   228 
   229         /* If the window is unmapped, numItems will be zero and _NET_WM_STATE_HIDDEN
   230          * will not be set. Do an additional check to see if the window is unmapped
   231          * and mark it as SDL_WINDOW_HIDDEN if it is.
   232          */
   233         {
   234             XWindowAttributes attr;
   235             SDL_memset(&attr,0,sizeof(attr));
   236             X11_XGetWindowAttributes(videodata->display, xwindow, &attr);
   237             if (attr.map_state == IsUnmapped) {
   238                 flags |= SDL_WINDOW_HIDDEN;
   239             }
   240         }
   241         X11_XFree(propertyValue);
   242     }
   243 
   244     /* FIXME, check the size hints for resizable */
   245     /* flags |= SDL_WINDOW_RESIZABLE; */
   246 
   247     return flags;
   248 }
   249 
   250 static int
   251 SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
   252 {
   253     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   254     SDL_WindowData *data;
   255     int numwindows = videodata->numwindows;
   256     int windowlistlength = videodata->windowlistlength;
   257     SDL_WindowData **windowlist = videodata->windowlist;
   258 
   259     /* Allocate the window data */
   260     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   261     if (!data) {
   262         return SDL_OutOfMemory();
   263     }
   264     data->window = window;
   265     data->xwindow = w;
   266 #ifdef X_HAVE_UTF8_STRING
   267     if (SDL_X11_HAVE_UTF8 && videodata->im) {
   268         data->ic =
   269             X11_XCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w,
   270                        XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
   271                        NULL);
   272     }
   273 #endif
   274     data->created = created;
   275     data->videodata = videodata;
   276 
   277     /* Associate the data with the window */
   278 
   279     if (numwindows < windowlistlength) {
   280         windowlist[numwindows] = data;
   281         videodata->numwindows++;
   282     } else {
   283         windowlist =
   284             (SDL_WindowData **) SDL_realloc(windowlist,
   285                                             (numwindows +
   286                                              1) * sizeof(*windowlist));
   287         if (!windowlist) {
   288             SDL_free(data);
   289             return SDL_OutOfMemory();
   290         }
   291         windowlist[numwindows] = data;
   292         videodata->numwindows++;
   293         videodata->windowlistlength++;
   294         videodata->windowlist = windowlist;
   295     }
   296 
   297     /* Fill in the SDL window with the window data */
   298     {
   299         XWindowAttributes attrib;
   300 
   301         X11_XGetWindowAttributes(data->videodata->display, w, &attrib);
   302         window->x = attrib.x;
   303         window->y = attrib.y;
   304         window->w = attrib.width;
   305         window->h = attrib.height;
   306         if (attrib.map_state != IsUnmapped) {
   307             window->flags |= SDL_WINDOW_SHOWN;
   308         } else {
   309             window->flags &= ~SDL_WINDOW_SHOWN;
   310         }
   311         data->visual = attrib.visual;
   312         data->colormap = attrib.colormap;
   313     }
   314 
   315     window->flags |= X11_GetNetWMState(_this, w);
   316 
   317     {
   318         Window FocalWindow;
   319         int RevertTo=0;
   320         X11_XGetInputFocus(data->videodata->display, &FocalWindow, &RevertTo);
   321         if (FocalWindow==w)
   322         {
   323             window->flags |= SDL_WINDOW_INPUT_FOCUS;
   324         }
   325 
   326         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
   327             SDL_SetKeyboardFocus(data->window);
   328         }
   329 
   330         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   331             /* Tell x11 to clip mouse */
   332         }
   333     }
   334 
   335     /* All done! */
   336     window->driverdata = data;
   337     return 0;
   338 }
   339 
   340 static void
   341 SetWindowBordered(Display *display, int screen, Window window, SDL_bool border)
   342 {
   343     /*
   344      * this code used to check for KWM_WIN_DECORATION, but KDE hasn't
   345      *  supported it for years and years. It now respects _MOTIF_WM_HINTS.
   346      *  Gnome is similar: just use the Motif atom.
   347      */
   348 
   349     Atom WM_HINTS = X11_XInternAtom(display, "_MOTIF_WM_HINTS", True);
   350     if (WM_HINTS != None) {
   351         /* Hints used by Motif compliant window managers */
   352         struct
   353         {
   354             unsigned long flags;
   355             unsigned long functions;
   356             unsigned long decorations;
   357             long input_mode;
   358             unsigned long status;
   359         } MWMHints = {
   360             (1L << 1), 0, border ? 1 : 0, 0, 0
   361         };
   362 
   363         X11_XChangeProperty(display, window, WM_HINTS, WM_HINTS, 32,
   364                         PropModeReplace, (unsigned char *) &MWMHints,
   365                         sizeof(MWMHints) / sizeof(long));
   366     } else {  /* set the transient hints instead, if necessary */
   367         X11_XSetTransientForHint(display, window, RootWindow(display, screen));
   368     }
   369 }
   370 
   371 int
   372 X11_CreateWindow(_THIS, SDL_Window * window)
   373 {
   374     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   375     SDL_DisplayData *displaydata =
   376         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   377     SDL_WindowData *windowdata;
   378     Display *display = data->display;
   379     int screen = displaydata->screen;
   380     Visual *visual;
   381     int depth;
   382     XSetWindowAttributes xattr;
   383     Window w;
   384     XSizeHints *sizehints;
   385     XWMHints *wmhints;
   386     XClassHint *classhints;
   387     Atom _NET_WM_BYPASS_COMPOSITOR;
   388     Atom _NET_WM_WINDOW_TYPE;
   389     Atom wintype;
   390     const char *wintype_name = NULL;
   391     long compositor = 1;
   392     Atom _NET_WM_PID;
   393     Atom XdndAware, xdnd_version = 5;
   394     long fevent = 0;
   395 
   396 #if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_EGL
   397     if ((window->flags & SDL_WINDOW_OPENGL) &&
   398         !SDL_getenv("SDL_VIDEO_X11_VISUALID")) {
   399         XVisualInfo *vinfo = NULL;
   400 
   401 #if SDL_VIDEO_OPENGL_EGL
   402         if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES 
   403 #if SDL_VIDEO_OPENGL_GLX            
   404             && ( !_this->gl_data || X11_GL_UseEGL(_this) )
   405 #endif
   406         ) {
   407             vinfo = X11_GLES_GetVisual(_this, display, screen);
   408         } else
   409 #endif
   410         {
   411 #if SDL_VIDEO_OPENGL_GLX
   412             vinfo = X11_GL_GetVisual(_this, display, screen);
   413 #endif
   414         }
   415 
   416         if (!vinfo) {
   417             return -1;
   418         }
   419         visual = vinfo->visual;
   420         depth = vinfo->depth;
   421         X11_XFree(vinfo);
   422     } else
   423 #endif
   424     {
   425         visual = displaydata->visual;
   426         depth = displaydata->depth;
   427     }
   428 
   429     xattr.override_redirect = ((window->flags & SDL_WINDOW_TOOLTIP) || (window->flags & SDL_WINDOW_POPUP_MENU)) ? True : False;
   430     xattr.background_pixmap = None;
   431     xattr.border_pixel = 0;
   432 
   433     if (visual->class == DirectColor) {
   434         XColor *colorcells;
   435         int i;
   436         int ncolors;
   437         int rmax, gmax, bmax;
   438         int rmask, gmask, bmask;
   439         int rshift, gshift, bshift;
   440 
   441         xattr.colormap =
   442             X11_XCreateColormap(display, RootWindow(display, screen),
   443                             visual, AllocAll);
   444 
   445         /* If we can't create a colormap, then we must die */
   446         if (!xattr.colormap) {
   447             return SDL_SetError("Could not create writable colormap");
   448         }
   449 
   450         /* OK, we got a colormap, now fill it in as best as we can */
   451         colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   452         if (!colorcells) {
   453             return SDL_OutOfMemory();
   454         }
   455         ncolors = visual->map_entries;
   456         rmax = 0xffff;
   457         gmax = 0xffff;
   458         bmax = 0xffff;
   459 
   460         rshift = 0;
   461         rmask = visual->red_mask;
   462         while (0 == (rmask & 1)) {
   463             rshift++;
   464             rmask >>= 1;
   465         }
   466 
   467         gshift = 0;
   468         gmask = visual->green_mask;
   469         while (0 == (gmask & 1)) {
   470             gshift++;
   471             gmask >>= 1;
   472         }
   473 
   474         bshift = 0;
   475         bmask = visual->blue_mask;
   476         while (0 == (bmask & 1)) {
   477             bshift++;
   478             bmask >>= 1;
   479         }
   480 
   481         /* build the color table pixel values */
   482         for (i = 0; i < ncolors; i++) {
   483             Uint32 red = (rmax * i) / (ncolors - 1);
   484             Uint32 green = (gmax * i) / (ncolors - 1);
   485             Uint32 blue = (bmax * i) / (ncolors - 1);
   486 
   487             Uint32 rbits = (rmask * i) / (ncolors - 1);
   488             Uint32 gbits = (gmask * i) / (ncolors - 1);
   489             Uint32 bbits = (bmask * i) / (ncolors - 1);
   490 
   491             Uint32 pix =
   492                 (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   493 
   494             colorcells[i].pixel = pix;
   495 
   496             colorcells[i].red = red;
   497             colorcells[i].green = green;
   498             colorcells[i].blue = blue;
   499 
   500             colorcells[i].flags = DoRed | DoGreen | DoBlue;
   501         }
   502 
   503         X11_XStoreColors(display, xattr.colormap, colorcells, ncolors);
   504 
   505         SDL_free(colorcells);
   506     } else {
   507         xattr.colormap =
   508             X11_XCreateColormap(display, RootWindow(display, screen),
   509                             visual, AllocNone);
   510     }
   511 
   512     w = X11_XCreateWindow(display, RootWindow(display, screen),
   513                       window->x, window->y, window->w, window->h,
   514                       0, depth, InputOutput, visual,
   515                       (CWOverrideRedirect | CWBackPixmap | CWBorderPixel |
   516                        CWColormap), &xattr);
   517     if (!w) {
   518         return SDL_SetError("Couldn't create window");
   519     }
   520 
   521     SetWindowBordered(display, screen, w,
   522                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
   523 
   524     sizehints = X11_XAllocSizeHints();
   525     /* Setup the normal size hints */
   526     sizehints->flags = 0;
   527     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   528         sizehints->min_width = sizehints->max_width = window->w;
   529         sizehints->min_height = sizehints->max_height = window->h;
   530         sizehints->flags |= (PMaxSize | PMinSize);
   531     }
   532     sizehints->x = window->x;
   533     sizehints->y = window->y;
   534     sizehints->flags |= USPosition;
   535 
   536     /* Setup the input hints so we get keyboard input */
   537     wmhints = X11_XAllocWMHints();
   538     wmhints->input = True;
   539     wmhints->window_group = data->window_group;
   540     wmhints->flags = InputHint | WindowGroupHint;
   541 
   542     /* Setup the class hints so we can get an icon (AfterStep) */
   543     classhints = X11_XAllocClassHint();
   544     classhints->res_name = data->classname;
   545     classhints->res_class = data->classname;
   546 
   547     /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */
   548     X11_XSetWMProperties(display, w, NULL, NULL, NULL, 0, sizehints, wmhints, classhints);
   549 
   550     X11_XFree(sizehints);
   551     X11_XFree(wmhints);
   552     X11_XFree(classhints);
   553     /* Set the PID related to the window for the given hostname, if possible */
   554     if (data->pid > 0) {
   555         long pid = (long) data->pid;
   556         _NET_WM_PID = X11_XInternAtom(display, "_NET_WM_PID", False);
   557         X11_XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace,
   558                         (unsigned char *) &pid, 1);
   559     }
   560 
   561     /* Set the window manager state */
   562     X11_SetNetWMState(_this, w, window->flags);
   563 
   564     compositor = 2;  /* don't disable compositing except for "normal" windows */
   565 
   566     if (window->flags & SDL_WINDOW_UTILITY) {
   567         wintype_name = "_NET_WM_WINDOW_TYPE_UTILITY";
   568     } else if (window->flags & SDL_WINDOW_TOOLTIP) {
   569         wintype_name = "_NET_WM_WINDOW_TYPE_TOOLTIP";
   570     } else if (window->flags & SDL_WINDOW_POPUP_MENU) {
   571         wintype_name = "_NET_WM_WINDOW_TYPE_POPUP_MENU";
   572     } else {
   573         wintype_name = "_NET_WM_WINDOW_TYPE_NORMAL";
   574         compositor = 1;  /* disable compositing for "normal" windows */
   575     }
   576 
   577     /* Let the window manager know what type of window we are. */
   578     _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
   579     wintype = X11_XInternAtom(display, wintype_name, False);
   580     X11_XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
   581                     PropModeReplace, (unsigned char *)&wintype, 1);
   582 
   583     _NET_WM_BYPASS_COMPOSITOR = X11_XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False);
   584     X11_XChangeProperty(display, w, _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
   585                     PropModeReplace,
   586                     (unsigned char *)&compositor, 1);
   587 
   588     {
   589         Atom protocols[3];
   590         int proto_count = 0;
   591 
   592         protocols[proto_count++] = data->WM_DELETE_WINDOW; /* Allow window to be deleted by the WM */
   593         protocols[proto_count++] = data->WM_TAKE_FOCUS; /* Since we will want to set input focus explicitly */
   594 
   595         /* Default to using ping if there is no hint */
   596         if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NET_WM_PING, SDL_TRUE)) {
   597             protocols[proto_count++] = data->_NET_WM_PING; /* Respond so WM knows we're alive */
   598         }
   599 
   600         SDL_assert(proto_count <= sizeof(protocols) / sizeof(protocols[0]));
   601 
   602         X11_XSetWMProtocols(display, w, protocols, proto_count);
   603     }
   604 
   605     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   606         X11_XDestroyWindow(display, w);
   607         return -1;
   608     }
   609     windowdata = (SDL_WindowData *) window->driverdata;
   610 
   611 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   612     if ((window->flags & SDL_WINDOW_OPENGL) && 
   613         _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
   614 #if SDL_VIDEO_OPENGL_GLX            
   615         && ( !_this->gl_data || X11_GL_UseEGL(_this) )
   616 #endif  
   617     ) {
   618 #if SDL_VIDEO_OPENGL_EGL  
   619         if (!_this->egl_data) {
   620             X11_XDestroyWindow(display, w);
   621             return -1;
   622         }
   623 
   624         /* Create the GLES window surface */
   625         windowdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) w);
   626 
   627         if (windowdata->egl_surface == EGL_NO_SURFACE) {
   628             X11_XDestroyWindow(display, w);
   629             return SDL_SetError("Could not create GLES window surface");
   630         }
   631 #else
   632         return SDL_SetError("Could not create GLES window surface (EGL support not configured)");
   633 #endif /* SDL_VIDEO_OPENGL_EGL */
   634     }
   635 #endif
   636     
   637 
   638 #ifdef X_HAVE_UTF8_STRING
   639     if (SDL_X11_HAVE_UTF8 && windowdata->ic) {
   640         X11_XGetICValues(windowdata->ic, XNFilterEvents, &fevent, NULL);
   641     }
   642 #endif
   643 
   644     X11_Xinput2SelectTouch(_this, window);
   645 
   646     X11_XSelectInput(display, w,
   647                  (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   648                  ExposureMask | ButtonPressMask | ButtonReleaseMask |
   649                  PointerMotionMask | KeyPressMask | KeyReleaseMask |
   650                  PropertyChangeMask | StructureNotifyMask |
   651                  KeymapStateMask | fevent));
   652 
   653     XdndAware = X11_XInternAtom(display, "XdndAware", False);
   654     X11_XChangeProperty(display, w, XdndAware, XA_ATOM, 32,
   655                  PropModeReplace,
   656                  (unsigned char*)&xdnd_version, 1);
   657 
   658     X11_XFlush(display);
   659 
   660     return 0;
   661 }
   662 
   663 int
   664 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   665 {
   666     Window w = (Window) data;
   667 
   668     window->title = X11_GetWindowTitle(_this, w);
   669 
   670     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   671         return -1;
   672     }
   673     return 0;
   674 }
   675 
   676 char *
   677 X11_GetWindowTitle(_THIS, Window xwindow)
   678 {
   679     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   680     Display *display = data->display;
   681     int status, real_format;
   682     Atom real_type;
   683     unsigned long items_read, items_left;
   684     unsigned char *propdata;
   685     char *title = NULL;
   686 
   687     status = X11_XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
   688                 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
   689                 &items_read, &items_left, &propdata);
   690     if (status == Success && propdata) {
   691         title = SDL_strdup(SDL_static_cast(char*, propdata));
   692         X11_XFree(propdata);
   693     } else {
   694         status = X11_XGetWindowProperty(display, xwindow, XA_WM_NAME,
   695                     0L, 8192L, False, XA_STRING, &real_type, &real_format,
   696                     &items_read, &items_left, &propdata);
   697         if (status == Success && propdata) {
   698             title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
   699             X11_XFree(propdata);
   700         } else {
   701             title = SDL_strdup("");
   702         }
   703     }
   704     return title;
   705 }
   706 
   707 void
   708 X11_SetWindowTitle(_THIS, SDL_Window * window)
   709 {
   710     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   711     Display *display = data->videodata->display;
   712     XTextProperty titleprop;
   713     Status status;
   714     const char *title = window->title ? window->title : "";
   715     char *title_locale = NULL;
   716 
   717 #ifdef X_HAVE_UTF8_STRING
   718     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   719 #endif
   720 
   721     title_locale = SDL_iconv_utf8_locale(title);
   722     if (!title_locale) {
   723         SDL_OutOfMemory();
   724         return;
   725     }
   726 
   727     status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
   728     SDL_free(title_locale);
   729     if (status) {
   730         X11_XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   731         X11_XFree(titleprop.value);
   732     }
   733 #ifdef X_HAVE_UTF8_STRING
   734     if (SDL_X11_HAVE_UTF8) {
   735         status = X11_Xutf8TextListToTextProperty(display, (char **) &title, 1,
   736                                             XUTF8StringStyle, &titleprop);
   737         if (status == Success) {
   738             X11_XSetTextProperty(display, data->xwindow, &titleprop,
   739                                  _NET_WM_NAME);
   740             X11_XFree(titleprop.value);
   741         }
   742     }
   743 #endif
   744 
   745     X11_XFlush(display);
   746 }
   747 
   748 void
   749 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   750 {
   751     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   752     Display *display = data->videodata->display;
   753     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   754 
   755     if (icon) {
   756         int propsize;
   757         long *propdata;
   758 
   759         /* Set the _NET_WM_ICON property */
   760         SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
   761         propsize = 2 + (icon->w * icon->h);
   762         propdata = SDL_malloc(propsize * sizeof(long));
   763         if (propdata) {
   764             int x, y;
   765             Uint32 *src;
   766             long *dst;
   767 
   768             propdata[0] = icon->w;
   769             propdata[1] = icon->h;
   770             dst = &propdata[2];
   771             for (y = 0; y < icon->h; ++y) {
   772                 src = (Uint32*)((Uint8*)icon->pixels + y * icon->pitch);
   773                 for (x = 0; x < icon->w; ++x) {
   774                     *dst++ = *src++;
   775                 }
   776             }
   777             X11_XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   778                             32, PropModeReplace, (unsigned char *) propdata,
   779                             propsize);
   780         }
   781         SDL_free(propdata);
   782     } else {
   783         X11_XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   784     }
   785     X11_XFlush(display);
   786 }
   787 
   788 void
   789 X11_SetWindowPosition(_THIS, SDL_Window * window)
   790 {
   791     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   792     Display *display = data->videodata->display;
   793 
   794     X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
   795     X11_XFlush(display);
   796 }
   797 
   798 void
   799 X11_SetWindowMinimumSize(_THIS, SDL_Window * window)
   800 {
   801     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   802     Display *display = data->videodata->display;
   803 
   804     if (window->flags & SDL_WINDOW_RESIZABLE) {
   805          XSizeHints *sizehints = X11_XAllocSizeHints();
   806          long userhints;
   807 
   808          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   809 
   810          sizehints->min_width = window->min_w;
   811          sizehints->min_height = window->min_h;
   812          sizehints->flags |= PMinSize;
   813 
   814          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   815 
   816          X11_XFree(sizehints);
   817 
   818         /* See comment in X11_SetWindowSize. */
   819         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   820         X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
   821         X11_XRaiseWindow(display, data->xwindow);
   822     }
   823 
   824     X11_XFlush(display);
   825 }
   826 
   827 void
   828 X11_SetWindowMaximumSize(_THIS, SDL_Window * window)
   829 {
   830     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   831     Display *display = data->videodata->display;
   832 
   833     if (window->flags & SDL_WINDOW_RESIZABLE) {
   834          XSizeHints *sizehints = X11_XAllocSizeHints();
   835          long userhints;
   836 
   837          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   838 
   839          sizehints->max_width = window->max_w;
   840          sizehints->max_height = window->max_h;
   841          sizehints->flags |= PMaxSize;
   842 
   843          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   844 
   845          X11_XFree(sizehints);
   846 
   847         /* See comment in X11_SetWindowSize. */
   848         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   849         X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
   850         X11_XRaiseWindow(display, data->xwindow);
   851     }
   852 
   853     X11_XFlush(display);
   854 }
   855 
   856 void
   857 X11_SetWindowSize(_THIS, SDL_Window * window)
   858 {
   859     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   860     Display *display = data->videodata->display;
   861 
   862     if (SDL_IsShapedWindow(window)) {
   863         X11_ResizeWindowShape(window);
   864     }
   865     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   866          /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the X11_XResizeWindow, thus
   867             we must set the size hints to adjust the window size. */
   868          XSizeHints *sizehints = X11_XAllocSizeHints();
   869          long userhints;
   870 
   871          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   872 
   873          sizehints->min_width = sizehints->max_width = window->w;
   874          sizehints->min_height = sizehints->max_height = window->h;
   875          sizehints->flags |= PMinSize | PMaxSize;
   876 
   877          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   878 
   879          X11_XFree(sizehints);
   880 
   881         /* From Pierre-Loup:
   882            WMs each have their little quirks with that.  When you change the
   883            size hints, they get a ConfigureNotify event with the
   884            WM_NORMAL_SIZE_HINTS Atom.  They all save the hints then, but they
   885            don't all resize the window right away to enforce the new hints.
   886 
   887            Some of them resize only after:
   888             - A user-initiated move or resize
   889             - A code-initiated move or resize
   890             - Hiding & showing window (Unmap & map)
   891 
   892            The following move & resize seems to help a lot of WMs that didn't
   893            properly update after the hints were changed. We don't do a
   894            hide/show, because there are supposedly subtle problems with doing so
   895            and transitioning from windowed to fullscreen in Unity.
   896          */
   897         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   898         X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
   899         X11_XRaiseWindow(display, data->xwindow);
   900     } else {
   901         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   902     }
   903 
   904     X11_XFlush(display);
   905 }
   906 
   907 int
   908 X11_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right)
   909 {
   910     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   911 
   912     *left = data->border_left;
   913     *right = data->border_right;
   914     *top = data->border_top;
   915     *bottom = data->border_bottom;
   916 
   917     return 0;
   918 }
   919 
   920 int
   921 X11_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
   922 {
   923     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   924     Display *display = data->videodata->display;
   925     Atom _NET_WM_WINDOW_OPACITY = data->videodata->_NET_WM_WINDOW_OPACITY;
   926 
   927     if (opacity == 1.0f) {
   928         X11_XDeleteProperty(display, data->xwindow, _NET_WM_WINDOW_OPACITY);
   929     } else  {
   930         const Uint32 FullyOpaque = 0xFFFFFFFF;
   931         const long alpha = (long) ((double)opacity * (double)FullyOpaque);
   932         X11_XChangeProperty(display, data->xwindow, _NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32,
   933             PropModeReplace, (unsigned char *)&alpha, 1);
   934     }
   935 
   936     return 0;
   937 }
   938 
   939 int 
   940 X11_SetWindowModalFor(_THIS, SDL_Window * modal_window, SDL_Window * parent_window) {
   941     SDL_WindowData *data = (SDL_WindowData *) modal_window->driverdata;
   942     SDL_WindowData *parent_data = (SDL_WindowData *) parent_window->driverdata;
   943     Display *display = data->videodata->display;
   944 
   945     X11_XSetTransientForHint(display, data->xwindow, parent_data->xwindow);
   946     return 0;
   947 }
   948 
   949 int
   950 X11_SetWindowInputFocus(_THIS, SDL_Window * window) 
   951 {
   952     if (X11_IsWindowMapped(_this, window)) {
   953         SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   954         Display *display = data->videodata->display;
   955         X11_XSetInputFocus(display, data->xwindow, RevertToNone, CurrentTime);
   956         X11_XFlush(display);
   957         return 0;
   958     }
   959     return -1;
   960 }
   961 
   962 void
   963 X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   964 {
   965     const SDL_bool focused = ((window->flags & SDL_WINDOW_INPUT_FOCUS) != 0);
   966     const SDL_bool visible = ((window->flags & SDL_WINDOW_HIDDEN) == 0);
   967     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   968     SDL_DisplayData *displaydata =
   969         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   970     Display *display = data->videodata->display;
   971     XEvent event;
   972 
   973     SetWindowBordered(display, displaydata->screen, data->xwindow, bordered);
   974     X11_XFlush(display);
   975 
   976     if (visible) {
   977         XWindowAttributes attr;
   978         do {
   979             X11_XSync(display, False);
   980             X11_XGetWindowAttributes(display, data->xwindow, &attr);
   981         } while (attr.map_state != IsViewable);
   982 
   983         if (focused) {
   984             X11_XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
   985         }
   986     }
   987 
   988     /* make sure these don't make it to the real event queue if they fired here. */
   989     X11_XSync(display, False);
   990     X11_XCheckIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
   991     X11_XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   992 }
   993 
   994 void
   995 X11_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
   996 {
   997     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   998     Display *display = data->videodata->display;
   999 
  1000     XSizeHints *sizehints = X11_XAllocSizeHints();
  1001     long userhints;
  1002 
  1003     X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
  1004 
  1005     if (resizable) {
  1006         /* FIXME: Is there a better way to get max window size from X? -flibit */
  1007         const int maxsize = 0x7FFFFFFF;
  1008         sizehints->min_width = window->min_w;
  1009         sizehints->min_height = window->min_h;
  1010         sizehints->max_width = (window->max_w == 0) ? maxsize : window->max_w;
  1011         sizehints->max_height = (window->max_h == 0) ? maxsize : window->max_h;
  1012     } else {
  1013         sizehints->min_width = window->w;
  1014         sizehints->min_height = window->h;
  1015         sizehints->max_width = window->w;
  1016         sizehints->max_height = window->h;
  1017     }
  1018     sizehints->flags |= PMinSize | PMaxSize;
  1019 
  1020     X11_XSetWMNormalHints(display, data->xwindow, sizehints);
  1021 
  1022     X11_XFree(sizehints);
  1023 
  1024     /* See comment in X11_SetWindowSize. */
  1025     X11_XResizeWindow(display, data->xwindow, window->w, window->h);
  1026     X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
  1027     X11_XRaiseWindow(display, data->xwindow);
  1028 
  1029     X11_XFlush(display);
  1030 }
  1031 
  1032 void
  1033 X11_ShowWindow(_THIS, SDL_Window * window)
  1034 {
  1035     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1036     Display *display = data->videodata->display;
  1037     XEvent event;
  1038 
  1039     if (!X11_IsWindowMapped(_this, window)) {
  1040         X11_XMapRaised(display, data->xwindow);
  1041         /* Blocking wait for "MapNotify" event.
  1042          * We use X11_XIfEvent because pXWindowEvent takes a mask rather than a type,
  1043          * and XCheckTypedWindowEvent doesn't block */
  1044         if(!(window->flags & SDL_WINDOW_FOREIGN))
  1045             X11_XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
  1046         X11_XFlush(display);
  1047     }
  1048 
  1049     if (!data->videodata->net_wm) {
  1050         /* no WM means no FocusIn event, which confuses us. Force it. */
  1051         X11_XSetInputFocus(display, data->xwindow, RevertToNone, CurrentTime);
  1052         X11_XFlush(display);
  1053     }
  1054 }
  1055 
  1056 void
  1057 X11_HideWindow(_THIS, SDL_Window * window)
  1058 {
  1059     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1060     SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  1061     Display *display = data->videodata->display;
  1062     XEvent event;
  1063 
  1064     if (X11_IsWindowMapped(_this, window)) {
  1065         X11_XWithdrawWindow(display, data->xwindow, displaydata->screen);
  1066         /* Blocking wait for "UnmapNotify" event */
  1067         if(!(window->flags & SDL_WINDOW_FOREIGN))
  1068             X11_XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
  1069         X11_XFlush(display);
  1070     }
  1071 }
  1072 
  1073 static void
  1074 SetWindowActive(_THIS, SDL_Window * window)
  1075 {
  1076     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1077     SDL_DisplayData *displaydata =
  1078         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  1079     Display *display = data->videodata->display;
  1080     Atom _NET_ACTIVE_WINDOW = data->videodata->_NET_ACTIVE_WINDOW;
  1081 
  1082     if (X11_IsWindowMapped(_this, window)) {
  1083         XEvent e;
  1084 
  1085         /*printf("SDL Window %p: sending _NET_ACTIVE_WINDOW with timestamp %lu\n", window, data->user_time);*/
  1086 
  1087         SDL_zero(e);
  1088         e.xany.type = ClientMessage;
  1089         e.xclient.message_type = _NET_ACTIVE_WINDOW;
  1090         e.xclient.format = 32;
  1091         e.xclient.window = data->xwindow;
  1092         e.xclient.data.l[0] = 1;  /* source indication. 1 = application */
  1093         e.xclient.data.l[1] = data->user_time;
  1094         e.xclient.data.l[2] = 0;
  1095 
  1096         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1097                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1098 
  1099         X11_XFlush(display);
  1100     }
  1101 }
  1102 
  1103 void
  1104 X11_RaiseWindow(_THIS, SDL_Window * window)
  1105 {
  1106     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1107     Display *display = data->videodata->display;
  1108 
  1109     X11_XRaiseWindow(display, data->xwindow);
  1110     SetWindowActive(_this, window);
  1111     X11_XFlush(display);
  1112 }
  1113 
  1114 static void
  1115 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
  1116 {
  1117     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1118     SDL_DisplayData *displaydata =
  1119         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  1120     Display *display = data->videodata->display;
  1121     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
  1122     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
  1123     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
  1124 
  1125     if (maximized) {
  1126         window->flags |= SDL_WINDOW_MAXIMIZED;
  1127     } else {
  1128         window->flags &= ~SDL_WINDOW_MAXIMIZED;
  1129     }
  1130 
  1131     if (X11_IsWindowMapped(_this, window)) {
  1132         XEvent e;
  1133 
  1134         SDL_zero(e);
  1135         e.xany.type = ClientMessage;
  1136         e.xclient.message_type = _NET_WM_STATE;
  1137         e.xclient.format = 32;
  1138         e.xclient.window = data->xwindow;
  1139         e.xclient.data.l[0] =
  1140             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  1141         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
  1142         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
  1143         e.xclient.data.l[3] = 0l;
  1144 
  1145         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1146                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1147     } else {
  1148         X11_SetNetWMState(_this, data->xwindow, window->flags);
  1149     }
  1150     X11_XFlush(display);
  1151 }
  1152 
  1153 void
  1154 X11_MaximizeWindow(_THIS, SDL_Window * window)
  1155 {
  1156     SetWindowMaximized(_this, window, SDL_TRUE);
  1157 }
  1158 
  1159 void
  1160 X11_MinimizeWindow(_THIS, SDL_Window * window)
  1161 {
  1162     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1163     SDL_DisplayData *displaydata =
  1164         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  1165     Display *display = data->videodata->display;
  1166 
  1167     X11_XIconifyWindow(display, data->xwindow, displaydata->screen);
  1168     X11_XFlush(display);
  1169 }
  1170 
  1171 void
  1172 X11_RestoreWindow(_THIS, SDL_Window * window)
  1173 {
  1174     SetWindowMaximized(_this, window, SDL_FALSE);
  1175     X11_ShowWindow(_this, window);
  1176     SetWindowActive(_this, window);
  1177 }
  1178 
  1179 /* This asks the Window Manager to handle fullscreen for us. This is the modern way. */
  1180 static void
  1181 X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1182 {
  1183     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1184     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1185     Display *display = data->videodata->display;
  1186     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
  1187     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
  1188 
  1189     if (X11_IsWindowMapped(_this, window)) {
  1190         XEvent e;
  1191 
  1192         if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
  1193             /* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we
  1194                can be resized to the fullscreen resolution (or reset so we're not resizable again) */
  1195             XSizeHints *sizehints = X11_XAllocSizeHints();
  1196             long flags = 0;
  1197             X11_XGetWMNormalHints(display, data->xwindow, sizehints, &flags);
  1198             /* set the resize flags on */
  1199             if (fullscreen) {
  1200                 /* we are going fullscreen so turn the flags off */
  1201                 sizehints->flags &= ~(PMinSize | PMaxSize);
  1202             } else {
  1203                 /* Reset the min/max width height to make the window non-resizable again */
  1204                 sizehints->flags |= PMinSize | PMaxSize;
  1205                 sizehints->min_width = sizehints->max_width = window->windowed.w;
  1206                 sizehints->min_height = sizehints->max_height = window->windowed.h;
  1207             }
  1208             X11_XSetWMNormalHints(display, data->xwindow, sizehints);
  1209             X11_XFree(sizehints);
  1210         }
  1211 
  1212         SDL_zero(e);
  1213         e.xany.type = ClientMessage;
  1214         e.xclient.message_type = _NET_WM_STATE;
  1215         e.xclient.format = 32;
  1216         e.xclient.window = data->xwindow;
  1217         e.xclient.data.l[0] =
  1218             fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  1219         e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
  1220         e.xclient.data.l[3] = 0l;
  1221 
  1222         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1223                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1224 
  1225         /* Fullscreen windows sometimes end up being marked maximized by
  1226             window managers. Force it back to how we expect it to be. */
  1227         if (!fullscreen && ((window->flags & SDL_WINDOW_MAXIMIZED) == 0)) {
  1228             SDL_zero(e);
  1229             e.xany.type = ClientMessage;
  1230             e.xclient.message_type = _NET_WM_STATE;
  1231             e.xclient.format = 32;
  1232             e.xclient.window = data->xwindow;
  1233             e.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
  1234             e.xclient.data.l[1] = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
  1235             e.xclient.data.l[2] = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
  1236             e.xclient.data.l[3] = 0l;
  1237             X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1238                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1239         }
  1240     } else {
  1241         Uint32 flags;
  1242 
  1243         flags = window->flags;
  1244         if (fullscreen) {
  1245             flags |= SDL_WINDOW_FULLSCREEN;
  1246         } else {
  1247             flags &= ~SDL_WINDOW_FULLSCREEN;
  1248         }
  1249         X11_SetNetWMState(_this, data->xwindow, flags);
  1250     }
  1251 
  1252     if (data->visual->class == DirectColor) {
  1253         if ( fullscreen ) {
  1254             X11_XInstallColormap(display, data->colormap);
  1255         } else {
  1256             X11_XUninstallColormap(display, data->colormap);
  1257         }
  1258     }
  1259 
  1260     X11_XFlush(display);
  1261 }
  1262 
  1263 /* This handles fullscreen itself, outside the Window Manager. */
  1264 static void
  1265 X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1266 {
  1267     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1268     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1269     Visual *visual = data->visual;
  1270     Display *display = data->videodata->display;
  1271     const int screen = displaydata->screen;
  1272     Window root = RootWindow(display, screen);
  1273     const int def_vis = (visual == DefaultVisual(display, screen));
  1274     unsigned long xattrmask = 0;
  1275     XSetWindowAttributes xattr;
  1276     XEvent ev;
  1277     SDL_Rect rect;
  1278 
  1279     if ( data->fswindow ) {
  1280         return;  /* already fullscreen, I hope. */
  1281     }
  1282 
  1283     X11_GetDisplayBounds(_this, _display, &rect);
  1284 
  1285     SDL_zero(xattr);
  1286     xattr.override_redirect = True;
  1287     xattrmask |= CWOverrideRedirect;
  1288     xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
  1289     xattrmask |= CWBackPixel;
  1290     xattr.border_pixel = 0;
  1291     xattrmask |= CWBorderPixel;
  1292     xattr.colormap = data->colormap;
  1293     xattrmask |= CWColormap;
  1294 
  1295     data->fswindow = X11_XCreateWindow(display, root,
  1296                                    rect.x, rect.y, rect.w, rect.h, 0,
  1297                                    displaydata->depth, InputOutput,
  1298                                    visual, xattrmask, &xattr);
  1299 
  1300     X11_XSelectInput(display, data->fswindow, StructureNotifyMask);
  1301     X11_XSetWindowBackground(display, data->fswindow, 0);
  1302     X11_XInstallColormap(display, data->colormap);
  1303     X11_XClearWindow(display, data->fswindow);
  1304     X11_XMapRaised(display, data->fswindow);
  1305 
  1306     /* Make sure the fswindow is in view by warping mouse to the corner */
  1307     X11_XUngrabPointer(display, CurrentTime);
  1308     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1309 
  1310     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1311     X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
  1312     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1313 
  1314 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
  1315     if ( displaydata->use_vidmode ) {
  1316         X11_XF86VidModeLockModeSwitch(display, screen, True);
  1317     }
  1318 #endif
  1319 
  1320     SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
  1321 
  1322     /* Center actual window within our cover-the-screen window. */
  1323     X11_XReparentWindow(display, data->xwindow, data->fswindow,
  1324                     (rect.w - window->w) / 2, (rect.h - window->h) / 2);
  1325 
  1326     /* Move the mouse to the upper left to make sure it's on-screen */
  1327     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1328 
  1329     /* Center mouse in the fullscreen window. */
  1330     rect.x += (rect.w / 2);
  1331     rect.y += (rect.h / 2);
  1332     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1333 
  1334     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1335     X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1336     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1337 
  1338     SDL_UpdateWindowGrab(window);
  1339 }
  1340 
  1341 static void
  1342 X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1343 {
  1344     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1345     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1346     Display *display = data->videodata->display;
  1347     const int screen = displaydata->screen;
  1348     Window root = RootWindow(display, screen);
  1349     Window fswindow = data->fswindow;
  1350     XEvent ev;
  1351 
  1352     if (!data->fswindow) {
  1353         return;  /* already not fullscreen, I hope. */
  1354     }
  1355 
  1356     data->fswindow = None;
  1357 
  1358 #if SDL_VIDEO_DRIVER_X11_VIDMODE
  1359     if ( displaydata->use_vidmode ) {
  1360         X11_XF86VidModeLockModeSwitch(display, screen, False);
  1361     }
  1362 #endif
  1363 
  1364     SDL_UpdateWindowGrab(window);
  1365 
  1366     X11_XReparentWindow(display, data->xwindow, root, window->x, window->y);
  1367 
  1368     /* flush these events so they don't confuse normal event handling */
  1369     X11_XSync(display, False);
  1370     X11_XCheckIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1371     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1372 
  1373     SetWindowBordered(display, screen, data->xwindow,
  1374                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1375 
  1376     X11_XWithdrawWindow(display, fswindow, screen);
  1377 
  1378     /* Wait to be unmapped. */
  1379     X11_XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&fswindow);
  1380     X11_XDestroyWindow(display, fswindow);
  1381 }
  1382 
  1383 
  1384 void
  1385 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1386 {
  1387     /* !!! FIXME: SDL_Hint? */
  1388     SDL_bool legacy = SDL_FALSE;
  1389     const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
  1390     if (env) {
  1391         legacy = SDL_atoi(env);
  1392     } else {
  1393         SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1394         SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1395         if ( displaydata->use_vidmode ) {
  1396             legacy = SDL_TRUE;  /* the new stuff only works with XRandR. */
  1397         } else if ( !videodata->net_wm ) {
  1398             legacy = SDL_TRUE;  /* The window manager doesn't support it */
  1399         } else {
  1400             /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
  1401             /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
  1402             legacy = SDL_FALSE;  /* try the new way. */
  1403         }
  1404     }
  1405 
  1406     if (legacy) {
  1407         if (fullscreen) {
  1408             X11_BeginWindowFullscreenLegacy(_this, window, _display);
  1409         } else {
  1410             X11_EndWindowFullscreenLegacy(_this, window, _display);
  1411         }
  1412     } else {
  1413         X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
  1414     }
  1415 }
  1416 
  1417 
  1418 int
  1419 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1420 {
  1421     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1422     Display *display = data->videodata->display;
  1423     Visual *visual = data->visual;
  1424     Colormap colormap = data->colormap;
  1425     XColor *colorcells;
  1426     int ncolors;
  1427     int rmask, gmask, bmask;
  1428     int rshift, gshift, bshift;
  1429     int i;
  1430 
  1431     if (visual->class != DirectColor) {
  1432         return SDL_SetError("Window doesn't have DirectColor visual");
  1433     }
  1434 
  1435     ncolors = visual->map_entries;
  1436     colorcells = SDL_malloc(ncolors * sizeof(XColor));
  1437     if (!colorcells) {
  1438         return SDL_OutOfMemory();
  1439     }
  1440 
  1441     rshift = 0;
  1442     rmask = visual->red_mask;
  1443     while (0 == (rmask & 1)) {
  1444         rshift++;
  1445         rmask >>= 1;
  1446     }
  1447 
  1448     gshift = 0;
  1449     gmask = visual->green_mask;
  1450     while (0 == (gmask & 1)) {
  1451         gshift++;
  1452         gmask >>= 1;
  1453     }
  1454 
  1455     bshift = 0;
  1456     bmask = visual->blue_mask;
  1457     while (0 == (bmask & 1)) {
  1458         bshift++;
  1459         bmask >>= 1;
  1460     }
  1461 
  1462     /* build the color table pixel values */
  1463     for (i = 0; i < ncolors; i++) {
  1464         Uint32 rbits = (rmask * i) / (ncolors - 1);
  1465         Uint32 gbits = (gmask * i) / (ncolors - 1);
  1466         Uint32 bbits = (bmask * i) / (ncolors - 1);
  1467         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
  1468 
  1469         colorcells[i].pixel = pix;
  1470 
  1471         colorcells[i].red = ramp[(0 * 256) + i];
  1472         colorcells[i].green = ramp[(1 * 256) + i];
  1473         colorcells[i].blue = ramp[(2 * 256) + i];
  1474 
  1475         colorcells[i].flags = DoRed | DoGreen | DoBlue;
  1476     }
  1477 
  1478     X11_XStoreColors(display, colormap, colorcells, ncolors);
  1479     X11_XFlush(display);
  1480     SDL_free(colorcells);
  1481 
  1482     return 0;
  1483 }
  1484 
  1485 void
  1486 X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
  1487 {
  1488     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1489     Display *display = data->videodata->display;
  1490     SDL_bool oldstyle_fullscreen;
  1491     SDL_bool grab_keyboard;
  1492 
  1493     /* ICCCM2.0-compliant window managers can handle fullscreen windows
  1494        If we're using XVidMode to change resolution we need to confine
  1495        the cursor so we don't pan around the virtual desktop.
  1496      */
  1497     oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
  1498 
  1499     if (oldstyle_fullscreen || grabbed) {
  1500         /* Try to grab the mouse */
  1501         if (!data->videodata->broken_pointer_grab) {
  1502             int attempts;
  1503             int result;
  1504 
  1505             /* Try for up to 5000ms (5s) to grab. If it still fails, stop trying. */
  1506             for (attempts = 0; attempts < 100; attempts++) {
  1507                 result = X11_XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1508                                  GrabModeAsync, data->xwindow, None, CurrentTime);
  1509                 if (result == GrabSuccess) {
  1510                     break;
  1511                 }
  1512                 SDL_Delay(50);
  1513             }
  1514 
  1515             if (result != GrabSuccess) {
  1516                 SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "The X server refused to let us grab the mouse. You might experience input bugs.");
  1517                 data->videodata->broken_pointer_grab = SDL_TRUE;  /* don't try again. */
  1518             }
  1519         }
  1520 
  1521         /* Raise the window if we grab the mouse */
  1522         X11_XRaiseWindow(display, data->xwindow);
  1523 
  1524         /* Now grab the keyboard */
  1525         if (SDL_GetHintBoolean(SDL_HINT_GRAB_KEYBOARD, SDL_FALSE)) {
  1526             grab_keyboard = SDL_TRUE;
  1527         } else {
  1528             /* We need to do this with the old style override_redirect
  1529                fullscreen window otherwise we won't get keyboard focus.
  1530             */
  1531             grab_keyboard = oldstyle_fullscreen;
  1532         }
  1533         if (grab_keyboard) {
  1534             X11_XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1535                           GrabModeAsync, CurrentTime);
  1536         }
  1537     } else {
  1538         X11_XUngrabPointer(display, CurrentTime);
  1539         X11_XUngrabKeyboard(display, CurrentTime);
  1540     }
  1541     X11_XSync(display, False);
  1542 }
  1543 
  1544 void
  1545 X11_DestroyWindow(_THIS, SDL_Window * window)
  1546 {
  1547     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1548 
  1549     if (data) {
  1550         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1551         Display *display = videodata->display;
  1552         int numwindows = videodata->numwindows;
  1553         SDL_WindowData **windowlist = videodata->windowlist;
  1554         int i;
  1555 
  1556         if (windowlist) {
  1557             for (i = 0; i < numwindows; ++i) {
  1558                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1559                     windowlist[i] = windowlist[numwindows - 1];
  1560                     windowlist[numwindows - 1] = NULL;
  1561                     videodata->numwindows--;
  1562                     break;
  1563                 }
  1564             }
  1565         }
  1566 #ifdef X_HAVE_UTF8_STRING
  1567         if (data->ic) {
  1568             X11_XDestroyIC(data->ic);
  1569         }
  1570 #endif
  1571         if (data->created) {
  1572             X11_XDestroyWindow(display, data->xwindow);
  1573             X11_XFlush(display);
  1574         }
  1575         SDL_free(data);
  1576     }
  1577     window->driverdata = NULL;
  1578 }
  1579 
  1580 SDL_bool
  1581 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1582 {
  1583     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1584     Display *display = data->videodata->display;
  1585 
  1586     if (info->version.major == SDL_MAJOR_VERSION &&
  1587         info->version.minor == SDL_MINOR_VERSION) {
  1588         info->subsystem = SDL_SYSWM_X11;
  1589         info->info.x11.display = display;
  1590         info->info.x11.window = data->xwindow;
  1591         return SDL_TRUE;
  1592     } else {
  1593         SDL_SetError("Application not compiled with SDL %d.%d",
  1594                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1595         return SDL_FALSE;
  1596     }
  1597 }
  1598 
  1599 int
  1600 X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
  1601 {
  1602     return 0;  /* just succeed, the real work is done elsewhere. */
  1603 }
  1604 
  1605 #endif /* SDL_VIDEO_DRIVER_X11 */
  1606 
  1607 /* vi: set ts=4 sw=4 expandtab: */