src/video/x11/SDL_x11events.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 02 Nov 2016 02:56:54 -0700
changeset 10572 8b8a45c000f9
parent 10570 251691cfeaa0
child 10609 d702ecbd8ba7
permissions -rw-r--r--
Fixed text input events with UIM

Alex Baines

I realized overnight that my patch probably broke text input events with UIM, and I confirmed that it does. Can't believe I overlooked that... I've been making stupid mistakes in these patches recently, sorry.

Anyway, *this* one seems to fix it properly. Knowing my luck it probably breaks something else.
     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             videodata->filter_code = orig_keycode;
   578             videodata->filter_time = xevent.xkey.time;
   579 
   580             if (orig_event_type == KeyPress) {
   581                 SDL_SendKeyboardKey(SDL_PRESSED, scancode);
   582             } else {
   583                 SDL_SendKeyboardKey(SDL_RELEASED, scancode);
   584             }
   585 #endif
   586         }
   587         return;
   588     }
   589 
   590     /* Send a SDL_SYSWMEVENT if the application wants them */
   591     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   592         SDL_SysWMmsg wmmsg;
   593 
   594         SDL_VERSION(&wmmsg.version);
   595         wmmsg.subsystem = SDL_SYSWM_X11;
   596         wmmsg.msg.x11.event = xevent;
   597         SDL_SendSysWMEvent(&wmmsg);
   598     }
   599 
   600 #if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
   601     if(xevent.type == GenericEvent) {
   602         X11_HandleGenericEvent(videodata,xevent);
   603         return;
   604     }
   605 #endif
   606 
   607 #if 0
   608     printf("type = %d display = %d window = %d\n",
   609            xevent.type, xevent.xany.display, xevent.xany.window);
   610 #endif
   611 
   612     data = NULL;
   613     if (videodata && videodata->windowlist) {
   614         for (i = 0; i < videodata->numwindows; ++i) {
   615             if ((videodata->windowlist[i] != NULL) &&
   616                 (videodata->windowlist[i]->xwindow == xevent.xany.window)) {
   617                 data = videodata->windowlist[i];
   618                 break;
   619             }
   620         }
   621     }
   622     if (!data) {
   623         /* The window for KeymapNotify, etc events is 0 */
   624         if (xevent.type == KeymapNotify) {
   625             if (SDL_GetKeyboardFocus() != NULL) {
   626                 X11_ReconcileKeyboardState(_this);
   627             }
   628         } else if (xevent.type == MappingNotify) {
   629             /* Has the keyboard layout changed? */
   630             const int request = xevent.xmapping.request;
   631 
   632 #ifdef DEBUG_XEVENTS
   633             printf("window %p: MappingNotify!\n", data);
   634 #endif
   635             if ((request == MappingKeyboard) || (request == MappingModifier)) {
   636                 X11_XRefreshKeyboardMapping(&xevent.xmapping);
   637             }
   638 
   639             X11_UpdateKeymap(_this);
   640             SDL_SendKeymapChangedEvent();
   641         }
   642         return;
   643     }
   644 
   645     switch (xevent.type) {
   646 
   647         /* Gaining mouse coverage? */
   648     case EnterNotify:{
   649             SDL_Mouse *mouse = SDL_GetMouse();
   650 #ifdef DEBUG_XEVENTS
   651             printf("window %p: EnterNotify! (%d,%d,%d)\n", data,
   652                    xevent.xcrossing.x,
   653                    xevent.xcrossing.y,
   654                    xevent.xcrossing.mode);
   655             if (xevent.xcrossing.mode == NotifyGrab)
   656                 printf("Mode: NotifyGrab\n");
   657             if (xevent.xcrossing.mode == NotifyUngrab)
   658                 printf("Mode: NotifyUngrab\n");
   659 #endif
   660             SDL_SetMouseFocus(data->window);
   661 
   662             mouse->last_x = xevent.xcrossing.x;
   663             mouse->last_y = xevent.xcrossing.y;
   664 
   665             if (!mouse->relative_mode) {
   666                 SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
   667             }
   668         }
   669         break;
   670         /* Losing mouse coverage? */
   671     case LeaveNotify:{
   672 #ifdef DEBUG_XEVENTS
   673             printf("window %p: LeaveNotify! (%d,%d,%d)\n", data,
   674                    xevent.xcrossing.x,
   675                    xevent.xcrossing.y,
   676                    xevent.xcrossing.mode);
   677             if (xevent.xcrossing.mode == NotifyGrab)
   678                 printf("Mode: NotifyGrab\n");
   679             if (xevent.xcrossing.mode == NotifyUngrab)
   680                 printf("Mode: NotifyUngrab\n");
   681 #endif
   682             if (!SDL_GetMouse()->relative_mode) {
   683                 SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
   684             }
   685 
   686             if (xevent.xcrossing.mode != NotifyGrab &&
   687                 xevent.xcrossing.mode != NotifyUngrab &&
   688                 xevent.xcrossing.detail != NotifyInferior) {
   689                 SDL_SetMouseFocus(NULL);
   690             }
   691         }
   692         break;
   693 
   694         /* Gaining input focus? */
   695     case FocusIn:{
   696             if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
   697                 /* Someone is handling a global hotkey, ignore it */
   698 #ifdef DEBUG_XEVENTS
   699                 printf("window %p: FocusIn (NotifyGrab/NotifyUngrab, ignoring)\n", data);
   700 #endif
   701                 break;
   702             }
   703 
   704             if (xevent.xfocus.detail == NotifyInferior) {
   705 #ifdef DEBUG_XEVENTS
   706                 printf("window %p: FocusIn (NotifierInferior, ignoring)\n", data);
   707 #endif
   708                 break;
   709             }
   710 #ifdef DEBUG_XEVENTS
   711             printf("window %p: FocusIn!\n", data);
   712 #endif
   713             if (!videodata->last_mode_change_deadline) /* no recent mode changes */
   714             {
   715                 data->pending_focus = PENDING_FOCUS_NONE;
   716                 data->pending_focus_time = 0;
   717                 X11_DispatchFocusIn(_this, data);
   718             }
   719             else
   720             {
   721                 data->pending_focus = PENDING_FOCUS_IN;
   722                 data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME;
   723             }
   724             data->last_focus_event_time = SDL_GetTicks();
   725         }
   726         break;
   727 
   728         /* Losing input focus? */
   729     case FocusOut:{
   730             if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
   731                 /* Someone is handling a global hotkey, ignore it */
   732 #ifdef DEBUG_XEVENTS
   733                 printf("window %p: FocusOut (NotifyGrab/NotifyUngrab, ignoring)\n", data);
   734 #endif
   735                 break;
   736             }
   737             if (xevent.xfocus.detail == NotifyInferior) {
   738                 /* We still have focus if a child gets focus */
   739 #ifdef DEBUG_XEVENTS
   740                 printf("window %p: FocusOut (NotifierInferior, ignoring)\n", data);
   741 #endif
   742                 break;
   743             }
   744 #ifdef DEBUG_XEVENTS
   745             printf("window %p: FocusOut!\n", data);
   746 #endif
   747             if (!videodata->last_mode_change_deadline) /* no recent mode changes */
   748             {
   749                 data->pending_focus = PENDING_FOCUS_NONE;
   750                 data->pending_focus_time = 0;
   751                 X11_DispatchFocusOut(_this, data);
   752             }
   753             else
   754             {
   755                 data->pending_focus = PENDING_FOCUS_OUT;
   756                 data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME;
   757             }
   758         }
   759         break;
   760 
   761         /* Key press? */
   762     case KeyPress:{
   763             KeyCode keycode = xevent.xkey.keycode;
   764             KeySym keysym = NoSymbol;
   765             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
   766             Status status = 0;
   767             SDL_bool handled_by_ime = SDL_FALSE;
   768 
   769 #ifdef DEBUG_XEVENTS
   770             printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
   771 #endif
   772 #if 1
   773             if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
   774                 int min_keycode, max_keycode;
   775                 X11_XDisplayKeycodes(display, &min_keycode, &max_keycode);
   776                 keysym = X11_KeyCodeToSym(_this, keycode, xevent.xkey.state >> 13);
   777                 fprintf(stderr,
   778                         "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",
   779                         keycode, keycode - min_keycode, keysym,
   780                         X11_XKeysymToString(keysym));
   781             }
   782 #endif
   783             /* */
   784             SDL_zero(text);
   785 #ifdef X_HAVE_UTF8_STRING
   786             if (data->ic) {
   787                 X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   788                                   &keysym, &status);
   789             } else {
   790                 X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   791             }
   792 #else
   793             X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   794 #endif
   795 
   796 #ifdef SDL_USE_IME
   797             if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
   798                 handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode);
   799             }
   800 #endif
   801             if (!handled_by_ime) {
   802                 /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */
   803                 if (xevent.xkey.keycode != videodata->filter_code || xevent.xkey.time != videodata->filter_time) {
   804                     SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
   805                 }
   806                 if(*text) {
   807                     SDL_SendKeyboardText(text);
   808                 }
   809             }
   810 
   811             X11_UpdateUserTime(data, xevent.xkey.time);
   812         }
   813         break;
   814 
   815         /* Key release? */
   816     case KeyRelease:{
   817             KeyCode keycode = xevent.xkey.keycode;
   818 
   819 #ifdef DEBUG_XEVENTS
   820             printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
   821 #endif
   822             if (X11_KeyRepeat(display, &xevent)) {
   823                 /* We're about to get a repeated key down, ignore the key up */
   824                 break;
   825             }
   826             SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
   827         }
   828         break;
   829 
   830         /* Have we been iconified? */
   831     case UnmapNotify:{
   832 #ifdef DEBUG_XEVENTS
   833             printf("window %p: UnmapNotify!\n", data);
   834 #endif
   835             X11_DispatchUnmapNotify(data);
   836         }
   837         break;
   838 
   839         /* Have we been restored? */
   840     case MapNotify:{
   841 #ifdef DEBUG_XEVENTS
   842             printf("window %p: MapNotify!\n", data);
   843 #endif
   844             X11_DispatchMapNotify(data);
   845         }
   846         break;
   847 
   848         /* Have we been resized or moved? */
   849     case ConfigureNotify:{
   850 #ifdef DEBUG_XEVENTS
   851             printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data,
   852                    xevent.xconfigure.x, xevent.xconfigure.y,
   853                    xevent.xconfigure.width, xevent.xconfigure.height);
   854 #endif
   855             /* Real configure notify events are relative to the parent, synthetic events are absolute. */
   856             if (!xevent.xconfigure.send_event) {
   857                 unsigned int NumChildren;
   858                 Window ChildReturn, Root, Parent;
   859                 Window * Children;
   860                 /* Translate these coodinates back to relative to root */
   861                 X11_XQueryTree(data->videodata->display, xevent.xconfigure.window, &Root, &Parent, &Children, &NumChildren);
   862                 X11_XTranslateCoordinates(xevent.xconfigure.display,
   863                                         Parent, DefaultRootWindow(xevent.xconfigure.display),
   864                                         xevent.xconfigure.x, xevent.xconfigure.y,
   865                                         &xevent.xconfigure.x, &xevent.xconfigure.y,
   866                                         &ChildReturn);
   867             }
   868                 
   869             if (xevent.xconfigure.x != data->last_xconfigure.x ||
   870                 xevent.xconfigure.y != data->last_xconfigure.y) {
   871                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
   872                                     xevent.xconfigure.x, xevent.xconfigure.y);
   873 #ifdef SDL_USE_IME
   874                 if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
   875                     /* Update IME candidate list position */
   876                     SDL_IME_UpdateTextRect(NULL);
   877                 }
   878 #endif
   879             }
   880             if (xevent.xconfigure.width != data->last_xconfigure.width ||
   881                 xevent.xconfigure.height != data->last_xconfigure.height) {
   882                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED,
   883                                     xevent.xconfigure.width,
   884                                     xevent.xconfigure.height);
   885             }
   886             data->last_xconfigure = xevent.xconfigure;
   887         }
   888         break;
   889 
   890         /* Have we been requested to quit (or another client message?) */
   891     case ClientMessage:{
   892 
   893             static int xdnd_version=0;
   894 
   895             if (xevent.xclient.message_type == videodata->XdndEnter) {
   896 
   897                 SDL_bool use_list = xevent.xclient.data.l[1] & 1;
   898                 data->xdnd_source = xevent.xclient.data.l[0];
   899                 xdnd_version = (xevent.xclient.data.l[1] >> 24);
   900 #ifdef DEBUG_XEVENTS
   901                 printf("XID of source window : %ld\n", data->xdnd_source);
   902                 printf("Protocol version to use : %d\n", xdnd_version);
   903                 printf("More then 3 data types : %d\n", (int) use_list);
   904 #endif
   905  
   906                 if (use_list) {
   907                     /* fetch conversion targets */
   908                     SDL_x11Prop p;
   909                     X11_ReadProperty(&p, display, data->xdnd_source, videodata->XdndTypeList);
   910                     /* pick one */
   911                     data->xdnd_req = X11_PickTarget(display, (Atom*)p.data, p.count);
   912                     X11_XFree(p.data);
   913                 } else {
   914                     /* pick from list of three */
   915                     data->xdnd_req = X11_PickTargetFromAtoms(display, xevent.xclient.data.l[2], xevent.xclient.data.l[3], xevent.xclient.data.l[4]);
   916                 }
   917             }
   918             else if (xevent.xclient.message_type == videodata->XdndPosition) {
   919             
   920 #ifdef DEBUG_XEVENTS
   921                 Atom act= videodata->XdndActionCopy;
   922                 if(xdnd_version >= 2) {
   923                     act = xevent.xclient.data.l[4];
   924                 }
   925                 printf("Action requested by user is : %s\n", X11_XGetAtomName(display , act));
   926 #endif
   927                 
   928 
   929                 /* reply with status */
   930                 memset(&m, 0, sizeof(XClientMessageEvent));
   931                 m.type = ClientMessage;
   932                 m.display = xevent.xclient.display;
   933                 m.window = xevent.xclient.data.l[0];
   934                 m.message_type = videodata->XdndStatus;
   935                 m.format=32;
   936                 m.data.l[0] = data->xwindow;
   937                 m.data.l[1] = (data->xdnd_req != None);
   938                 m.data.l[2] = 0; /* specify an empty rectangle */
   939                 m.data.l[3] = 0;
   940                 m.data.l[4] = videodata->XdndActionCopy; /* we only accept copying anyway */
   941 
   942                 X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
   943                 X11_XFlush(display);
   944             }
   945             else if(xevent.xclient.message_type == videodata->XdndDrop) {
   946                 if (data->xdnd_req == None) {
   947                     /* say again - not interested! */
   948                     memset(&m, 0, sizeof(XClientMessageEvent));
   949                     m.type = ClientMessage;
   950                     m.display = xevent.xclient.display;
   951                     m.window = xevent.xclient.data.l[0];
   952                     m.message_type = videodata->XdndFinished;
   953                     m.format=32;
   954                     m.data.l[0] = data->xwindow;
   955                     m.data.l[1] = 0;
   956                     m.data.l[2] = None; /* fail! */
   957                     X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
   958                 } else {
   959                     /* convert */
   960                     if(xdnd_version >= 1) {
   961                         X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, xevent.xclient.data.l[2]);
   962                     } else {
   963                         X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, CurrentTime);
   964                     }
   965                 }
   966             }
   967             else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   968                 (xevent.xclient.format == 32) &&
   969                 (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
   970                 Window root = DefaultRootWindow(display);
   971 
   972 #ifdef DEBUG_XEVENTS
   973                 printf("window %p: _NET_WM_PING\n", data);
   974 #endif
   975                 xevent.xclient.window = root;
   976                 X11_XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
   977                 break;
   978             }
   979 
   980             else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   981                 (xevent.xclient.format == 32) &&
   982                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   983 
   984 #ifdef DEBUG_XEVENTS
   985                 printf("window %p: WM_DELETE_WINDOW\n", data);
   986 #endif
   987                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   988                 break;
   989             }
   990             else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   991                 (xevent.xclient.format == 32) &&
   992                 (xevent.xclient.data.l[0] == videodata->WM_TAKE_FOCUS)) {
   993 
   994 #ifdef DEBUG_XEVENTS
   995                 printf("window %p: WM_TAKE_FOCUS\n", data);
   996 #endif
   997                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_TAKE_FOCUS, 0, 0);
   998                 break;
   999             }
  1000         }
  1001         break;
  1002 
  1003         /* Do we need to refresh ourselves? */
  1004     case Expose:{
  1005 #ifdef DEBUG_XEVENTS
  1006             printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
  1007 #endif
  1008             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
  1009         }
  1010         break;
  1011 
  1012     case MotionNotify:{
  1013             SDL_Mouse *mouse = SDL_GetMouse();
  1014             if(!mouse->relative_mode || mouse->relative_mode_warp) {
  1015 #ifdef DEBUG_MOTION
  1016                 printf("window %p: X11 motion: %d,%d\n", data, xevent.xmotion.x, xevent.xmotion.y);
  1017 #endif
  1018 
  1019                 SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y);
  1020             }
  1021         }
  1022         break;
  1023 
  1024     case ButtonPress:{
  1025             int xticks = 0, yticks = 0;
  1026 #ifdef DEBUG_XEVENTS
  1027             printf("window %p: ButtonPress (X11 button = %d)\n", data, xevent.xbutton.button);
  1028 #endif
  1029             if (X11_IsWheelEvent(display,&xevent,&xticks, &yticks)) {
  1030                 SDL_SendMouseWheel(data->window, 0, xticks, yticks, SDL_MOUSEWHEEL_NORMAL);
  1031             } else {
  1032                 SDL_bool ignore_click = SDL_FALSE;
  1033                 int button = xevent.xbutton.button;
  1034                 if(button == Button1) {
  1035                     if (ProcessHitTest(_this, data, &xevent)) {
  1036                         SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0);
  1037                         break;  /* don't pass this event on to app. */
  1038                     }
  1039                 }
  1040                 else if(button > 7) {
  1041                     /* X button values 4-7 are used for scrolling, so X1 is 8, X2 is 9, ...
  1042                        => subtract (8-SDL_BUTTON_X1) to get value SDL expects */
  1043                     button -= (8-SDL_BUTTON_X1);
  1044                 }
  1045                 if (data->last_focus_event_time) {
  1046                     const int X11_FOCUS_CLICK_TIMEOUT = 10;
  1047                     if (!SDL_TICKS_PASSED(SDL_GetTicks(), data->last_focus_event_time + X11_FOCUS_CLICK_TIMEOUT)) {
  1048                         ignore_click = !SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, SDL_FALSE);
  1049                     }
  1050                     data->last_focus_event_time = 0;
  1051                 }
  1052                 if (!ignore_click) {
  1053                     SDL_SendMouseButton(data->window, 0, SDL_PRESSED, button);
  1054                 }
  1055             }
  1056             X11_UpdateUserTime(data, xevent.xbutton.time);
  1057         }
  1058         break;
  1059 
  1060     case ButtonRelease:{
  1061             int button = xevent.xbutton.button;
  1062             /* The X server sends a Release event for each Press for wheels. Ignore them. */
  1063             int xticks = 0, yticks = 0;
  1064 #ifdef DEBUG_XEVENTS
  1065             printf("window %p: ButtonRelease (X11 button = %d)\n", data, xevent.xbutton.button);
  1066 #endif
  1067             if (!X11_IsWheelEvent(display, &xevent, &xticks, &yticks)) {
  1068                 if (button > 7) {
  1069                     /* see explanation at case ButtonPress */
  1070                     button -= (8-SDL_BUTTON_X1);
  1071                 }
  1072                 SDL_SendMouseButton(data->window, 0, SDL_RELEASED, button);
  1073             }
  1074         }
  1075         break;
  1076 
  1077     case PropertyNotify:{
  1078 #ifdef DEBUG_XEVENTS
  1079             unsigned char *propdata;
  1080             int status, real_format;
  1081             Atom real_type;
  1082             unsigned long items_read, items_left;
  1083 
  1084             char *name = X11_XGetAtomName(display, xevent.xproperty.atom);
  1085             if (name) {
  1086                 printf("window %p: PropertyNotify: %s %s time=%lu\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed", xevent.xproperty.time);
  1087                 X11_XFree(name);
  1088             }
  1089 
  1090             status = X11_XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata);
  1091             if (status == Success && items_read > 0) {
  1092                 if (real_type == XA_INTEGER) {
  1093                     int *values = (int *)propdata;
  1094 
  1095                     printf("{");
  1096                     for (i = 0; i < items_read; i++) {
  1097                         printf(" %d", values[i]);
  1098                     }
  1099                     printf(" }\n");
  1100                 } else if (real_type == XA_CARDINAL) {
  1101                     if (real_format == 32) {
  1102                         Uint32 *values = (Uint32 *)propdata;
  1103 
  1104                         printf("{");
  1105                         for (i = 0; i < items_read; i++) {
  1106                             printf(" %d", values[i]);
  1107                         }
  1108                         printf(" }\n");
  1109                     } else if (real_format == 16) {
  1110                         Uint16 *values = (Uint16 *)propdata;
  1111 
  1112                         printf("{");
  1113                         for (i = 0; i < items_read; i++) {
  1114                             printf(" %d", values[i]);
  1115                         }
  1116                         printf(" }\n");
  1117                     } else if (real_format == 8) {
  1118                         Uint8 *values = (Uint8 *)propdata;
  1119 
  1120                         printf("{");
  1121                         for (i = 0; i < items_read; i++) {
  1122                             printf(" %d", values[i]);
  1123                         }
  1124                         printf(" }\n");
  1125                     }
  1126                 } else if (real_type == XA_STRING ||
  1127                            real_type == videodata->UTF8_STRING) {
  1128                     printf("{ \"%s\" }\n", propdata);
  1129                 } else if (real_type == XA_ATOM) {
  1130                     Atom *atoms = (Atom *)propdata;
  1131 
  1132                     printf("{");
  1133                     for (i = 0; i < items_read; i++) {
  1134                         char *atomname = X11_XGetAtomName(display, atoms[i]);
  1135                         if (atomname) {
  1136                             printf(" %s", atomname);
  1137                             X11_XFree(atomname);
  1138                         }
  1139                     }
  1140                     printf(" }\n");
  1141                 } else {
  1142                     char *atomname = X11_XGetAtomName(display, real_type);
  1143                     printf("Unknown type: %ld (%s)\n", real_type, atomname ? atomname : "UNKNOWN");
  1144                     if (atomname) {
  1145                         X11_XFree(atomname);
  1146                     }
  1147                 }
  1148             }
  1149             if (status == Success) {
  1150                 X11_XFree(propdata);
  1151             }
  1152 #endif /* DEBUG_XEVENTS */
  1153 
  1154             /* Take advantage of this moment to make sure user_time has a
  1155                 valid timestamp from the X server, so if we later try to
  1156                 raise/restore this window, _NET_ACTIVE_WINDOW can have a
  1157                 non-zero timestamp, even if there's never been a mouse or
  1158                 key press to this window so far. Note that we don't try to
  1159                 set _NET_WM_USER_TIME here, though. That's only for legit
  1160                 user interaction with the window. */
  1161             if (!data->user_time) {
  1162                 data->user_time = xevent.xproperty.time;
  1163             }
  1164 
  1165             if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
  1166                 /* Get the new state from the window manager.
  1167                    Compositing window managers can alter visibility of windows
  1168                    without ever mapping / unmapping them, so we handle that here,
  1169                    because they use the NETWM protocol to notify us of changes.
  1170                  */
  1171                 const Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window);
  1172                 const Uint32 changed = flags ^ data->window->flags;
  1173 
  1174                 if ((changed & SDL_WINDOW_HIDDEN) || (changed & SDL_WINDOW_FULLSCREEN)) {
  1175                      if (flags & SDL_WINDOW_HIDDEN) {
  1176                          X11_DispatchUnmapNotify(data);
  1177                      } else {
  1178                          X11_DispatchMapNotify(data);
  1179                     }
  1180                 }
  1181 
  1182                 if (changed & SDL_WINDOW_MAXIMIZED) {
  1183                     if (flags & SDL_WINDOW_MAXIMIZED) {
  1184                         SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
  1185                     } else {
  1186                         SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
  1187                     }
  1188                 }
  1189             } else if (xevent.xproperty.atom == videodata->XKLAVIER_STATE) {
  1190                 /* Hack for Ubuntu 12.04 (etc) that doesn't send MappingNotify
  1191                    events when the keyboard layout changes (for example,
  1192                    changing from English to French on the menubar's keyboard
  1193                    icon). Since it changes the XKLAVIER_STATE property, we
  1194                    notice and reinit our keymap here. This might not be the
  1195                    right approach, but it seems to work. */
  1196                 X11_UpdateKeymap(_this);
  1197                 SDL_SendKeymapChangedEvent();
  1198             } else if (xevent.xproperty.atom == videodata->_NET_FRAME_EXTENTS) {
  1199                 Atom type;
  1200                 int format;
  1201                 unsigned long nitems, bytes_after;
  1202                 unsigned char *property;
  1203                 if (X11_XGetWindowProperty(display, data->xwindow, videodata->_NET_FRAME_EXTENTS, 0, 16, 0, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &property) == Success) {
  1204                     if (type != None && nitems == 4) {
  1205                         data->border_left = (int) ((long*)property)[0];
  1206                         data->border_right = (int) ((long*)property)[1];
  1207                         data->border_top = (int) ((long*)property)[2];
  1208                         data->border_bottom = (int) ((long*)property)[3];
  1209                     }
  1210                     X11_XFree(property);
  1211 
  1212                     #ifdef DEBUG_XEVENTS
  1213                     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);
  1214                     #endif
  1215                 }
  1216             }
  1217         }
  1218         break;
  1219 
  1220     /* Copy the selection from our own CUTBUFFER to the requested property */
  1221     case SelectionRequest: {
  1222             XSelectionRequestEvent *req;
  1223             XEvent sevent;
  1224             int seln_format;
  1225             unsigned long nbytes;
  1226             unsigned long overflow;
  1227             unsigned char *seln_data;
  1228 
  1229             req = &xevent.xselectionrequest;
  1230 #ifdef DEBUG_XEVENTS
  1231             printf("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", data,
  1232                 req->requestor, req->target);
  1233 #endif
  1234 
  1235             SDL_zero(sevent);
  1236             sevent.xany.type = SelectionNotify;
  1237             sevent.xselection.selection = req->selection;
  1238             sevent.xselection.target = None;
  1239             sevent.xselection.property = None;
  1240             sevent.xselection.requestor = req->requestor;
  1241             sevent.xselection.time = req->time;
  1242 
  1243             if (X11_XGetWindowProperty(display, DefaultRootWindow(display),
  1244                     X11_GetSDLCutBufferClipboardType(display), 0, INT_MAX/4, False, req->target,
  1245                     &sevent.xselection.target, &seln_format, &nbytes,
  1246                     &overflow, &seln_data) == Success) {
  1247                 Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0);
  1248                 if (sevent.xselection.target == req->target) {
  1249                     X11_XChangeProperty(display, req->requestor, req->property,
  1250                         sevent.xselection.target, seln_format, PropModeReplace,
  1251                         seln_data, nbytes);
  1252                     sevent.xselection.property = req->property;
  1253                 } else if (XA_TARGETS == req->target) {
  1254                     Atom SupportedFormats[] = { XA_TARGETS, sevent.xselection.target };
  1255                     X11_XChangeProperty(display, req->requestor, req->property,
  1256                         XA_ATOM, 32, PropModeReplace,
  1257                         (unsigned char*)SupportedFormats,
  1258                         SDL_arraysize(SupportedFormats));
  1259                     sevent.xselection.property = req->property;
  1260                     sevent.xselection.target = XA_TARGETS;
  1261                 }
  1262                 X11_XFree(seln_data);
  1263             }
  1264             X11_XSendEvent(display, req->requestor, False, 0, &sevent);
  1265             X11_XSync(display, False);
  1266         }
  1267         break;
  1268 
  1269     case SelectionNotify: {
  1270             Atom target = xevent.xselection.target;
  1271 #ifdef DEBUG_XEVENTS
  1272             printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
  1273                 xevent.xselection.requestor, xevent.xselection.target);
  1274 #endif
  1275             if (target == data->xdnd_req) {
  1276                 /* read data */
  1277                 SDL_x11Prop p;
  1278                 X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY);
  1279 
  1280                 if (p.format == 8) {
  1281                     /* !!! FIXME: don't use strtok here. It's not reentrant and not in SDL_stdinc. */
  1282                     char* name = X11_XGetAtomName(display, target);
  1283                     char *token = strtok((char *) p.data, "\r\n");
  1284                     while (token != NULL) {
  1285                         if (SDL_strcmp("text/plain", name)==0) {
  1286                             SDL_SendDropText(data->window, token);
  1287                         } else if (SDL_strcmp("text/uri-list", name)==0) {
  1288                             char *fn = X11_URIToLocal(token);
  1289                             if (fn) {
  1290                                 SDL_SendDropFile(data->window, fn);
  1291                             }
  1292                         }
  1293                         token = strtok(NULL, "\r\n");
  1294                     }
  1295                     SDL_SendDropComplete(data->window);
  1296                 }
  1297                 X11_XFree(p.data);
  1298 
  1299                 /* send reply */
  1300                 SDL_memset(&m, 0, sizeof(XClientMessageEvent));
  1301                 m.type = ClientMessage;
  1302                 m.display = display;
  1303                 m.window = data->xdnd_source;
  1304                 m.message_type = videodata->XdndFinished;
  1305                 m.format = 32;
  1306                 m.data.l[0] = data->xwindow;
  1307                 m.data.l[1] = 1;
  1308                 m.data.l[2] = videodata->XdndActionCopy;
  1309                 X11_XSendEvent(display, data->xdnd_source, False, NoEventMask, (XEvent*)&m);
  1310 
  1311                 X11_XSync(display, False);
  1312 
  1313             } else {
  1314                 videodata->selection_waiting = SDL_FALSE;
  1315             }
  1316         }
  1317         break;
  1318 
  1319     case SelectionClear: {
  1320             Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0);
  1321 
  1322             if (xevent.xselectionclear.selection == XA_PRIMARY ||
  1323                 (XA_CLIPBOARD != None && xevent.xselectionclear.selection == XA_CLIPBOARD)) {
  1324                 SDL_SendClipboardUpdate();
  1325             }
  1326         }
  1327         break;
  1328 
  1329     default:{
  1330 #ifdef DEBUG_XEVENTS
  1331             printf("window %p: Unhandled event %d\n", data, xevent.type);
  1332 #endif
  1333         }
  1334         break;
  1335     }
  1336 }
  1337 
  1338 static void
  1339 X11_HandleFocusChanges(_THIS)
  1340 {
  1341     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1342     int i;
  1343 
  1344     if (videodata && videodata->windowlist) {
  1345         for (i = 0; i < videodata->numwindows; ++i) {
  1346             SDL_WindowData *data = videodata->windowlist[i];
  1347             if (data && data->pending_focus != PENDING_FOCUS_NONE) {
  1348                 Uint32 now = SDL_GetTicks();
  1349                 if (SDL_TICKS_PASSED(now, data->pending_focus_time)) {
  1350                     if (data->pending_focus == PENDING_FOCUS_IN) {
  1351                         X11_DispatchFocusIn(_this, data);
  1352                     } else {
  1353                         X11_DispatchFocusOut(_this, data);
  1354                     }
  1355                     data->pending_focus = PENDING_FOCUS_NONE;
  1356                 }
  1357             }
  1358         }
  1359     }
  1360 }
  1361 /* Ack!  X11_XPending() actually performs a blocking read if no events available */
  1362 static int
  1363 X11_Pending(Display * display)
  1364 {
  1365     /* Flush the display connection and look to see if events are queued */
  1366     X11_XFlush(display);
  1367     if (X11_XEventsQueued(display, QueuedAlready)) {
  1368         return (1);
  1369     }
  1370 
  1371     /* More drastic measures are required -- see if X is ready to talk */
  1372     {
  1373         static struct timeval zero_time;        /* static == 0 */
  1374         int x11_fd;
  1375         fd_set fdset;
  1376 
  1377         x11_fd = ConnectionNumber(display);
  1378         FD_ZERO(&fdset);
  1379         FD_SET(x11_fd, &fdset);
  1380         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
  1381             return (X11_XPending(display));
  1382         }
  1383     }
  1384 
  1385     /* Oh well, nothing is ready .. */
  1386     return (0);
  1387 }
  1388 
  1389 void
  1390 X11_PumpEvents(_THIS)
  1391 {
  1392     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  1393 
  1394     if (data->last_mode_change_deadline) {
  1395         if (SDL_TICKS_PASSED(SDL_GetTicks(), data->last_mode_change_deadline)) {
  1396             data->last_mode_change_deadline = 0;  /* assume we're done. */
  1397         }
  1398     }
  1399 
  1400     /* Update activity every 30 seconds to prevent screensaver */
  1401     if (_this->suspend_screensaver) {
  1402         const Uint32 now = SDL_GetTicks();
  1403         if (!data->screensaver_activity ||
  1404             SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) {
  1405             X11_XResetScreenSaver(data->display);
  1406 
  1407 #if SDL_USE_LIBDBUS
  1408             SDL_DBus_ScreensaverTickle();
  1409 #endif
  1410 
  1411             data->screensaver_activity = now;
  1412         }
  1413     }
  1414 
  1415     /* Keep processing pending events */
  1416     while (X11_Pending(data->display)) {
  1417         X11_DispatchEvent(_this);
  1418     }
  1419 
  1420 #ifdef SDL_USE_IME
  1421     if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
  1422         SDL_IME_PumpEvents();
  1423     }
  1424 #endif
  1425 
  1426     /* FIXME: Only need to do this when there are pending focus changes */
  1427     X11_HandleFocusChanges(_this);
  1428 }
  1429 
  1430 
  1431 void
  1432 X11_SuspendScreenSaver(_THIS)
  1433 {
  1434 #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
  1435     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  1436     int dummy;
  1437     int major_version, minor_version;
  1438 #endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */
  1439 
  1440 #if SDL_USE_LIBDBUS
  1441     if (SDL_DBus_ScreensaverInhibit(_this->suspend_screensaver)) {
  1442         return;
  1443     }
  1444 
  1445     if (_this->suspend_screensaver) {
  1446         SDL_DBus_ScreensaverTickle();
  1447     }
  1448 #endif
  1449 
  1450 #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
  1451     if (SDL_X11_HAVE_XSS) {
  1452         /* X11_XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
  1453         if (!X11_XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
  1454             !X11_XScreenSaverQueryVersion(data->display,
  1455                                       &major_version, &minor_version) ||
  1456             major_version < 1 || (major_version == 1 && minor_version < 1)) {
  1457             return;
  1458         }
  1459 
  1460         X11_XScreenSaverSuspend(data->display, _this->suspend_screensaver);
  1461         X11_XResetScreenSaver(data->display);
  1462     }
  1463 #endif
  1464 }
  1465 
  1466 #endif /* SDL_VIDEO_DRIVER_X11 */
  1467 
  1468 /* vi: set ts=4 sw=4 expandtab: */