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