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