sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_x11window.c (58584B)


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