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