cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_x11window.c (48699B)


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