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