src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 18 Jan 2020 11:21:42 -0800
changeset 13430 c32f98490438
parent 13422 fd6a12de91c7
permissions -rw-r--r--
Added missing file from previous commit
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2020 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     long fevent = 0;
   394 
   395 #if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_EGL
   396     const char *forced_visual_id = SDL_GetHint(SDL_HINT_VIDEO_X11_WINDOW_VISUALID);
   397 
   398     if (forced_visual_id != NULL && forced_visual_id[0] != '\0')
   399     {
   400         XVisualInfo *vi, template;
   401         int nvis;
   402 
   403         SDL_zero(template);
   404         template.visualid = SDL_strtol(forced_visual_id, NULL, 0);
   405         vi = X11_XGetVisualInfo(display, VisualIDMask, &template, &nvis);
   406         if (vi) {
   407             visual = vi->visual;
   408             depth = vi->depth;
   409             X11_XFree(vi);
   410         }
   411         else
   412         {
   413             return -1;
   414         }
   415     }
   416     else if ((window->flags & SDL_WINDOW_OPENGL) &&
   417         !SDL_getenv("SDL_VIDEO_X11_VISUALID")) {
   418         XVisualInfo *vinfo = NULL;
   419 
   420 #if SDL_VIDEO_OPENGL_EGL
   421         if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES 
   422 #if SDL_VIDEO_OPENGL_GLX            
   423             && ( !_this->gl_data || X11_GL_UseEGL(_this) )
   424 #endif
   425         ) {
   426             vinfo = X11_GLES_GetVisual(_this, display, screen);
   427         } else
   428 #endif
   429         {
   430 #if SDL_VIDEO_OPENGL_GLX
   431             vinfo = X11_GL_GetVisual(_this, display, screen);
   432 #endif
   433         }
   434 
   435         if (!vinfo) {
   436             return -1;
   437         }
   438         visual = vinfo->visual;
   439         depth = vinfo->depth;
   440         X11_XFree(vinfo);
   441     } else
   442 #endif
   443     {
   444         visual = displaydata->visual;
   445         depth = displaydata->depth;
   446     }
   447 
   448     xattr.override_redirect = ((window->flags & SDL_WINDOW_TOOLTIP) || (window->flags & SDL_WINDOW_POPUP_MENU)) ? True : False;
   449     xattr.background_pixmap = None;
   450     xattr.border_pixel = 0;
   451 
   452     if (visual->class == DirectColor) {
   453         XColor *colorcells;
   454         int i;
   455         int ncolors;
   456         int rmax, gmax, bmax;
   457         int rmask, gmask, bmask;
   458         int rshift, gshift, bshift;
   459 
   460         xattr.colormap =
   461             X11_XCreateColormap(display, RootWindow(display, screen),
   462                             visual, AllocAll);
   463 
   464         /* If we can't create a colormap, then we must die */
   465         if (!xattr.colormap) {
   466             return SDL_SetError("Could not create writable colormap");
   467         }
   468 
   469         /* OK, we got a colormap, now fill it in as best as we can */
   470         colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   471         if (!colorcells) {
   472             return SDL_OutOfMemory();
   473         }
   474         ncolors = visual->map_entries;
   475         rmax = 0xffff;
   476         gmax = 0xffff;
   477         bmax = 0xffff;
   478 
   479         rshift = 0;
   480         rmask = visual->red_mask;
   481         while (0 == (rmask & 1)) {
   482             rshift++;
   483             rmask >>= 1;
   484         }
   485 
   486         gshift = 0;
   487         gmask = visual->green_mask;
   488         while (0 == (gmask & 1)) {
   489             gshift++;
   490             gmask >>= 1;
   491         }
   492 
   493         bshift = 0;
   494         bmask = visual->blue_mask;
   495         while (0 == (bmask & 1)) {
   496             bshift++;
   497             bmask >>= 1;
   498         }
   499 
   500         /* build the color table pixel values */
   501         for (i = 0; i < ncolors; i++) {
   502             Uint32 red = (rmax * i) / (ncolors - 1);
   503             Uint32 green = (gmax * i) / (ncolors - 1);
   504             Uint32 blue = (bmax * i) / (ncolors - 1);
   505 
   506             Uint32 rbits = (rmask * i) / (ncolors - 1);
   507             Uint32 gbits = (gmask * i) / (ncolors - 1);
   508             Uint32 bbits = (bmask * i) / (ncolors - 1);
   509 
   510             Uint32 pix =
   511                 (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   512 
   513             colorcells[i].pixel = pix;
   514 
   515             colorcells[i].red = red;
   516             colorcells[i].green = green;
   517             colorcells[i].blue = blue;
   518 
   519             colorcells[i].flags = DoRed | DoGreen | DoBlue;
   520         }
   521 
   522         X11_XStoreColors(display, xattr.colormap, colorcells, ncolors);
   523 
   524         SDL_free(colorcells);
   525     } else {
   526         xattr.colormap =
   527             X11_XCreateColormap(display, RootWindow(display, screen),
   528                             visual, AllocNone);
   529     }
   530 
   531     w = X11_XCreateWindow(display, RootWindow(display, screen),
   532                       window->x, window->y, window->w, window->h,
   533                       0, depth, InputOutput, visual,
   534                       (CWOverrideRedirect | CWBackPixmap | CWBorderPixel |
   535                        CWColormap), &xattr);
   536     if (!w) {
   537         return SDL_SetError("Couldn't create window");
   538     }
   539 
   540     SetWindowBordered(display, screen, w,
   541                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
   542 
   543     sizehints = X11_XAllocSizeHints();
   544     /* Setup the normal size hints */
   545     sizehints->flags = 0;
   546     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   547         sizehints->min_width = sizehints->max_width = window->w;
   548         sizehints->min_height = sizehints->max_height = window->h;
   549         sizehints->flags |= (PMaxSize | PMinSize);
   550     }
   551     sizehints->x = window->x;
   552     sizehints->y = window->y;
   553     sizehints->flags |= USPosition;
   554 
   555     /* Setup the input hints so we get keyboard input */
   556     wmhints = X11_XAllocWMHints();
   557     wmhints->input = True;
   558     wmhints->window_group = data->window_group;
   559     wmhints->flags = InputHint | WindowGroupHint;
   560 
   561     /* Setup the class hints so we can get an icon (AfterStep) */
   562     classhints = X11_XAllocClassHint();
   563     classhints->res_name = data->classname;
   564     classhints->res_class = data->classname;
   565 
   566     /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */
   567     X11_XSetWMProperties(display, w, NULL, NULL, NULL, 0, sizehints, wmhints, classhints);
   568 
   569     X11_XFree(sizehints);
   570     X11_XFree(wmhints);
   571     X11_XFree(classhints);
   572     /* Set the PID related to the window for the given hostname, if possible */
   573     if (data->pid > 0) {
   574         long pid = (long) data->pid;
   575         _NET_WM_PID = X11_XInternAtom(display, "_NET_WM_PID", False);
   576         X11_XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace,
   577                         (unsigned char *) &pid, 1);
   578     }
   579 
   580     /* Set the window manager state */
   581     X11_SetNetWMState(_this, w, window->flags);
   582 
   583     compositor = 2;  /* don't disable compositing except for "normal" windows */
   584 
   585     if (window->flags & SDL_WINDOW_UTILITY) {
   586         wintype_name = "_NET_WM_WINDOW_TYPE_UTILITY";
   587     } else if (window->flags & SDL_WINDOW_TOOLTIP) {
   588         wintype_name = "_NET_WM_WINDOW_TYPE_TOOLTIP";
   589     } else if (window->flags & SDL_WINDOW_POPUP_MENU) {
   590         wintype_name = "_NET_WM_WINDOW_TYPE_POPUP_MENU";
   591     } else {
   592         wintype_name = "_NET_WM_WINDOW_TYPE_NORMAL";
   593         compositor = 1;  /* disable compositing for "normal" windows */
   594     }
   595 
   596     /* Let the window manager know what type of window we are. */
   597     _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
   598     wintype = X11_XInternAtom(display, wintype_name, False);
   599     X11_XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
   600                     PropModeReplace, (unsigned char *)&wintype, 1);
   601     if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, SDL_TRUE)) {
   602         _NET_WM_BYPASS_COMPOSITOR = X11_XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False);
   603         X11_XChangeProperty(display, w, _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
   604                         PropModeReplace,
   605                         (unsigned char *)&compositor, 1);
   606     }
   607 
   608     {
   609         Atom protocols[3];
   610         int proto_count = 0;
   611 
   612         protocols[proto_count++] = data->WM_DELETE_WINDOW; /* Allow window to be deleted by the WM */
   613         protocols[proto_count++] = data->WM_TAKE_FOCUS; /* Since we will want to set input focus explicitly */
   614 
   615         /* Default to using ping if there is no hint */
   616         if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NET_WM_PING, SDL_TRUE)) {
   617             protocols[proto_count++] = data->_NET_WM_PING; /* Respond so WM knows we're alive */
   618         }
   619 
   620         SDL_assert(proto_count <= sizeof(protocols) / sizeof(protocols[0]));
   621 
   622         X11_XSetWMProtocols(display, w, protocols, proto_count);
   623     }
   624 
   625     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   626         X11_XDestroyWindow(display, w);
   627         return -1;
   628     }
   629     windowdata = (SDL_WindowData *) window->driverdata;
   630 
   631 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   632     if ((window->flags & SDL_WINDOW_OPENGL) && 
   633         _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
   634 #if SDL_VIDEO_OPENGL_GLX            
   635         && ( !_this->gl_data || X11_GL_UseEGL(_this) )
   636 #endif  
   637     ) {
   638 #if SDL_VIDEO_OPENGL_EGL  
   639         if (!_this->egl_data) {
   640             return -1;
   641         }
   642 
   643         /* Create the GLES window surface */
   644         windowdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) w);
   645 
   646         if (windowdata->egl_surface == EGL_NO_SURFACE) {
   647             return SDL_SetError("Could not create GLES window surface");
   648         }
   649 #else
   650         return SDL_SetError("Could not create GLES window surface (EGL support not configured)");
   651 #endif /* SDL_VIDEO_OPENGL_EGL */
   652     }
   653 #endif
   654     
   655 
   656 #ifdef X_HAVE_UTF8_STRING
   657     if (SDL_X11_HAVE_UTF8 && windowdata->ic) {
   658         X11_XGetICValues(windowdata->ic, XNFilterEvents, &fevent, NULL);
   659     }
   660 #endif
   661 
   662     X11_Xinput2SelectTouch(_this, window);
   663 
   664     X11_XSelectInput(display, w,
   665                  (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   666                  ExposureMask | ButtonPressMask | ButtonReleaseMask |
   667                  PointerMotionMask | KeyPressMask | KeyReleaseMask |
   668                  PropertyChangeMask | StructureNotifyMask |
   669                  KeymapStateMask | fevent));
   670 
   671     X11_XFlush(display);
   672 
   673     return 0;
   674 }
   675 
   676 int
   677 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   678 {
   679     Window w = (Window) data;
   680 
   681     window->title = X11_GetWindowTitle(_this, w);
   682 
   683     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   684         return -1;
   685     }
   686     return 0;
   687 }
   688 
   689 char *
   690 X11_GetWindowTitle(_THIS, Window xwindow)
   691 {
   692     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   693     Display *display = data->display;
   694     int status, real_format;
   695     Atom real_type;
   696     unsigned long items_read, items_left;
   697     unsigned char *propdata;
   698     char *title = NULL;
   699 
   700     status = X11_XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
   701                 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
   702                 &items_read, &items_left, &propdata);
   703     if (status == Success && propdata) {
   704         title = SDL_strdup(SDL_static_cast(char*, propdata));
   705         X11_XFree(propdata);
   706     } else {
   707         status = X11_XGetWindowProperty(display, xwindow, XA_WM_NAME,
   708                     0L, 8192L, False, XA_STRING, &real_type, &real_format,
   709                     &items_read, &items_left, &propdata);
   710         if (status == Success && propdata) {
   711             title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
   712             X11_XFree(propdata);
   713         } else {
   714             title = SDL_strdup("");
   715         }
   716     }
   717     return title;
   718 }
   719 
   720 void
   721 X11_SetWindowTitle(_THIS, SDL_Window * window)
   722 {
   723     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   724     Display *display = data->videodata->display;
   725     XTextProperty titleprop;
   726     Status status;
   727     const char *title = window->title ? window->title : "";
   728     char *title_locale = NULL;
   729 
   730 #ifdef X_HAVE_UTF8_STRING
   731     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   732 #endif
   733 
   734     title_locale = SDL_iconv_utf8_locale(title);
   735     if (!title_locale) {
   736         SDL_OutOfMemory();
   737         return;
   738     }
   739 
   740     status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
   741     SDL_free(title_locale);
   742     if (status) {
   743         X11_XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   744         X11_XFree(titleprop.value);
   745     }
   746 #ifdef X_HAVE_UTF8_STRING
   747     if (SDL_X11_HAVE_UTF8) {
   748         status = X11_Xutf8TextListToTextProperty(display, (char **) &title, 1,
   749                                             XUTF8StringStyle, &titleprop);
   750         if (status == Success) {
   751             X11_XSetTextProperty(display, data->xwindow, &titleprop,
   752                                  _NET_WM_NAME);
   753             X11_XFree(titleprop.value);
   754         }
   755     }
   756 #endif
   757 
   758     X11_XFlush(display);
   759 }
   760 
   761 void
   762 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   763 {
   764     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   765     Display *display = data->videodata->display;
   766     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   767 
   768     if (icon) {
   769         int propsize;
   770         long *propdata;
   771 
   772         /* Set the _NET_WM_ICON property */
   773         SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
   774         propsize = 2 + (icon->w * icon->h);
   775         propdata = SDL_malloc(propsize * sizeof(long));
   776         if (propdata) {
   777             int x, y;
   778             Uint32 *src;
   779             long *dst;
   780 
   781             propdata[0] = icon->w;
   782             propdata[1] = icon->h;
   783             dst = &propdata[2];
   784             for (y = 0; y < icon->h; ++y) {
   785                 src = (Uint32*)((Uint8*)icon->pixels + y * icon->pitch);
   786                 for (x = 0; x < icon->w; ++x) {
   787                     *dst++ = *src++;
   788                 }
   789             }
   790             X11_XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   791                             32, PropModeReplace, (unsigned char *) propdata,
   792                             propsize);
   793         }
   794         SDL_free(propdata);
   795     } else {
   796         X11_XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   797     }
   798     X11_XFlush(display);
   799 }
   800 
   801 void
   802 X11_SetWindowPosition(_THIS, SDL_Window * window)
   803 {
   804     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   805     Display *display = data->videodata->display;
   806     unsigned int childCount;
   807     Window childReturn, root, parent;
   808     Window* children;
   809     XWindowAttributes attrs;
   810 
   811     /*Attempt to move the window*/
   812     X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
   813     X11_XFlush(display);
   814 
   815     /*If the window is not moved, then the coordinates on the window structure are out of sync, so we
   816       update them here. */
   817     X11_XQueryTree(display, data->xwindow, &root, &parent, &children, &childCount);
   818     X11_XGetWindowAttributes(display, data->xwindow, &attrs);
   819     X11_XTranslateCoordinates(display,
   820                               parent, DefaultRootWindow(display),
   821                               attrs.x, attrs.y,
   822                               &window->x, &window->y,
   823                               &childReturn);
   824 }
   825 
   826 void
   827 X11_SetWindowMinimumSize(_THIS, SDL_Window * window)
   828 {
   829     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   830     Display *display = data->videodata->display;
   831 
   832     if (window->flags & SDL_WINDOW_RESIZABLE) {
   833          XSizeHints *sizehints = X11_XAllocSizeHints();
   834          long userhints;
   835 
   836          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   837 
   838          sizehints->min_width = window->min_w;
   839          sizehints->min_height = window->min_h;
   840          sizehints->flags |= PMinSize;
   841 
   842          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   843 
   844          X11_XFree(sizehints);
   845 
   846         /* See comment in X11_SetWindowSize. */
   847         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   848         X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
   849         X11_XRaiseWindow(display, data->xwindow);
   850     }
   851 
   852     X11_XFlush(display);
   853 }
   854 
   855 void
   856 X11_SetWindowMaximumSize(_THIS, SDL_Window * window)
   857 {
   858     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   859     Display *display = data->videodata->display;
   860 
   861     if (window->flags & SDL_WINDOW_RESIZABLE) {
   862          XSizeHints *sizehints = X11_XAllocSizeHints();
   863          long userhints;
   864 
   865          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   866 
   867          sizehints->max_width = window->max_w;
   868          sizehints->max_height = window->max_h;
   869          sizehints->flags |= PMaxSize;
   870 
   871          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   872 
   873          X11_XFree(sizehints);
   874 
   875         /* See comment in X11_SetWindowSize. */
   876         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   877         X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
   878         X11_XRaiseWindow(display, data->xwindow);
   879     }
   880 
   881     X11_XFlush(display);
   882 }
   883 
   884 void
   885 X11_SetWindowSize(_THIS, SDL_Window * window)
   886 {
   887     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   888     Display *display = data->videodata->display;
   889 
   890     if (SDL_IsShapedWindow(window)) {
   891         X11_ResizeWindowShape(window);
   892     }
   893     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   894          /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the X11_XResizeWindow, thus
   895             we must set the size hints to adjust the window size. */
   896          XSizeHints *sizehints = X11_XAllocSizeHints();
   897          long userhints;
   898 
   899          X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   900 
   901          sizehints->min_width = sizehints->max_width = window->w;
   902          sizehints->min_height = sizehints->max_height = window->h;
   903          sizehints->flags |= PMinSize | PMaxSize;
   904 
   905          X11_XSetWMNormalHints(display, data->xwindow, sizehints);
   906 
   907          X11_XFree(sizehints);
   908 
   909         /* From Pierre-Loup:
   910            WMs each have their little quirks with that.  When you change the
   911            size hints, they get a ConfigureNotify event with the
   912            WM_NORMAL_SIZE_HINTS Atom.  They all save the hints then, but they
   913            don't all resize the window right away to enforce the new hints.
   914 
   915            Some of them resize only after:
   916             - A user-initiated move or resize
   917             - A code-initiated move or resize
   918             - Hiding & showing window (Unmap & map)
   919 
   920            The following move & resize seems to help a lot of WMs that didn't
   921            properly update after the hints were changed. We don't do a
   922            hide/show, because there are supposedly subtle problems with doing so
   923            and transitioning from windowed to fullscreen in Unity.
   924          */
   925         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   926         X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
   927         X11_XRaiseWindow(display, data->xwindow);
   928     } else {
   929         X11_XResizeWindow(display, data->xwindow, window->w, window->h);
   930     }
   931 
   932     X11_XFlush(display);
   933 }
   934 
   935 int
   936 X11_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right)
   937 {
   938     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   939 
   940     *left = data->border_left;
   941     *right = data->border_right;
   942     *top = data->border_top;
   943     *bottom = data->border_bottom;
   944 
   945     return 0;
   946 }
   947 
   948 int
   949 X11_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
   950 {
   951     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   952     Display *display = data->videodata->display;
   953     Atom _NET_WM_WINDOW_OPACITY = data->videodata->_NET_WM_WINDOW_OPACITY;
   954 
   955     if (opacity == 1.0f) {
   956         X11_XDeleteProperty(display, data->xwindow, _NET_WM_WINDOW_OPACITY);
   957     } else  {
   958         const Uint32 FullyOpaque = 0xFFFFFFFF;
   959         const long alpha = (long) ((double)opacity * (double)FullyOpaque);
   960         X11_XChangeProperty(display, data->xwindow, _NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32,
   961             PropModeReplace, (unsigned char *)&alpha, 1);
   962     }
   963 
   964     return 0;
   965 }
   966 
   967 int 
   968 X11_SetWindowModalFor(_THIS, SDL_Window * modal_window, SDL_Window * parent_window) {
   969     SDL_WindowData *data = (SDL_WindowData *) modal_window->driverdata;
   970     SDL_WindowData *parent_data = (SDL_WindowData *) parent_window->driverdata;
   971     Display *display = data->videodata->display;
   972 
   973     X11_XSetTransientForHint(display, data->xwindow, parent_data->xwindow);
   974     return 0;
   975 }
   976 
   977 int
   978 X11_SetWindowInputFocus(_THIS, SDL_Window * window) 
   979 {
   980     if (X11_IsWindowMapped(_this, window)) {
   981         SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   982         Display *display = data->videodata->display;
   983         X11_XSetInputFocus(display, data->xwindow, RevertToNone, CurrentTime);
   984         X11_XFlush(display);
   985         return 0;
   986     }
   987     return -1;
   988 }
   989 
   990 void
   991 X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   992 {
   993     const SDL_bool focused = ((window->flags & SDL_WINDOW_INPUT_FOCUS) != 0);
   994     const SDL_bool visible = ((window->flags & SDL_WINDOW_HIDDEN) == 0);
   995     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   996     SDL_DisplayData *displaydata =
   997         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   998     Display *display = data->videodata->display;
   999     XEvent event;
  1000 
  1001     SetWindowBordered(display, displaydata->screen, data->xwindow, bordered);
  1002     X11_XFlush(display);
  1003 
  1004     if (visible) {
  1005         XWindowAttributes attr;
  1006         do {
  1007             X11_XSync(display, False);
  1008             X11_XGetWindowAttributes(display, data->xwindow, &attr);
  1009         } while (attr.map_state != IsViewable);
  1010 
  1011         if (focused) {
  1012             X11_XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
  1013         }
  1014     }
  1015 
  1016     /* make sure these don't make it to the real event queue if they fired here. */
  1017     X11_XSync(display, False);
  1018     X11_XCheckIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
  1019     X11_XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
  1020 }
  1021 
  1022 void
  1023 X11_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
  1024 {
  1025     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1026     Display *display = data->videodata->display;
  1027 
  1028     XSizeHints *sizehints = X11_XAllocSizeHints();
  1029     long userhints;
  1030 
  1031     X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
  1032 
  1033     if (resizable) {
  1034         /* FIXME: Is there a better way to get max window size from X? -flibit */
  1035         const int maxsize = 0x7FFFFFFF;
  1036         sizehints->min_width = window->min_w;
  1037         sizehints->min_height = window->min_h;
  1038         sizehints->max_width = (window->max_w == 0) ? maxsize : window->max_w;
  1039         sizehints->max_height = (window->max_h == 0) ? maxsize : window->max_h;
  1040     } else {
  1041         sizehints->min_width = window->w;
  1042         sizehints->min_height = window->h;
  1043         sizehints->max_width = window->w;
  1044         sizehints->max_height = window->h;
  1045     }
  1046     sizehints->flags |= PMinSize | PMaxSize;
  1047 
  1048     X11_XSetWMNormalHints(display, data->xwindow, sizehints);
  1049 
  1050     X11_XFree(sizehints);
  1051 
  1052     /* See comment in X11_SetWindowSize. */
  1053     X11_XResizeWindow(display, data->xwindow, window->w, window->h);
  1054     X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
  1055     X11_XRaiseWindow(display, data->xwindow);
  1056 
  1057     X11_XFlush(display);
  1058 }
  1059 
  1060 void
  1061 X11_ShowWindow(_THIS, SDL_Window * window)
  1062 {
  1063     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1064     Display *display = data->videodata->display;
  1065     XEvent event;
  1066 
  1067     if (!X11_IsWindowMapped(_this, window)) {
  1068         X11_XMapRaised(display, data->xwindow);
  1069         /* Blocking wait for "MapNotify" event.
  1070          * We use X11_XIfEvent because pXWindowEvent takes a mask rather than a type,
  1071          * and XCheckTypedWindowEvent doesn't block */
  1072         if(!(window->flags & SDL_WINDOW_FOREIGN))
  1073             X11_XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
  1074         X11_XFlush(display);
  1075     }
  1076 
  1077     if (!data->videodata->net_wm) {
  1078         /* no WM means no FocusIn event, which confuses us. Force it. */
  1079         X11_XSetInputFocus(display, data->xwindow, RevertToNone, CurrentTime);
  1080         X11_XFlush(display);
  1081     }
  1082 }
  1083 
  1084 void
  1085 X11_HideWindow(_THIS, SDL_Window * window)
  1086 {
  1087     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1088     SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  1089     Display *display = data->videodata->display;
  1090     XEvent event;
  1091 
  1092     if (X11_IsWindowMapped(_this, window)) {
  1093         X11_XWithdrawWindow(display, data->xwindow, displaydata->screen);
  1094         /* Blocking wait for "UnmapNotify" event */
  1095         if(!(window->flags & SDL_WINDOW_FOREIGN))
  1096             X11_XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
  1097         X11_XFlush(display);
  1098     }
  1099 }
  1100 
  1101 static void
  1102 SetWindowActive(_THIS, SDL_Window * window)
  1103 {
  1104     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1105     SDL_DisplayData *displaydata =
  1106         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  1107     Display *display = data->videodata->display;
  1108     Atom _NET_ACTIVE_WINDOW = data->videodata->_NET_ACTIVE_WINDOW;
  1109 
  1110     if (X11_IsWindowMapped(_this, window)) {
  1111         XEvent e;
  1112 
  1113         /*printf("SDL Window %p: sending _NET_ACTIVE_WINDOW with timestamp %lu\n", window, data->user_time);*/
  1114 
  1115         SDL_zero(e);
  1116         e.xany.type = ClientMessage;
  1117         e.xclient.message_type = _NET_ACTIVE_WINDOW;
  1118         e.xclient.format = 32;
  1119         e.xclient.window = data->xwindow;
  1120         e.xclient.data.l[0] = 1;  /* source indication. 1 = application */
  1121         e.xclient.data.l[1] = data->user_time;
  1122         e.xclient.data.l[2] = 0;
  1123 
  1124         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1125                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1126 
  1127         X11_XFlush(display);
  1128     }
  1129 }
  1130 
  1131 void
  1132 X11_RaiseWindow(_THIS, SDL_Window * window)
  1133 {
  1134     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1135     Display *display = data->videodata->display;
  1136 
  1137     X11_XRaiseWindow(display, data->xwindow);
  1138     SetWindowActive(_this, window);
  1139     X11_XFlush(display);
  1140 }
  1141 
  1142 static void
  1143 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
  1144 {
  1145     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1146     SDL_DisplayData *displaydata =
  1147         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  1148     Display *display = data->videodata->display;
  1149     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
  1150     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
  1151     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
  1152 
  1153     if (maximized) {
  1154         window->flags |= SDL_WINDOW_MAXIMIZED;
  1155     } else {
  1156         window->flags &= ~SDL_WINDOW_MAXIMIZED;
  1157     }
  1158 
  1159     if (X11_IsWindowMapped(_this, window)) {
  1160         XEvent e;
  1161 
  1162         SDL_zero(e);
  1163         e.xany.type = ClientMessage;
  1164         e.xclient.message_type = _NET_WM_STATE;
  1165         e.xclient.format = 32;
  1166         e.xclient.window = data->xwindow;
  1167         e.xclient.data.l[0] =
  1168             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  1169         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
  1170         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
  1171         e.xclient.data.l[3] = 0l;
  1172 
  1173         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1174                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1175     } else {
  1176         X11_SetNetWMState(_this, data->xwindow, window->flags);
  1177     }
  1178     X11_XFlush(display);
  1179 }
  1180 
  1181 void
  1182 X11_MaximizeWindow(_THIS, SDL_Window * window)
  1183 {
  1184     SetWindowMaximized(_this, window, SDL_TRUE);
  1185 }
  1186 
  1187 void
  1188 X11_MinimizeWindow(_THIS, SDL_Window * window)
  1189 {
  1190     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1191     SDL_DisplayData *displaydata =
  1192         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
  1193     Display *display = data->videodata->display;
  1194 
  1195     X11_XIconifyWindow(display, data->xwindow, displaydata->screen);
  1196     X11_XFlush(display);
  1197 }
  1198 
  1199 void
  1200 X11_RestoreWindow(_THIS, SDL_Window * window)
  1201 {
  1202     SetWindowMaximized(_this, window, SDL_FALSE);
  1203     X11_ShowWindow(_this, window);
  1204     SetWindowActive(_this, window);
  1205 }
  1206 
  1207 /* This asks the Window Manager to handle fullscreen for us. This is the modern way. */
  1208 static void
  1209 X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1210 {
  1211     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1212     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1213     Display *display = data->videodata->display;
  1214     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
  1215     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
  1216 
  1217     if (X11_IsWindowMapped(_this, window)) {
  1218         XEvent e;
  1219 
  1220         if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
  1221             /* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we
  1222                can be resized to the fullscreen resolution (or reset so we're not resizable again) */
  1223             XSizeHints *sizehints = X11_XAllocSizeHints();
  1224             long flags = 0;
  1225             X11_XGetWMNormalHints(display, data->xwindow, sizehints, &flags);
  1226             /* set the resize flags on */
  1227             if (fullscreen) {
  1228                 /* we are going fullscreen so turn the flags off */
  1229                 sizehints->flags &= ~(PMinSize | PMaxSize);
  1230             } else {
  1231                 /* Reset the min/max width height to make the window non-resizable again */
  1232                 sizehints->flags |= PMinSize | PMaxSize;
  1233                 sizehints->min_width = sizehints->max_width = window->windowed.w;
  1234                 sizehints->min_height = sizehints->max_height = window->windowed.h;
  1235             }
  1236             X11_XSetWMNormalHints(display, data->xwindow, sizehints);
  1237             X11_XFree(sizehints);
  1238         }
  1239 
  1240         SDL_zero(e);
  1241         e.xany.type = ClientMessage;
  1242         e.xclient.message_type = _NET_WM_STATE;
  1243         e.xclient.format = 32;
  1244         e.xclient.window = data->xwindow;
  1245         e.xclient.data.l[0] =
  1246             fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  1247         e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
  1248         e.xclient.data.l[3] = 0l;
  1249 
  1250         X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1251                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1252 
  1253         /* Fullscreen windows sometimes end up being marked maximized by
  1254             window managers. Force it back to how we expect it to be. */
  1255         if (!fullscreen && ((window->flags & SDL_WINDOW_MAXIMIZED) == 0)) {
  1256             SDL_zero(e);
  1257             e.xany.type = ClientMessage;
  1258             e.xclient.message_type = _NET_WM_STATE;
  1259             e.xclient.format = 32;
  1260             e.xclient.window = data->xwindow;
  1261             e.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
  1262             e.xclient.data.l[1] = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
  1263             e.xclient.data.l[2] = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
  1264             e.xclient.data.l[3] = 0l;
  1265             X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
  1266                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
  1267         }
  1268     } else {
  1269         Uint32 flags;
  1270 
  1271         flags = window->flags;
  1272         if (fullscreen) {
  1273             flags |= SDL_WINDOW_FULLSCREEN;
  1274         } else {
  1275             flags &= ~SDL_WINDOW_FULLSCREEN;
  1276         }
  1277         X11_SetNetWMState(_this, data->xwindow, flags);
  1278     }
  1279 
  1280     if (data->visual->class == DirectColor) {
  1281         if ( fullscreen ) {
  1282             X11_XInstallColormap(display, data->colormap);
  1283         } else {
  1284             X11_XUninstallColormap(display, data->colormap);
  1285         }
  1286     }
  1287 
  1288     X11_XFlush(display);
  1289 }
  1290 
  1291 /* This handles fullscreen itself, outside the Window Manager. */
  1292 static void
  1293 X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1294 {
  1295     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1296     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1297     Visual *visual = data->visual;
  1298     Display *display = data->videodata->display;
  1299     const int screen = displaydata->screen;
  1300     Window root = RootWindow(display, screen);
  1301     const int def_vis = (visual == DefaultVisual(display, screen));
  1302     unsigned long xattrmask = 0;
  1303     XSetWindowAttributes xattr;
  1304     XEvent ev;
  1305     SDL_Rect rect;
  1306 
  1307     if ( data->fswindow ) {
  1308         return;  /* already fullscreen, I hope. */
  1309     }
  1310 
  1311     X11_GetDisplayBounds(_this, _display, &rect);
  1312 
  1313     SDL_zero(xattr);
  1314     xattr.override_redirect = True;
  1315     xattrmask |= CWOverrideRedirect;
  1316     xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
  1317     xattrmask |= CWBackPixel;
  1318     xattr.border_pixel = 0;
  1319     xattrmask |= CWBorderPixel;
  1320     xattr.colormap = data->colormap;
  1321     xattrmask |= CWColormap;
  1322 
  1323     data->fswindow = X11_XCreateWindow(display, root,
  1324                                    rect.x, rect.y, rect.w, rect.h, 0,
  1325                                    displaydata->depth, InputOutput,
  1326                                    visual, xattrmask, &xattr);
  1327 
  1328     X11_XSelectInput(display, data->fswindow, StructureNotifyMask);
  1329     X11_XSetWindowBackground(display, data->fswindow, 0);
  1330     X11_XInstallColormap(display, data->colormap);
  1331     X11_XClearWindow(display, data->fswindow);
  1332     X11_XMapRaised(display, data->fswindow);
  1333 
  1334     /* Make sure the fswindow is in view by warping mouse to the corner */
  1335     X11_XUngrabPointer(display, CurrentTime);
  1336     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1337 
  1338     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1339     X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
  1340     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
  1341 
  1342 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
  1343     if ( displaydata->use_vidmode ) {
  1344         X11_XF86VidModeLockModeSwitch(display, screen, True);
  1345     }
  1346 #endif
  1347 
  1348     SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
  1349 
  1350     /* Center actual window within our cover-the-screen window. */
  1351     X11_XReparentWindow(display, data->xwindow, data->fswindow,
  1352                     (rect.w - window->w) / 2, (rect.h - window->h) / 2);
  1353 
  1354     /* Move the mouse to the upper left to make sure it's on-screen */
  1355     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1356 
  1357     /* Center mouse in the fullscreen window. */
  1358     rect.x += (rect.w / 2);
  1359     rect.y += (rect.h / 2);
  1360     X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
  1361 
  1362     /* Wait to be mapped, filter Unmap event out if it arrives. */
  1363     X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1364     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1365 
  1366     SDL_UpdateWindowGrab(window);
  1367 }
  1368 
  1369 static void
  1370 X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
  1371 {
  1372     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1373     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1374     Display *display = data->videodata->display;
  1375     const int screen = displaydata->screen;
  1376     Window root = RootWindow(display, screen);
  1377     Window fswindow = data->fswindow;
  1378     XEvent ev;
  1379 
  1380     if (!data->fswindow) {
  1381         return;  /* already not fullscreen, I hope. */
  1382     }
  1383 
  1384     data->fswindow = None;
  1385 
  1386 #if SDL_VIDEO_DRIVER_X11_VIDMODE
  1387     if ( displaydata->use_vidmode ) {
  1388         X11_XF86VidModeLockModeSwitch(display, screen, False);
  1389     }
  1390 #endif
  1391 
  1392     SDL_UpdateWindowGrab(window);
  1393 
  1394     X11_XReparentWindow(display, data->xwindow, root, window->x, window->y);
  1395 
  1396     /* flush these events so they don't confuse normal event handling */
  1397     X11_XSync(display, False);
  1398     X11_XCheckIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
  1399     X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
  1400 
  1401     SetWindowBordered(display, screen, data->xwindow,
  1402                       (window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1403 
  1404     X11_XWithdrawWindow(display, fswindow, screen);
  1405 
  1406     /* Wait to be unmapped. */
  1407     X11_XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&fswindow);
  1408     X11_XDestroyWindow(display, fswindow);
  1409 }
  1410 
  1411 
  1412 void
  1413 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
  1414 {
  1415     /* !!! FIXME: SDL_Hint? */
  1416     SDL_bool legacy = SDL_FALSE;
  1417     const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
  1418     if (env) {
  1419         legacy = SDL_atoi(env);
  1420     } else {
  1421         SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1422         SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
  1423         if ( displaydata->use_vidmode ) {
  1424             legacy = SDL_TRUE;  /* the new stuff only works with XRandR. */
  1425         } else if ( !videodata->net_wm ) {
  1426             legacy = SDL_TRUE;  /* The window manager doesn't support it */
  1427         } else {
  1428             /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
  1429             /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
  1430             legacy = SDL_FALSE;  /* try the new way. */
  1431         }
  1432     }
  1433 
  1434     if (legacy) {
  1435         if (fullscreen) {
  1436             X11_BeginWindowFullscreenLegacy(_this, window, _display);
  1437         } else {
  1438             X11_EndWindowFullscreenLegacy(_this, window, _display);
  1439         }
  1440     } else {
  1441         X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
  1442     }
  1443 }
  1444 
  1445 
  1446 int
  1447 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1448 {
  1449     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1450     Display *display = data->videodata->display;
  1451     Visual *visual = data->visual;
  1452     Colormap colormap = data->colormap;
  1453     XColor *colorcells;
  1454     int ncolors;
  1455     int rmask, gmask, bmask;
  1456     int rshift, gshift, bshift;
  1457     int i;
  1458 
  1459     if (visual->class != DirectColor) {
  1460         return SDL_SetError("Window doesn't have DirectColor visual");
  1461     }
  1462 
  1463     ncolors = visual->map_entries;
  1464     colorcells = SDL_malloc(ncolors * sizeof(XColor));
  1465     if (!colorcells) {
  1466         return SDL_OutOfMemory();
  1467     }
  1468 
  1469     rshift = 0;
  1470     rmask = visual->red_mask;
  1471     while (0 == (rmask & 1)) {
  1472         rshift++;
  1473         rmask >>= 1;
  1474     }
  1475 
  1476     gshift = 0;
  1477     gmask = visual->green_mask;
  1478     while (0 == (gmask & 1)) {
  1479         gshift++;
  1480         gmask >>= 1;
  1481     }
  1482 
  1483     bshift = 0;
  1484     bmask = visual->blue_mask;
  1485     while (0 == (bmask & 1)) {
  1486         bshift++;
  1487         bmask >>= 1;
  1488     }
  1489 
  1490     /* build the color table pixel values */
  1491     for (i = 0; i < ncolors; i++) {
  1492         Uint32 rbits = (rmask * i) / (ncolors - 1);
  1493         Uint32 gbits = (gmask * i) / (ncolors - 1);
  1494         Uint32 bbits = (bmask * i) / (ncolors - 1);
  1495         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
  1496 
  1497         colorcells[i].pixel = pix;
  1498 
  1499         colorcells[i].red = ramp[(0 * 256) + i];
  1500         colorcells[i].green = ramp[(1 * 256) + i];
  1501         colorcells[i].blue = ramp[(2 * 256) + i];
  1502 
  1503         colorcells[i].flags = DoRed | DoGreen | DoBlue;
  1504     }
  1505 
  1506     X11_XStoreColors(display, colormap, colorcells, ncolors);
  1507     X11_XFlush(display);
  1508     SDL_free(colorcells);
  1509 
  1510     return 0;
  1511 }
  1512 
  1513 void
  1514 X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
  1515 {
  1516     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1517     Display *display = data->videodata->display;
  1518     SDL_bool oldstyle_fullscreen;
  1519     SDL_bool grab_keyboard;
  1520 
  1521     /* ICCCM2.0-compliant window managers can handle fullscreen windows
  1522        If we're using XVidMode to change resolution we need to confine
  1523        the cursor so we don't pan around the virtual desktop.
  1524      */
  1525     oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
  1526 
  1527     if (oldstyle_fullscreen || grabbed) {
  1528         /* Try to grab the mouse */
  1529         if (!data->videodata->broken_pointer_grab) {
  1530             const unsigned int mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask;
  1531             int attempts;
  1532             int result;
  1533 
  1534             /* Try for up to 5000ms (5s) to grab. If it still fails, stop trying. */
  1535             for (attempts = 0; attempts < 100; attempts++) {
  1536                 result = X11_XGrabPointer(display, data->xwindow, True, mask, GrabModeAsync,
  1537                                  GrabModeAsync, data->xwindow, None, CurrentTime);
  1538                 if (result == GrabSuccess) {
  1539                     break;
  1540                 }
  1541                 SDL_Delay(50);
  1542             }
  1543 
  1544             if (result != GrabSuccess) {
  1545                 SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "The X server refused to let us grab the mouse. You might experience input bugs.");
  1546                 data->videodata->broken_pointer_grab = SDL_TRUE;  /* don't try again. */
  1547             }
  1548         }
  1549 
  1550         /* Raise the window if we grab the mouse */
  1551         X11_XRaiseWindow(display, data->xwindow);
  1552 
  1553         /* Now grab the keyboard */
  1554         if (SDL_GetHintBoolean(SDL_HINT_GRAB_KEYBOARD, SDL_FALSE)) {
  1555             grab_keyboard = SDL_TRUE;
  1556         } else {
  1557             /* We need to do this with the old style override_redirect
  1558                fullscreen window otherwise we won't get keyboard focus.
  1559             */
  1560             grab_keyboard = oldstyle_fullscreen;
  1561         }
  1562         if (grab_keyboard) {
  1563             X11_XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1564                           GrabModeAsync, CurrentTime);
  1565         }
  1566     } else {
  1567         X11_XUngrabPointer(display, CurrentTime);
  1568         X11_XUngrabKeyboard(display, CurrentTime);
  1569     }
  1570     X11_XSync(display, False);
  1571 }
  1572 
  1573 void
  1574 X11_DestroyWindow(_THIS, SDL_Window * window)
  1575 {
  1576     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1577 
  1578     if (data) {
  1579         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1580         Display *display = videodata->display;
  1581         int numwindows = videodata->numwindows;
  1582         SDL_WindowData **windowlist = videodata->windowlist;
  1583         int i;
  1584 
  1585         if (windowlist) {
  1586             for (i = 0; i < numwindows; ++i) {
  1587                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1588                     windowlist[i] = windowlist[numwindows - 1];
  1589                     windowlist[numwindows - 1] = NULL;
  1590                     videodata->numwindows--;
  1591                     break;
  1592                 }
  1593             }
  1594         }
  1595 #ifdef X_HAVE_UTF8_STRING
  1596         if (data->ic) {
  1597             X11_XDestroyIC(data->ic);
  1598         }
  1599 #endif
  1600         if (data->created) {
  1601             X11_XDestroyWindow(display, data->xwindow);
  1602             X11_XFlush(display);
  1603         }
  1604         SDL_free(data);
  1605     }
  1606     window->driverdata = NULL;
  1607 }
  1608 
  1609 SDL_bool
  1610 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1611 {
  1612     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1613     Display *display = data->videodata->display;
  1614 
  1615     if (info->version.major == SDL_MAJOR_VERSION &&
  1616         info->version.minor == SDL_MINOR_VERSION) {
  1617         info->subsystem = SDL_SYSWM_X11;
  1618         info->info.x11.display = display;
  1619         info->info.x11.window = data->xwindow;
  1620         return SDL_TRUE;
  1621     } else {
  1622         SDL_SetError("Application not compiled with SDL %d.%d",
  1623                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1624         return SDL_FALSE;
  1625     }
  1626 }
  1627 
  1628 int
  1629 X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
  1630 {
  1631     return 0;  /* just succeed, the real work is done elsewhere. */
  1632 }
  1633 
  1634 void
  1635 X11_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept)
  1636 {
  1637     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1638     Display *display = data->videodata->display;
  1639     Atom XdndAware = X11_XInternAtom(display, "XdndAware", False);
  1640 
  1641     if (accept) {
  1642         Atom xdnd_version = 5;
  1643         X11_XChangeProperty(display, data->xwindow, XdndAware, XA_ATOM, 32,
  1644                      PropModeReplace, (unsigned char*)&xdnd_version, 1);
  1645     } else {
  1646         X11_XDeleteProperty(display, data->xwindow, XdndAware);
  1647     }
  1648 }
  1649 
  1650 #endif /* SDL_VIDEO_DRIVER_X11 */
  1651 
  1652 /* vi: set ts=4 sw=4 expandtab: */