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