cscg22-gearboy

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

SDL_x11events.c (46328B)


      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 <sys/types.h>
     26#include <sys/time.h>
     27#include <signal.h>
     28#include <unistd.h>
     29#include <limits.h> /* For INT_MAX */
     30
     31#include "SDL_x11video.h"
     32#include "SDL_x11touch.h"
     33#include "SDL_x11xinput2.h"
     34#include "../../events/SDL_events_c.h"
     35#include "../../events/SDL_mouse_c.h"
     36#include "../../events/SDL_touch_c.h"
     37
     38#include "SDL_timer.h"
     39#include "SDL_syswm.h"
     40
     41#include <stdio.h>
     42
     43#ifndef _NET_WM_MOVERESIZE_SIZE_TOPLEFT
     44#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
     45#endif
     46
     47#ifndef _NET_WM_MOVERESIZE_SIZE_TOP
     48#define _NET_WM_MOVERESIZE_SIZE_TOP          1
     49#endif
     50
     51#ifndef _NET_WM_MOVERESIZE_SIZE_TOPRIGHT
     52#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
     53#endif
     54
     55#ifndef _NET_WM_MOVERESIZE_SIZE_RIGHT
     56#define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
     57#endif
     58
     59#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
     60#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
     61#endif
     62
     63#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOM
     64#define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
     65#endif
     66
     67#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
     68#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
     69#endif
     70
     71#ifndef _NET_WM_MOVERESIZE_SIZE_LEFT
     72#define _NET_WM_MOVERESIZE_SIZE_LEFT         7
     73#endif
     74
     75#ifndef _NET_WM_MOVERESIZE_MOVE
     76#define _NET_WM_MOVERESIZE_MOVE              8
     77#endif
     78
     79typedef struct {
     80    unsigned char *data;
     81    int format, count;
     82    Atom type;
     83} SDL_x11Prop;
     84
     85/* Reads property
     86   Must call X11_XFree on results
     87 */
     88static void X11_ReadProperty(SDL_x11Prop *p, Display *disp, Window w, Atom prop)
     89{
     90    unsigned char *ret=NULL;
     91    Atom type;
     92    int fmt;
     93    unsigned long count;
     94    unsigned long bytes_left;
     95    int bytes_fetch = 0;
     96
     97    do {
     98        if (ret != 0) X11_XFree(ret);
     99        X11_XGetWindowProperty(disp, w, prop, 0, bytes_fetch, False, AnyPropertyType, &type, &fmt, &count, &bytes_left, &ret);
    100        bytes_fetch += bytes_left;
    101    } while (bytes_left != 0);
    102
    103    p->data=ret;
    104    p->format=fmt;
    105    p->count=count;
    106    p->type=type;
    107}
    108
    109/* Find text-uri-list in a list of targets and return it's atom
    110   if available, else return None */
    111static Atom X11_PickTarget(Display *disp, Atom list[], int list_count)
    112{
    113    Atom request = None;
    114    char *name;
    115    int i;
    116    for (i=0; i < list_count && request == None; i++) {
    117        name = X11_XGetAtomName(disp, list[i]);
    118        if (strcmp("text/uri-list", name)==0) request = list[i];
    119        X11_XFree(name);
    120    }
    121    return request;
    122}
    123
    124/* Wrapper for X11_PickTarget for a maximum of three targets, a special
    125   case in the Xdnd protocol */
    126static Atom X11_PickTargetFromAtoms(Display *disp, Atom a0, Atom a1, Atom a2)
    127{
    128    int count=0;
    129    Atom atom[3];
    130    if (a0 != None) atom[count++] = a0;
    131    if (a1 != None) atom[count++] = a1;
    132    if (a2 != None) atom[count++] = a2;
    133    return X11_PickTarget(disp, atom, count);
    134}
    135/* #define DEBUG_XEVENTS */
    136
    137struct KeyRepeatCheckData
    138{
    139    XEvent *event;
    140    SDL_bool found;
    141};
    142
    143static Bool X11_KeyRepeatCheckIfEvent(Display *display, XEvent *chkev,
    144    XPointer arg)
    145{
    146    struct KeyRepeatCheckData *d = (struct KeyRepeatCheckData *) arg;
    147    if (chkev->type == KeyPress &&
    148        chkev->xkey.keycode == d->event->xkey.keycode &&
    149        chkev->xkey.time - d->event->xkey.time < 2)
    150        d->found = SDL_TRUE;
    151    return False;
    152}
    153
    154/* Check to see if this is a repeated key.
    155   (idea shamelessly lifted from GII -- thanks guys! :)
    156 */
    157static SDL_bool X11_KeyRepeat(Display *display, XEvent *event)
    158{
    159    XEvent dummyev;
    160    struct KeyRepeatCheckData d;
    161    d.event = event;
    162    d.found = SDL_FALSE;
    163    if (X11_XPending(display))
    164        X11_XCheckIfEvent(display, &dummyev, X11_KeyRepeatCheckIfEvent,
    165            (XPointer) &d);
    166    return d.found;
    167}
    168
    169static Bool X11_IsWheelCheckIfEvent(Display *display, XEvent *chkev,
    170    XPointer arg)
    171{
    172    XEvent *event = (XEvent *) arg;
    173    /* we only handle buttons 4 and 5 - false positive avoidance */
    174    if (chkev->type == ButtonRelease &&
    175        (event->xbutton.button == Button4 || event->xbutton.button == Button5) &&
    176        chkev->xbutton.button == event->xbutton.button &&
    177        chkev->xbutton.time == event->xbutton.time)
    178        return True;
    179    return False;
    180}
    181
    182static SDL_bool X11_IsWheelEvent(Display * display,XEvent * event,int * ticks)
    183{
    184    XEvent relevent;
    185    if (X11_XPending(display)) {
    186        /* according to the xlib docs, no specific mouse wheel events exist.
    187           however, mouse wheel events trigger a button press and a button release
    188           immediately. thus, checking if the same button was released at the same
    189           time as it was pressed, should be an adequate hack to derive a mouse
    190           wheel event.
    191           However, there is broken and unusual hardware out there...
    192           - False positive: a button for which a release event is
    193             generated (or synthesised) immediately.
    194           - False negative: a wheel which, when rolled, doesn't have
    195             a release event generated immediately. */
    196        if (X11_XCheckIfEvent(display, &relevent, X11_IsWheelCheckIfEvent,
    197            (XPointer) event)) {
    198
    199            /* by default, X11 only knows 5 buttons. on most 3 button + wheel mouse,
    200               Button4 maps to wheel up, Button5 maps to wheel down. */
    201            if (event->xbutton.button == Button4) {
    202                *ticks = 1;
    203            }
    204            else if (event->xbutton.button == Button5) {
    205                *ticks = -1;
    206            }
    207            return SDL_TRUE;
    208        }
    209    }
    210    return SDL_FALSE;
    211}
    212
    213/* Decodes URI escape sequences in string buf of len bytes
    214   (excluding the terminating NULL byte) in-place. Since
    215   URI-encoded characters take three times the space of
    216   normal characters, this should not be an issue.
    217
    218   Returns the number of decoded bytes that wound up in
    219   the buffer, excluding the terminating NULL byte.
    220
    221   The buffer is guaranteed to be NULL-terminated but
    222   may contain embedded NULL bytes.
    223
    224   On error, -1 is returned.
    225 */
    226int X11_URIDecode(char *buf, int len) {
    227    int ri, wi, di;
    228    char decode = '\0';
    229    if (buf == NULL || len < 0) {
    230        errno = EINVAL;
    231        return -1;
    232    }
    233    if (len == 0) {
    234        len = SDL_strlen(buf);
    235    }
    236    for (ri = 0, wi = 0, di = 0; ri < len && wi < len; ri += 1) {
    237        if (di == 0) {
    238            /* start decoding */
    239            if (buf[ri] == '%') {
    240                decode = '\0';
    241                di += 1;
    242                continue;
    243            }
    244            /* normal write */
    245            buf[wi] = buf[ri];
    246            wi += 1;
    247            continue;
    248        } else if (di == 1 || di == 2) {
    249            char off = '\0';
    250            char isa = buf[ri] >= 'a' && buf[ri] <= 'f';
    251            char isA = buf[ri] >= 'A' && buf[ri] <= 'F';
    252            char isn = buf[ri] >= '0' && buf[ri] <= '9';
    253            if (!(isa || isA || isn)) {
    254                /* not a hexadecimal */
    255                int sri;
    256                for (sri = ri - di; sri <= ri; sri += 1) {
    257                    buf[wi] = buf[sri];
    258                    wi += 1;
    259                }
    260                di = 0;
    261                continue;
    262            }
    263            /* itsy bitsy magicsy */
    264            if (isn) {
    265                off = 0 - '0';
    266            } else if (isa) {
    267                off = 10 - 'a';
    268            } else if (isA) {
    269                off = 10 - 'A';
    270            }
    271            decode |= (buf[ri] + off) << (2 - di) * 4;
    272            if (di == 2) {
    273                buf[wi] = decode;
    274                wi += 1;
    275                di = 0;
    276            } else {
    277                di += 1;
    278            }
    279            continue;
    280        }
    281    }
    282    buf[wi] = '\0';
    283    return wi;
    284}
    285
    286/* Convert URI to local filename
    287   return filename if possible, else NULL
    288*/
    289static char* X11_URIToLocal(char* uri) {
    290    char *file = NULL;
    291    SDL_bool local;
    292
    293    if (memcmp(uri,"file:/",6) == 0) uri += 6;      /* local file? */
    294    else if (strstr(uri,":/") != NULL) return file; /* wrong scheme */
    295
    296    local = uri[0] != '/' || ( uri[0] != '\0' && uri[1] == '/' );
    297
    298    /* got a hostname? */
    299    if ( !local && uri[0] == '/' && uri[2] != '/' ) {
    300      char* hostname_end = strchr( uri+1, '/' );
    301      if ( hostname_end != NULL ) {
    302          char hostname[ 257 ];
    303          if ( gethostname( hostname, 255 ) == 0 ) {
    304            hostname[ 256 ] = '\0';
    305            if ( memcmp( uri+1, hostname, hostname_end - ( uri+1 )) == 0 ) {
    306                uri = hostname_end + 1;
    307                local = SDL_TRUE;
    308            }
    309          }
    310      }
    311    }
    312    if ( local ) {
    313      file = uri;
    314      /* Convert URI escape sequences to real characters */
    315      X11_URIDecode(file, 0);
    316      if ( uri[1] == '/' ) {
    317          file++;
    318      } else {
    319          file--;
    320      }
    321    }
    322    return file;
    323}
    324
    325#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
    326static void X11_HandleGenericEvent(SDL_VideoData *videodata,XEvent event)
    327{
    328    /* event is a union, so cookie == &event, but this is type safe. */
    329    XGenericEventCookie *cookie = &event.xcookie;
    330    if (X11_XGetEventData(videodata->display, cookie)) {
    331        X11_HandleXinput2Event(videodata, cookie);
    332        X11_XFreeEventData(videodata->display, cookie);
    333    }
    334}
    335#endif /* SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS */
    336
    337
    338static void
    339X11_DispatchFocusIn(SDL_WindowData *data)
    340{
    341#ifdef DEBUG_XEVENTS
    342    printf("window %p: Dispatching FocusIn\n", data);
    343#endif
    344    SDL_SetKeyboardFocus(data->window);
    345#ifdef X_HAVE_UTF8_STRING
    346    if (data->ic) {
    347        X11_XSetICFocus(data->ic);
    348    }
    349#endif
    350#ifdef SDL_USE_IBUS
    351    SDL_IBus_SetFocus(SDL_TRUE);
    352#endif
    353}
    354
    355static void
    356X11_DispatchFocusOut(SDL_WindowData *data)
    357{
    358#ifdef DEBUG_XEVENTS
    359    printf("window %p: Dispatching FocusOut\n", data);
    360#endif
    361    /* If another window has already processed a focus in, then don't try to
    362     * remove focus here.  Doing so will incorrectly remove focus from that
    363     * window, and the focus lost event for this window will have already
    364     * been dispatched anyway. */
    365    if (data->window == SDL_GetKeyboardFocus()) {
    366        SDL_SetKeyboardFocus(NULL);
    367    }
    368#ifdef X_HAVE_UTF8_STRING
    369    if (data->ic) {
    370        X11_XUnsetICFocus(data->ic);
    371    }
    372#endif
    373#ifdef SDL_USE_IBUS
    374    SDL_IBus_SetFocus(SDL_FALSE);
    375#endif
    376}
    377
    378static void
    379X11_DispatchMapNotify(SDL_WindowData *data)
    380{
    381    SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
    382    SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
    383}
    384
    385static void
    386X11_DispatchUnmapNotify(SDL_WindowData *data)
    387{
    388    SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
    389    SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    390}
    391
    392static void
    393InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point)
    394{
    395    SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
    396    SDL_Window* window = data->window;
    397    Display *display = viddata->display;
    398    XEvent evt;
    399
    400    /* !!! FIXME: we need to regrab this if necessary when the drag is done. */
    401    X11_XUngrabPointer(display, 0L);
    402    X11_XFlush(display);
    403
    404    evt.xclient.type = ClientMessage;
    405    evt.xclient.window = data->xwindow;
    406    evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True);
    407    evt.xclient.format = 32;
    408    evt.xclient.data.l[0] = window->x + point->x;
    409    evt.xclient.data.l[1] = window->y + point->y;
    410    evt.xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE;
    411    evt.xclient.data.l[3] = Button1;
    412    evt.xclient.data.l[4] = 0;
    413    X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt);
    414
    415    X11_XSync(display, 0);
    416}
    417
    418static void
    419InitiateWindowResize(_THIS, const SDL_WindowData *data, const SDL_Point *point, int direction)
    420{
    421    SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
    422    SDL_Window* window = data->window;
    423    Display *display = viddata->display;
    424    XEvent evt;
    425
    426    if (direction < _NET_WM_MOVERESIZE_SIZE_TOPLEFT || direction > _NET_WM_MOVERESIZE_SIZE_LEFT)
    427        return;
    428
    429    /* !!! FIXME: we need to regrab this if necessary when the drag is done. */
    430    X11_XUngrabPointer(display, 0L);
    431    X11_XFlush(display);
    432
    433    evt.xclient.type = ClientMessage;
    434    evt.xclient.window = data->xwindow;
    435    evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True);
    436    evt.xclient.format = 32;
    437    evt.xclient.data.l[0] = window->x + point->x;
    438    evt.xclient.data.l[1] = window->y + point->y;
    439    evt.xclient.data.l[2] = direction;
    440    evt.xclient.data.l[3] = Button1;
    441    evt.xclient.data.l[4] = 0;
    442    X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt);
    443
    444    X11_XSync(display, 0);
    445}
    446
    447static SDL_bool
    448ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev)
    449{
    450    SDL_Window *window = data->window;
    451    SDL_bool ret = SDL_FALSE;
    452
    453    if (window->hit_test) {
    454        const SDL_Point point = { xev->xbutton.x, xev->xbutton.y };
    455        const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
    456        switch (rc) {
    457            case SDL_HITTEST_DRAGGABLE: {
    458                    InitiateWindowMove(_this, data, &point);
    459                    ret = SDL_TRUE;
    460                }
    461                break;
    462            case SDL_HITTEST_RESIZE_TOPLEFT: {
    463                    InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPLEFT);
    464                    ret = SDL_TRUE;
    465                }
    466                break;
    467            case SDL_HITTEST_RESIZE_TOP: {
    468                    InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOP);
    469                    ret = SDL_TRUE;
    470                }
    471                break;
    472            case SDL_HITTEST_RESIZE_TOPRIGHT: {
    473                    InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPRIGHT);
    474                    ret = SDL_TRUE;
    475                }
    476                break;
    477            case SDL_HITTEST_RESIZE_RIGHT: {
    478                    InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_RIGHT);
    479                    ret = SDL_TRUE;
    480                }
    481                break;
    482            case SDL_HITTEST_RESIZE_BOTTOMRIGHT: {
    483                    InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT);
    484                    ret = SDL_TRUE;
    485                }
    486                break;
    487            case SDL_HITTEST_RESIZE_BOTTOM: {
    488                    InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOM);
    489                    ret = SDL_TRUE;
    490                }
    491                break;
    492            case SDL_HITTEST_RESIZE_BOTTOMLEFT: {
    493                    InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT);
    494                    ret = SDL_TRUE;
    495                }
    496                break;
    497            case SDL_HITTEST_RESIZE_LEFT: {
    498                    InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_LEFT);
    499                    ret = SDL_TRUE;
    500                }
    501                break;
    502            default:
    503                break;
    504        }
    505    }
    506
    507    return ret;
    508}
    509
    510static void
    511ReconcileKeyboardState(_THIS, const SDL_WindowData *data)
    512{
    513    SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
    514    SDL_Window* window = data->window;
    515    Display *display = viddata->display;
    516    char keys[32];
    517    int keycode = 0;
    518
    519    X11_XQueryKeymap( display, keys );
    520
    521    while ( keycode < 256 ) {
    522        if ( keys[keycode / 8] & (1 << (keycode % 8)) ) {
    523            SDL_SendKeyboardKey(SDL_PRESSED, viddata->key_layout[keycode]);
    524        } else {
    525            SDL_SendKeyboardKey(SDL_RELEASED, viddata->key_layout[keycode]);
    526        }
    527        keycode++;
    528    }
    529}
    530
    531static void
    532X11_DispatchEvent(_THIS)
    533{
    534    SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    535    Display *display = videodata->display;
    536    SDL_WindowData *data;
    537    XEvent xevent;
    538    int orig_event_type;
    539    KeyCode orig_keycode;
    540    XClientMessageEvent m;
    541    int i;
    542
    543    SDL_zero(xevent);           /* valgrind fix. --ryan. */
    544    X11_XNextEvent(display, &xevent);
    545
    546    /* Save the original keycode for dead keys, which are filtered out by
    547       the XFilterEvent() call below.
    548    */
    549    orig_event_type = xevent.type;
    550    if (orig_event_type == KeyPress || orig_event_type == KeyRelease) {
    551        orig_keycode = xevent.xkey.keycode;
    552    } else {
    553        orig_keycode = 0;
    554    }
    555
    556    /* filter events catchs XIM events and sends them to the correct handler */
    557    if (X11_XFilterEvent(&xevent, None) == True) {
    558#if 0
    559        printf("Filtered event type = %d display = %d window = %d\n",
    560               xevent.type, xevent.xany.display, xevent.xany.window);
    561#endif
    562        if (orig_keycode) {
    563            /* Make sure dead key press/release events are sent */
    564            /* Actually, don't do this because it causes double-delivery
    565               of some keys on Ubuntu 14.04 (bug 2526)
    566            SDL_Scancode scancode = videodata->key_layout[orig_keycode];
    567            if (orig_event_type == KeyPress) {
    568                SDL_SendKeyboardKey(SDL_PRESSED, scancode);
    569            } else {
    570                SDL_SendKeyboardKey(SDL_RELEASED, scancode);
    571            }
    572            */
    573        }
    574        return;
    575    }
    576
    577    /* Send a SDL_SYSWMEVENT if the application wants them */
    578    if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
    579        SDL_SysWMmsg wmmsg;
    580
    581        SDL_VERSION(&wmmsg.version);
    582        wmmsg.subsystem = SDL_SYSWM_X11;
    583        wmmsg.msg.x11.event = xevent;
    584        SDL_SendSysWMEvent(&wmmsg);
    585    }
    586
    587#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
    588    if(xevent.type == GenericEvent) {
    589        X11_HandleGenericEvent(videodata,xevent);
    590        return;
    591    }
    592#endif
    593
    594#if 0
    595    printf("type = %d display = %d window = %d\n",
    596           xevent.type, xevent.xany.display, xevent.xany.window);
    597#endif
    598
    599    data = NULL;
    600    if (videodata && videodata->windowlist) {
    601        for (i = 0; i < videodata->numwindows; ++i) {
    602            if ((videodata->windowlist[i] != NULL) &&
    603                (videodata->windowlist[i]->xwindow == xevent.xany.window)) {
    604                data = videodata->windowlist[i];
    605                break;
    606            }
    607        }
    608    }
    609    if (!data) {
    610        return;
    611    }
    612
    613    switch (xevent.type) {
    614
    615        /* Gaining mouse coverage? */
    616    case EnterNotify:{
    617#ifdef DEBUG_XEVENTS
    618            printf("window %p: EnterNotify! (%d,%d,%d)\n", data,
    619                   xevent.xcrossing.x,
    620                   xevent.xcrossing.y,
    621                   xevent.xcrossing.mode);
    622            if (xevent.xcrossing.mode == NotifyGrab)
    623                printf("Mode: NotifyGrab\n");
    624            if (xevent.xcrossing.mode == NotifyUngrab)
    625                printf("Mode: NotifyUngrab\n");
    626#endif
    627            SDL_SetMouseFocus(data->window);
    628
    629            if (!SDL_GetMouse()->relative_mode) {
    630                SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
    631            }
    632        }
    633        break;
    634        /* Losing mouse coverage? */
    635    case LeaveNotify:{
    636#ifdef DEBUG_XEVENTS
    637            printf("window %p: LeaveNotify! (%d,%d,%d)\n", data,
    638                   xevent.xcrossing.x,
    639                   xevent.xcrossing.y,
    640                   xevent.xcrossing.mode);
    641            if (xevent.xcrossing.mode == NotifyGrab)
    642                printf("Mode: NotifyGrab\n");
    643            if (xevent.xcrossing.mode == NotifyUngrab)
    644                printf("Mode: NotifyUngrab\n");
    645#endif
    646            if (!SDL_GetMouse()->relative_mode) {
    647                SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
    648            }
    649
    650            if (xevent.xcrossing.mode != NotifyGrab &&
    651                xevent.xcrossing.mode != NotifyUngrab &&
    652                xevent.xcrossing.detail != NotifyInferior) {
    653                SDL_SetMouseFocus(NULL);
    654            }
    655        }
    656        break;
    657
    658        /* Gaining input focus? */
    659    case FocusIn:{
    660            if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
    661                /* Someone is handling a global hotkey, ignore it */
    662#ifdef DEBUG_XEVENTS
    663                printf("window %p: FocusIn (NotifyGrab/NotifyUngrab, ignoring)\n", data);
    664#endif
    665                break;
    666            }
    667
    668            if (xevent.xfocus.detail == NotifyInferior) {
    669#ifdef DEBUG_XEVENTS
    670                printf("window %p: FocusIn (NotifierInferior, ignoring)\n", data);
    671#endif
    672                break;
    673            }
    674#ifdef DEBUG_XEVENTS
    675            printf("window %p: FocusIn!\n", data);
    676#endif
    677            if (data->pending_focus == PENDING_FOCUS_OUT &&
    678                data->window == SDL_GetKeyboardFocus()) {
    679                ReconcileKeyboardState(_this, data);
    680            }
    681            data->pending_focus = PENDING_FOCUS_IN;
    682            data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME;
    683        }
    684        break;
    685
    686        /* Losing input focus? */
    687    case FocusOut:{
    688            if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
    689                /* Someone is handling a global hotkey, ignore it */
    690#ifdef DEBUG_XEVENTS
    691                printf("window %p: FocusOut (NotifyGrab/NotifyUngrab, ignoring)\n", data);
    692#endif
    693                break;
    694            }
    695            if (xevent.xfocus.detail == NotifyInferior) {
    696                /* We still have focus if a child gets focus */
    697#ifdef DEBUG_XEVENTS
    698                printf("window %p: FocusOut (NotifierInferior, ignoring)\n", data);
    699#endif
    700                break;
    701            }
    702#ifdef DEBUG_XEVENTS
    703            printf("window %p: FocusOut!\n", data);
    704#endif
    705            data->pending_focus = PENDING_FOCUS_OUT;
    706            data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_OUT_TIME;
    707        }
    708        break;
    709
    710        /* Generated upon EnterWindow and FocusIn */
    711    case KeymapNotify:{
    712#ifdef DEBUG_XEVENTS
    713            printf("window %p: KeymapNotify!\n", data);
    714#endif
    715            /* FIXME:
    716               X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
    717             */
    718        }
    719        break;
    720
    721        /* Has the keyboard layout changed? */
    722    case MappingNotify:{
    723#ifdef DEBUG_XEVENTS
    724            printf("window %p: MappingNotify!\n", data);
    725#endif
    726            X11_UpdateKeymap(_this);
    727        }
    728        break;
    729
    730        /* Key press? */
    731    case KeyPress:{
    732            KeyCode keycode = xevent.xkey.keycode;
    733            KeySym keysym = NoSymbol;
    734            char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
    735            Status status = 0;
    736            SDL_bool handled_by_ime = SDL_FALSE;
    737
    738#ifdef DEBUG_XEVENTS
    739            printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
    740#endif
    741#if 1
    742            if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
    743                int min_keycode, max_keycode;
    744                X11_XDisplayKeycodes(display, &min_keycode, &max_keycode);
    745#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
    746                keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0);
    747#else
    748                keysym = XKeycodeToKeysym(display, keycode, 0);
    749#endif
    750                fprintf(stderr,
    751                        "The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL mailing list <sdl@libsdl.org> X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s).\n",
    752                        keycode, keycode - min_keycode, keysym,
    753                        X11_XKeysymToString(keysym));
    754            }
    755#endif
    756            /* */
    757            SDL_zero(text);
    758#ifdef X_HAVE_UTF8_STRING
    759            if (data->ic) {
    760                X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
    761                                  &keysym, &status);
    762            }
    763#else
    764            XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
    765#endif
    766#ifdef SDL_USE_IBUS
    767            if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
    768                if(!(handled_by_ime = SDL_IBus_ProcessKeyEvent(keysym, keycode))){
    769#endif
    770                    if(*text){
    771                        SDL_SendKeyboardText(text);
    772                    }
    773#ifdef SDL_USE_IBUS
    774                }
    775            }
    776#endif
    777            if (!handled_by_ime) {
    778                SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
    779            }
    780
    781        }
    782        break;
    783
    784        /* Key release? */
    785    case KeyRelease:{
    786            KeyCode keycode = xevent.xkey.keycode;
    787
    788#ifdef DEBUG_XEVENTS
    789            printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
    790#endif
    791            if (X11_KeyRepeat(display, &xevent)) {
    792                /* We're about to get a repeated key down, ignore the key up */
    793                break;
    794            }
    795            SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
    796        }
    797        break;
    798
    799        /* Have we been iconified? */
    800    case UnmapNotify:{
    801#ifdef DEBUG_XEVENTS
    802            printf("window %p: UnmapNotify!\n", data);
    803#endif
    804            X11_DispatchUnmapNotify(data);
    805        }
    806        break;
    807
    808        /* Have we been restored? */
    809    case MapNotify:{
    810#ifdef DEBUG_XEVENTS
    811            printf("window %p: MapNotify!\n", data);
    812#endif
    813            X11_DispatchMapNotify(data);
    814        }
    815        break;
    816
    817        /* Have we been resized or moved? */
    818    case ConfigureNotify:{
    819#ifdef DEBUG_XEVENTS
    820            printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data,
    821                   xevent.xconfigure.x, xevent.xconfigure.y,
    822                   xevent.xconfigure.width, xevent.xconfigure.height);
    823#endif
    824            long border_left = 0;
    825            long border_top = 0;
    826            if (data->xwindow) {
    827                Atom _net_frame_extents = X11_XInternAtom(display, "_NET_FRAME_EXTENTS", 0);
    828                Atom type;
    829                int format;
    830                unsigned long nitems, bytes_after;
    831                unsigned char *property;
    832                if (X11_XGetWindowProperty(display, data->xwindow,
    833                        _net_frame_extents, 0, 16, 0,
    834                        XA_CARDINAL, &type, &format,
    835                        &nitems, &bytes_after, &property) == Success) {
    836                    if (type != None && nitems == 4)
    837                    {
    838                        border_left = ((long*)property)[0];
    839                        border_top = ((long*)property)[2];
    840                    }
    841                    X11_XFree(property);
    842                }
    843            }
    844
    845            if (xevent.xconfigure.x != data->last_xconfigure.x ||
    846                xevent.xconfigure.y != data->last_xconfigure.y) {
    847                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
    848                                    xevent.xconfigure.x - border_left,
    849                                    xevent.xconfigure.y - border_top);
    850#ifdef SDL_USE_IBUS
    851                if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
    852                    /* Update IBus candidate list position */
    853                    SDL_IBus_UpdateTextRect(NULL);
    854                }
    855#endif
    856            }
    857            if (xevent.xconfigure.width != data->last_xconfigure.width ||
    858                xevent.xconfigure.height != data->last_xconfigure.height) {
    859                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED,
    860                                    xevent.xconfigure.width,
    861                                    xevent.xconfigure.height);
    862            }
    863            data->last_xconfigure = xevent.xconfigure;
    864        }
    865        break;
    866
    867        /* Have we been requested to quit (or another client message?) */
    868    case ClientMessage:{
    869
    870            int xdnd_version=0;
    871
    872            if (xevent.xclient.message_type == videodata->XdndEnter) {
    873                SDL_bool use_list = xevent.xclient.data.l[1] & 1;
    874                data->xdnd_source = xevent.xclient.data.l[0];
    875                xdnd_version = ( xevent.xclient.data.l[1] >> 24);
    876                if (use_list) {
    877                    /* fetch conversion targets */
    878                    SDL_x11Prop p;
    879                    X11_ReadProperty(&p, display, data->xdnd_source, videodata->XdndTypeList);
    880                    /* pick one */
    881                    data->xdnd_req = X11_PickTarget(display, (Atom*)p.data, p.count);
    882                    X11_XFree(p.data);
    883                } else {
    884                    /* pick from list of three */
    885                    data->xdnd_req = X11_PickTargetFromAtoms(display, xevent.xclient.data.l[2], xevent.xclient.data.l[3], xevent.xclient.data.l[4]);
    886                }
    887            }
    888            else if (xevent.xclient.message_type == videodata->XdndPosition) {
    889
    890                /* reply with status */
    891                memset(&m, 0, sizeof(XClientMessageEvent));
    892                m.type = ClientMessage;
    893                m.display = xevent.xclient.display;
    894                m.window = xevent.xclient.data.l[0];
    895                m.message_type = videodata->XdndStatus;
    896                m.format=32;
    897                m.data.l[0] = data->xwindow;
    898                m.data.l[1] = (data->xdnd_req != None);
    899                m.data.l[2] = 0; /* specify an empty rectangle */
    900                m.data.l[3] = 0;
    901                m.data.l[4] = videodata->XdndActionCopy; /* we only accept copying anyway */
    902
    903                X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
    904                X11_XFlush(display);
    905            }
    906            else if(xevent.xclient.message_type == videodata->XdndDrop) {
    907                if (data->xdnd_req == None) {
    908                    /* say again - not interested! */
    909                    memset(&m, 0, sizeof(XClientMessageEvent));
    910                    m.type = ClientMessage;
    911                    m.display = xevent.xclient.display;
    912                    m.window = xevent.xclient.data.l[0];
    913                    m.message_type = videodata->XdndFinished;
    914                    m.format=32;
    915                    m.data.l[0] = data->xwindow;
    916                    m.data.l[1] = 0;
    917                    m.data.l[2] = None; /* fail! */
    918                    X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
    919                } else {
    920                    /* convert */
    921                    if(xdnd_version >= 1) {
    922                        X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, xevent.xclient.data.l[2]);
    923                    } else {
    924                        X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, CurrentTime);
    925                    }
    926                }
    927            }
    928            else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
    929                (xevent.xclient.format == 32) &&
    930                (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
    931                Window root = DefaultRootWindow(display);
    932
    933#ifdef DEBUG_XEVENTS
    934                printf("window %p: _NET_WM_PING\n", data);
    935#endif
    936                xevent.xclient.window = root;
    937                X11_XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
    938                break;
    939            }
    940
    941            else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
    942                (xevent.xclient.format == 32) &&
    943                (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
    944
    945#ifdef DEBUG_XEVENTS
    946                printf("window %p: WM_DELETE_WINDOW\n", data);
    947#endif
    948                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
    949                break;
    950            }
    951        }
    952        break;
    953
    954        /* Do we need to refresh ourselves? */
    955    case Expose:{
    956#ifdef DEBUG_XEVENTS
    957            printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
    958#endif
    959            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
    960        }
    961        break;
    962
    963    case MotionNotify:{
    964            SDL_Mouse *mouse = SDL_GetMouse();
    965            if(!mouse->relative_mode || mouse->relative_mode_warp) {
    966#ifdef DEBUG_MOTION
    967                printf("window %p: X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
    968#endif
    969
    970                SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y);
    971            }
    972        }
    973        break;
    974
    975    case ButtonPress:{
    976            int ticks = 0;
    977            if (X11_IsWheelEvent(display,&xevent,&ticks)) {
    978                SDL_SendMouseWheel(data->window, 0, 0, ticks);
    979            } else {
    980                if(xevent.xbutton.button == Button1) {
    981                    if (ProcessHitTest(_this, data, &xevent)) {
    982                        break;  /* don't pass this event on to app. */
    983                    }
    984                }
    985                SDL_SendMouseButton(data->window, 0, SDL_PRESSED, xevent.xbutton.button);
    986            }
    987        }
    988        break;
    989
    990    case ButtonRelease:{
    991            SDL_SendMouseButton(data->window, 0, SDL_RELEASED, xevent.xbutton.button);
    992        }
    993        break;
    994
    995    case PropertyNotify:{
    996#ifdef DEBUG_XEVENTS
    997            unsigned char *propdata;
    998            int status, real_format;
    999            Atom real_type;
   1000            unsigned long items_read, items_left, i;
   1001
   1002            char *name = X11_XGetAtomName(display, xevent.xproperty.atom);
   1003            if (name) {
   1004                printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed");
   1005                X11_XFree(name);
   1006            }
   1007
   1008            status = X11_XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata);
   1009            if (status == Success && items_read > 0) {
   1010                if (real_type == XA_INTEGER) {
   1011                    int *values = (int *)propdata;
   1012
   1013                    printf("{");
   1014                    for (i = 0; i < items_read; i++) {
   1015                        printf(" %d", values[i]);
   1016                    }
   1017                    printf(" }\n");
   1018                } else if (real_type == XA_CARDINAL) {
   1019                    if (real_format == 32) {
   1020                        Uint32 *values = (Uint32 *)propdata;
   1021
   1022                        printf("{");
   1023                        for (i = 0; i < items_read; i++) {
   1024                            printf(" %d", values[i]);
   1025                        }
   1026                        printf(" }\n");
   1027                    } else if (real_format == 16) {
   1028                        Uint16 *values = (Uint16 *)propdata;
   1029
   1030                        printf("{");
   1031                        for (i = 0; i < items_read; i++) {
   1032                            printf(" %d", values[i]);
   1033                        }
   1034                        printf(" }\n");
   1035                    } else if (real_format == 8) {
   1036                        Uint8 *values = (Uint8 *)propdata;
   1037
   1038                        printf("{");
   1039                        for (i = 0; i < items_read; i++) {
   1040                            printf(" %d", values[i]);
   1041                        }
   1042                        printf(" }\n");
   1043                    }
   1044                } else if (real_type == XA_STRING ||
   1045                           real_type == videodata->UTF8_STRING) {
   1046                    printf("{ \"%s\" }\n", propdata);
   1047                } else if (real_type == XA_ATOM) {
   1048                    Atom *atoms = (Atom *)propdata;
   1049
   1050                    printf("{");
   1051                    for (i = 0; i < items_read; i++) {
   1052                        char *name = X11_XGetAtomName(display, atoms[i]);
   1053                        if (name) {
   1054                            printf(" %s", name);
   1055                            X11_XFree(name);
   1056                        }
   1057                    }
   1058                    printf(" }\n");
   1059                } else {
   1060                    char *name = X11_XGetAtomName(display, real_type);
   1061                    printf("Unknown type: %ld (%s)\n", real_type, name ? name : "UNKNOWN");
   1062                    if (name) {
   1063                        X11_XFree(name);
   1064                    }
   1065                }
   1066            }
   1067            if (status == Success) {
   1068                X11_XFree(propdata);
   1069            }
   1070#endif /* DEBUG_XEVENTS */
   1071
   1072            if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
   1073                /* Get the new state from the window manager.
   1074                   Compositing window managers can alter visibility of windows
   1075                   without ever mapping / unmapping them, so we handle that here,
   1076                   because they use the NETWM protocol to notify us of changes.
   1077                 */
   1078                Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window);
   1079				if ((flags^data->window->flags) & SDL_WINDOW_HIDDEN ||
   1080					(flags^data->window->flags) & SDL_WINDOW_FULLSCREEN ) {
   1081                    if (flags & SDL_WINDOW_HIDDEN) {
   1082                        X11_DispatchUnmapNotify(data);
   1083                    } else {
   1084                        X11_DispatchMapNotify(data);
   1085                    }
   1086                }
   1087            }
   1088        }
   1089        break;
   1090
   1091    /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
   1092    case SelectionRequest: {
   1093            XSelectionRequestEvent *req;
   1094            XEvent sevent;
   1095            int seln_format;
   1096            unsigned long nbytes;
   1097            unsigned long overflow;
   1098            unsigned char *seln_data;
   1099
   1100            req = &xevent.xselectionrequest;
   1101#ifdef DEBUG_XEVENTS
   1102            printf("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", data,
   1103                req->requestor, req->target);
   1104#endif
   1105
   1106            SDL_zero(sevent);
   1107            sevent.xany.type = SelectionNotify;
   1108            sevent.xselection.selection = req->selection;
   1109            sevent.xselection.target = None;
   1110            sevent.xselection.property = None;
   1111            sevent.xselection.requestor = req->requestor;
   1112            sevent.xselection.time = req->time;
   1113            if (X11_XGetWindowProperty(display, DefaultRootWindow(display),
   1114                    XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
   1115                    &sevent.xselection.target, &seln_format, &nbytes,
   1116                    &overflow, &seln_data) == Success) {
   1117                Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0);
   1118                if (sevent.xselection.target == req->target) {
   1119                    X11_XChangeProperty(display, req->requestor, req->property,
   1120                        sevent.xselection.target, seln_format, PropModeReplace,
   1121                        seln_data, nbytes);
   1122                    sevent.xselection.property = req->property;
   1123                } else if (XA_TARGETS == req->target) {
   1124                    Atom SupportedFormats[] = { sevent.xselection.target, XA_TARGETS };
   1125                    X11_XChangeProperty(display, req->requestor, req->property,
   1126                        XA_ATOM, 32, PropModeReplace,
   1127                        (unsigned char*)SupportedFormats,
   1128                        sizeof(SupportedFormats)/sizeof(*SupportedFormats));
   1129                    sevent.xselection.property = req->property;
   1130                }
   1131                X11_XFree(seln_data);
   1132            }
   1133            X11_XSendEvent(display, req->requestor, False, 0, &sevent);
   1134            X11_XSync(display, False);
   1135        }
   1136        break;
   1137
   1138    case SelectionNotify: {
   1139#ifdef DEBUG_XEVENTS
   1140            printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
   1141                xevent.xselection.requestor, xevent.xselection.target);
   1142#endif
   1143            Atom target = xevent.xselection.target;
   1144            if (target == data->xdnd_req) {
   1145                /* read data */
   1146                SDL_x11Prop p;
   1147                X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY);
   1148
   1149                if (p.format == 8) {
   1150                    SDL_bool expect_lf = SDL_FALSE;
   1151                    char *start = NULL;
   1152                    char *scan = (char*)p.data;
   1153                    char *fn;
   1154                    char *uri;
   1155                    int length = 0;
   1156                    while (p.count--) {
   1157                        if (!expect_lf) {
   1158                            if (*scan == 0x0D) {
   1159                                expect_lf = SDL_TRUE;
   1160                            }
   1161                            if (start == NULL) {
   1162                                start = scan;
   1163                                length = 0;
   1164                            }
   1165                            length++;
   1166                        } else {
   1167                            if (*scan == 0x0A && length > 0) {
   1168                                uri = SDL_malloc(length--);
   1169                                SDL_memcpy(uri, start, length);
   1170                                uri[length] = '\0';
   1171                                fn = X11_URIToLocal(uri);
   1172                                if (fn) {
   1173                                    SDL_SendDropFile(fn);
   1174                                }
   1175                                SDL_free(uri);
   1176                            }
   1177                            expect_lf = SDL_FALSE;
   1178                            start = NULL;
   1179                        }
   1180                        scan++;
   1181                    }
   1182                }
   1183
   1184                X11_XFree(p.data);
   1185
   1186                /* send reply */
   1187                SDL_memset(&m, 0, sizeof(XClientMessageEvent));
   1188                m.type = ClientMessage;
   1189                m.display = display;
   1190                m.window = data->xdnd_source;
   1191                m.message_type = videodata->XdndFinished;
   1192                m.format = 32;
   1193                m.data.l[0] = data->xwindow;
   1194                m.data.l[1] = 1;
   1195                m.data.l[2] = videodata->XdndActionCopy;
   1196                X11_XSendEvent(display, data->xdnd_source, False, NoEventMask, (XEvent*)&m);
   1197
   1198                X11_XSync(display, False);
   1199
   1200            } else {
   1201                videodata->selection_waiting = SDL_FALSE;
   1202            }
   1203        }
   1204        break;
   1205
   1206    default:{
   1207#ifdef DEBUG_XEVENTS
   1208            printf("window %p: Unhandled event %d\n", data, xevent.type);
   1209#endif
   1210        }
   1211        break;
   1212    }
   1213}
   1214
   1215static void
   1216X11_HandleFocusChanges(_THIS)
   1217{
   1218    SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   1219    int i;
   1220
   1221    if (videodata && videodata->windowlist) {
   1222        for (i = 0; i < videodata->numwindows; ++i) {
   1223            SDL_WindowData *data = videodata->windowlist[i];
   1224            if (data && data->pending_focus != PENDING_FOCUS_NONE) {
   1225                Uint32 now = SDL_GetTicks();
   1226                if (SDL_TICKS_PASSED(now, data->pending_focus_time)) {
   1227                    if ( data->pending_focus == PENDING_FOCUS_IN ) {
   1228                        X11_DispatchFocusIn(data);
   1229                    } else {
   1230                        X11_DispatchFocusOut(data);
   1231                    }
   1232                    data->pending_focus = PENDING_FOCUS_NONE;
   1233                }
   1234            }
   1235        }
   1236    }
   1237}
   1238/* Ack!  X11_XPending() actually performs a blocking read if no events available */
   1239static int
   1240X11_Pending(Display * display)
   1241{
   1242    /* Flush the display connection and look to see if events are queued */
   1243    X11_XFlush(display);
   1244    if (X11_XEventsQueued(display, QueuedAlready)) {
   1245        return (1);
   1246    }
   1247
   1248    /* More drastic measures are required -- see if X is ready to talk */
   1249    {
   1250        static struct timeval zero_time;        /* static == 0 */
   1251        int x11_fd;
   1252        fd_set fdset;
   1253
   1254        x11_fd = ConnectionNumber(display);
   1255        FD_ZERO(&fdset);
   1256        FD_SET(x11_fd, &fdset);
   1257        if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   1258            return (X11_XPending(display));
   1259        }
   1260    }
   1261
   1262    /* Oh well, nothing is ready .. */
   1263    return (0);
   1264}
   1265
   1266void
   1267X11_PumpEvents(_THIS)
   1268{
   1269    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   1270
   1271    /* Update activity every 30 seconds to prevent screensaver */
   1272    if (_this->suspend_screensaver) {
   1273        Uint32 now = SDL_GetTicks();
   1274        if (!data->screensaver_activity ||
   1275            SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) {
   1276            X11_XResetScreenSaver(data->display);
   1277
   1278#if SDL_USE_LIBDBUS
   1279            SDL_DBus_ScreensaverTickle();
   1280#endif
   1281
   1282            data->screensaver_activity = now;
   1283        }
   1284    }
   1285
   1286#ifdef SDL_USE_IBUS
   1287    if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
   1288        SDL_IBus_PumpEvents();
   1289    }
   1290#endif
   1291
   1292    /* Keep processing pending events */
   1293    while (X11_Pending(data->display)) {
   1294        X11_DispatchEvent(_this);
   1295    }
   1296
   1297    /* FIXME: Only need to do this when there are pending focus changes */
   1298    X11_HandleFocusChanges(_this);
   1299}
   1300
   1301
   1302void
   1303X11_SuspendScreenSaver(_THIS)
   1304{
   1305#if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
   1306    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   1307    int dummy;
   1308    int major_version, minor_version;
   1309#endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */
   1310
   1311#if SDL_USE_LIBDBUS
   1312    if (SDL_DBus_ScreensaverInhibit(_this->suspend_screensaver)) {
   1313        return;
   1314    }
   1315
   1316    if (_this->suspend_screensaver) {
   1317        SDL_DBus_ScreensaverTickle();
   1318    }
   1319#endif
   1320
   1321#if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
   1322    if (SDL_X11_HAVE_XSS) {
   1323        /* X11_XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
   1324        if (!X11_XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
   1325            !X11_XScreenSaverQueryVersion(data->display,
   1326                                      &major_version, &minor_version) ||
   1327            major_version < 1 || (major_version == 1 && minor_version < 1)) {
   1328            return;
   1329        }
   1330
   1331        X11_XScreenSaverSuspend(data->display, _this->suspend_screensaver);
   1332        X11_XResetScreenSaver(data->display);
   1333    }
   1334#endif
   1335}
   1336
   1337#endif /* SDL_VIDEO_DRIVER_X11 */
   1338
   1339/* vi: set ts=4 sw=4 expandtab: */