src/video/x11/SDL_x11events.c
author Alex Baines <alex@abaines.me.uk>
Fri, 28 Oct 2016 01:28:58 +0100
changeset 10562 b48d8a98e261
parent 10499 363c1c7e7a41
child 10570 251691cfeaa0
permissions -rw-r--r--
Fix double events / no repeat flag on key events when built withoutibus/fcitx

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