src/video/x11/SDL_x11events.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 06 Apr 2015 00:10:54 -0400
changeset 9458 543298b36b28
parent 9331 bb0b744fd1a6
child 9555 fff4b6354b99
permissions -rw-r--r--
This function can be static.
     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     SDL_bool ret = SDL_FALSE;
   452 
   453     if (window->hit_test) {
   454         const SDL_Point point = { xev->xbutton.x, xev->xbutton.y };
   455         const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
   456         switch (rc) {
   457             case SDL_HITTEST_DRAGGABLE: {
   458                     InitiateWindowMove(_this, data, &point);
   459                     ret = SDL_TRUE;
   460                 }
   461                 break;
   462             case SDL_HITTEST_RESIZE_TOPLEFT: {
   463                     InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPLEFT);
   464                     ret = SDL_TRUE;
   465                 }
   466                 break;
   467             case SDL_HITTEST_RESIZE_TOP: {
   468                     InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOP);
   469                     ret = SDL_TRUE;
   470                 }
   471                 break;
   472             case SDL_HITTEST_RESIZE_TOPRIGHT: {
   473                     InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPRIGHT);
   474                     ret = SDL_TRUE;
   475                 }
   476                 break;
   477             case SDL_HITTEST_RESIZE_RIGHT: {
   478                     InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_RIGHT);
   479                     ret = SDL_TRUE;
   480                 }
   481                 break;
   482             case SDL_HITTEST_RESIZE_BOTTOMRIGHT: {
   483                     InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT);
   484                     ret = SDL_TRUE;
   485                 }
   486                 break;
   487             case SDL_HITTEST_RESIZE_BOTTOM: {
   488                     InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOM);
   489                     ret = SDL_TRUE;
   490                 }
   491                 break;
   492             case SDL_HITTEST_RESIZE_BOTTOMLEFT: {
   493                     InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT);
   494                     ret = SDL_TRUE;
   495                 }
   496                 break;
   497             case SDL_HITTEST_RESIZE_LEFT: {
   498                     InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_LEFT);
   499                     ret = SDL_TRUE;
   500                 }
   501                 break;
   502             default:
   503                 break;
   504         }
   505     }
   506 
   507     return ret;
   508 }
   509 
   510 static void
   511 ReconcileKeyboardState(_THIS, const SDL_WindowData *data)
   512 {
   513     SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
   514     Display *display = viddata->display;
   515     char keys[32];
   516     int keycode = 0;
   517 
   518     X11_XQueryKeymap( display, keys );
   519 
   520     while ( keycode < 256 ) {
   521         if ( keys[keycode / 8] & (1 << (keycode % 8)) ) {
   522             SDL_SendKeyboardKey(SDL_PRESSED, viddata->key_layout[keycode]);
   523         } else {
   524             SDL_SendKeyboardKey(SDL_RELEASED, viddata->key_layout[keycode]);
   525         }
   526         keycode++;
   527     }
   528 }
   529 
   530 static void
   531 X11_DispatchEvent(_THIS)
   532 {
   533     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   534     Display *display = videodata->display;
   535     SDL_WindowData *data;
   536     XEvent xevent;
   537     int orig_event_type;
   538     KeyCode orig_keycode;
   539     XClientMessageEvent m;
   540     int i;
   541 
   542     SDL_zero(xevent);           /* valgrind fix. --ryan. */
   543     X11_XNextEvent(display, &xevent);
   544 
   545     /* Save the original keycode for dead keys, which are filtered out by
   546        the XFilterEvent() call below.
   547     */
   548     orig_event_type = xevent.type;
   549     if (orig_event_type == KeyPress || orig_event_type == KeyRelease) {
   550         orig_keycode = xevent.xkey.keycode;
   551     } else {
   552         orig_keycode = 0;
   553     }
   554 
   555     /* filter events catchs XIM events and sends them to the correct handler */
   556     if (X11_XFilterEvent(&xevent, None) == True) {
   557 #if 0
   558         printf("Filtered event type = %d display = %d window = %d\n",
   559                xevent.type, xevent.xany.display, xevent.xany.window);
   560 #endif
   561         if (orig_keycode) {
   562             /* Make sure dead key press/release events are sent */
   563             /* Actually, don't do this because it causes double-delivery
   564                of some keys on Ubuntu 14.04 (bug 2526)
   565             SDL_Scancode scancode = videodata->key_layout[orig_keycode];
   566             if (orig_event_type == KeyPress) {
   567                 SDL_SendKeyboardKey(SDL_PRESSED, scancode);
   568             } else {
   569                 SDL_SendKeyboardKey(SDL_RELEASED, scancode);
   570             }
   571             */
   572         }
   573         return;
   574     }
   575 
   576     /* Send a SDL_SYSWMEVENT if the application wants them */
   577     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   578         SDL_SysWMmsg wmmsg;
   579 
   580         SDL_VERSION(&wmmsg.version);
   581         wmmsg.subsystem = SDL_SYSWM_X11;
   582         wmmsg.msg.x11.event = xevent;
   583         SDL_SendSysWMEvent(&wmmsg);
   584     }
   585 
   586 #if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
   587     if(xevent.type == GenericEvent) {
   588         X11_HandleGenericEvent(videodata,xevent);
   589         return;
   590     }
   591 #endif
   592 
   593 #if 0
   594     printf("type = %d display = %d window = %d\n",
   595            xevent.type, xevent.xany.display, xevent.xany.window);
   596 #endif
   597 
   598     data = NULL;
   599     if (videodata && videodata->windowlist) {
   600         for (i = 0; i < videodata->numwindows; ++i) {
   601             if ((videodata->windowlist[i] != NULL) &&
   602                 (videodata->windowlist[i]->xwindow == xevent.xany.window)) {
   603                 data = videodata->windowlist[i];
   604                 break;
   605             }
   606         }
   607     }
   608     if (!data) {
   609         return;
   610     }
   611 
   612     switch (xevent.type) {
   613 
   614         /* Gaining mouse coverage? */
   615     case EnterNotify:{
   616 #ifdef DEBUG_XEVENTS
   617             printf("window %p: EnterNotify! (%d,%d,%d)\n", data,
   618                    xevent.xcrossing.x,
   619                    xevent.xcrossing.y,
   620                    xevent.xcrossing.mode);
   621             if (xevent.xcrossing.mode == NotifyGrab)
   622                 printf("Mode: NotifyGrab\n");
   623             if (xevent.xcrossing.mode == NotifyUngrab)
   624                 printf("Mode: NotifyUngrab\n");
   625 #endif
   626             SDL_SetMouseFocus(data->window);
   627 
   628             if (!SDL_GetMouse()->relative_mode) {
   629                 SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
   630             }
   631         }
   632         break;
   633         /* Losing mouse coverage? */
   634     case LeaveNotify:{
   635 #ifdef DEBUG_XEVENTS
   636             printf("window %p: LeaveNotify! (%d,%d,%d)\n", data,
   637                    xevent.xcrossing.x,
   638                    xevent.xcrossing.y,
   639                    xevent.xcrossing.mode);
   640             if (xevent.xcrossing.mode == NotifyGrab)
   641                 printf("Mode: NotifyGrab\n");
   642             if (xevent.xcrossing.mode == NotifyUngrab)
   643                 printf("Mode: NotifyUngrab\n");
   644 #endif
   645             if (!SDL_GetMouse()->relative_mode) {
   646                 SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
   647             }
   648 
   649             if (xevent.xcrossing.mode != NotifyGrab &&
   650                 xevent.xcrossing.mode != NotifyUngrab &&
   651                 xevent.xcrossing.detail != NotifyInferior) {
   652                 SDL_SetMouseFocus(NULL);
   653             }
   654         }
   655         break;
   656 
   657         /* Gaining input focus? */
   658     case FocusIn:{
   659             if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
   660                 /* Someone is handling a global hotkey, ignore it */
   661 #ifdef DEBUG_XEVENTS
   662                 printf("window %p: FocusIn (NotifyGrab/NotifyUngrab, ignoring)\n", data);
   663 #endif
   664                 break;
   665             }
   666 
   667             if (xevent.xfocus.detail == NotifyInferior) {
   668 #ifdef DEBUG_XEVENTS
   669                 printf("window %p: FocusIn (NotifierInferior, ignoring)\n", data);
   670 #endif
   671                 break;
   672             }
   673 #ifdef DEBUG_XEVENTS
   674             printf("window %p: FocusIn!\n", data);
   675 #endif
   676             if (data->pending_focus == PENDING_FOCUS_OUT &&
   677                 data->window == SDL_GetKeyboardFocus()) {
   678                 ReconcileKeyboardState(_this, data);
   679             }
   680             if (!videodata->last_mode_change_deadline) /* no recent mode changes */
   681             {
   682                 data->pending_focus = PENDING_FOCUS_NONE;
   683                 data->pending_focus_time = 0;
   684                 X11_DispatchFocusIn(data);
   685             }
   686             else
   687             {
   688                 data->pending_focus = PENDING_FOCUS_IN;
   689                 data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME;
   690             }
   691         }
   692         break;
   693 
   694         /* Losing input focus? */
   695     case FocusOut:{
   696             if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
   697                 /* Someone is handling a global hotkey, ignore it */
   698 #ifdef DEBUG_XEVENTS
   699                 printf("window %p: FocusOut (NotifyGrab/NotifyUngrab, ignoring)\n", data);
   700 #endif
   701                 break;
   702             }
   703             if (xevent.xfocus.detail == NotifyInferior) {
   704                 /* We still have focus if a child gets focus */
   705 #ifdef DEBUG_XEVENTS
   706                 printf("window %p: FocusOut (NotifierInferior, ignoring)\n", data);
   707 #endif
   708                 break;
   709             }
   710 #ifdef DEBUG_XEVENTS
   711             printf("window %p: FocusOut!\n", data);
   712 #endif
   713             if (!videodata->last_mode_change_deadline) /* no recent mode changes */
   714             {
   715                 data->pending_focus = PENDING_FOCUS_NONE;
   716                 data->pending_focus_time = 0;
   717                 X11_DispatchFocusOut(data);
   718             }
   719             else
   720             {
   721                 data->pending_focus = PENDING_FOCUS_OUT;
   722                 data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME;
   723             }
   724         }
   725         break;
   726 
   727         /* Generated upon EnterWindow and FocusIn */
   728     case KeymapNotify:{
   729 #ifdef DEBUG_XEVENTS
   730             printf("window %p: KeymapNotify!\n", data);
   731 #endif
   732             /* FIXME:
   733                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   734              */
   735         }
   736         break;
   737 
   738         /* Has the keyboard layout changed? */
   739     case MappingNotify:{
   740 #ifdef DEBUG_XEVENTS
   741             printf("window %p: MappingNotify!\n", data);
   742 #endif
   743             X11_UpdateKeymap(_this);
   744         }
   745         break;
   746 
   747         /* Key press? */
   748     case KeyPress:{
   749             KeyCode keycode = xevent.xkey.keycode;
   750             KeySym keysym = NoSymbol;
   751             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
   752             Status status = 0;
   753             SDL_bool handled_by_ime = SDL_FALSE;
   754 
   755 #ifdef DEBUG_XEVENTS
   756             printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
   757 #endif
   758 #if 1
   759             if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
   760                 int min_keycode, max_keycode;
   761                 X11_XDisplayKeycodes(display, &min_keycode, &max_keycode);
   762 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
   763                 keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0);
   764 #else
   765                 keysym = XKeycodeToKeysym(display, keycode, 0);
   766 #endif
   767                 fprintf(stderr,
   768                         "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",
   769                         keycode, keycode - min_keycode, keysym,
   770                         X11_XKeysymToString(keysym));
   771             }
   772 #endif
   773             /* */
   774             SDL_zero(text);
   775 #ifdef X_HAVE_UTF8_STRING
   776             if (data->ic) {
   777                 X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   778                                   &keysym, &status);
   779             }
   780 #else
   781             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   782 #endif
   783 #ifdef SDL_USE_IBUS
   784             if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
   785                 if(!(handled_by_ime = SDL_IBus_ProcessKeyEvent(keysym, keycode))){
   786 #endif
   787                     if(*text){
   788                         SDL_SendKeyboardText(text);
   789                     }
   790 #ifdef SDL_USE_IBUS
   791                 }
   792             }
   793 #endif
   794             if (!handled_by_ime) {
   795                 SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
   796             }
   797 
   798         }
   799         break;
   800 
   801         /* Key release? */
   802     case KeyRelease:{
   803             KeyCode keycode = xevent.xkey.keycode;
   804 
   805 #ifdef DEBUG_XEVENTS
   806             printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
   807 #endif
   808             if (X11_KeyRepeat(display, &xevent)) {
   809                 /* We're about to get a repeated key down, ignore the key up */
   810                 break;
   811             }
   812             SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
   813         }
   814         break;
   815 
   816         /* Have we been iconified? */
   817     case UnmapNotify:{
   818 #ifdef DEBUG_XEVENTS
   819             printf("window %p: UnmapNotify!\n", data);
   820 #endif
   821             X11_DispatchUnmapNotify(data);
   822         }
   823         break;
   824 
   825         /* Have we been restored? */
   826     case MapNotify:{
   827 #ifdef DEBUG_XEVENTS
   828             printf("window %p: MapNotify!\n", data);
   829 #endif
   830             X11_DispatchMapNotify(data);
   831         }
   832         break;
   833 
   834         /* Have we been resized or moved? */
   835     case ConfigureNotify:{
   836 #ifdef DEBUG_XEVENTS
   837             printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data,
   838                    xevent.xconfigure.x, xevent.xconfigure.y,
   839                    xevent.xconfigure.width, xevent.xconfigure.height);
   840 #endif
   841             long border_left = 0;
   842             long border_top = 0;
   843             if (data->xwindow) {
   844                 Atom _net_frame_extents = X11_XInternAtom(display, "_NET_FRAME_EXTENTS", 0);
   845                 Atom type;
   846                 int format;
   847                 unsigned long nitems, bytes_after;
   848                 unsigned char *property;
   849                 if (X11_XGetWindowProperty(display, data->xwindow,
   850                         _net_frame_extents, 0, 16, 0,
   851                         XA_CARDINAL, &type, &format,
   852                         &nitems, &bytes_after, &property) == Success) {
   853                     if (type != None && nitems == 4)
   854                     {
   855                         border_left = ((long*)property)[0];
   856                         border_top = ((long*)property)[2];
   857                     }
   858                     X11_XFree(property);
   859                 }
   860             }
   861 
   862             if (xevent.xconfigure.x != data->last_xconfigure.x ||
   863                 xevent.xconfigure.y != data->last_xconfigure.y) {
   864                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
   865                                     xevent.xconfigure.x - border_left,
   866                                     xevent.xconfigure.y - border_top);
   867 #ifdef SDL_USE_IBUS
   868                 if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
   869                     /* Update IBus candidate list position */
   870                     SDL_IBus_UpdateTextRect(NULL);
   871                 }
   872 #endif
   873             }
   874             if (xevent.xconfigure.width != data->last_xconfigure.width ||
   875                 xevent.xconfigure.height != data->last_xconfigure.height) {
   876                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED,
   877                                     xevent.xconfigure.width,
   878                                     xevent.xconfigure.height);
   879             }
   880             data->last_xconfigure = xevent.xconfigure;
   881         }
   882         break;
   883 
   884         /* Have we been requested to quit (or another client message?) */
   885     case ClientMessage:{
   886 
   887             static int xdnd_version=0;
   888 
   889             if (xevent.xclient.message_type == videodata->XdndEnter) {
   890 
   891                 SDL_bool use_list = xevent.xclient.data.l[1] & 1;
   892                 data->xdnd_source = xevent.xclient.data.l[0];
   893                 xdnd_version = ( xevent.xclient.data.l[1] >> 24);
   894 #ifdef DEBUG_XEVENTS
   895                 printf("XID of source window : %ld\n", data->xdnd_source);
   896                 printf("Protocol version to use : %ld\n", xdnd_version);
   897                 printf("More then 3 data types : %ld\n", use_list); 
   898 #endif
   899  
   900                 if (use_list) {
   901                     /* fetch conversion targets */
   902                     SDL_x11Prop p;
   903                     X11_ReadProperty(&p, display, data->xdnd_source, videodata->XdndTypeList);
   904                     /* pick one */
   905                     data->xdnd_req = X11_PickTarget(display, (Atom*)p.data, p.count);
   906                     X11_XFree(p.data);
   907                 } else {
   908                     /* pick from list of three */
   909                     data->xdnd_req = X11_PickTargetFromAtoms(display, xevent.xclient.data.l[2], xevent.xclient.data.l[3], xevent.xclient.data.l[4]);
   910                 }
   911             }
   912             else if (xevent.xclient.message_type == videodata->XdndPosition) {
   913             
   914 #ifdef DEBUG_XEVENTS
   915                 Atom act= videodata->XdndActionCopy;
   916                 if(xdnd_version >= 2) {
   917                     act = xevent.xclient.data.l[4];
   918                 }
   919                 printf("Action requested by user is : %s\n", X11_XGetAtomName(display , act));
   920 #endif
   921                 
   922 
   923                 /* reply with status */
   924                 memset(&m, 0, sizeof(XClientMessageEvent));
   925                 m.type = ClientMessage;
   926                 m.display = xevent.xclient.display;
   927                 m.window = xevent.xclient.data.l[0];
   928                 m.message_type = videodata->XdndStatus;
   929                 m.format=32;
   930                 m.data.l[0] = data->xwindow;
   931                 m.data.l[1] = (data->xdnd_req != None);
   932                 m.data.l[2] = 0; /* specify an empty rectangle */
   933                 m.data.l[3] = 0;
   934                 m.data.l[4] = videodata->XdndActionCopy; /* we only accept copying anyway */
   935 
   936                 X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
   937                 X11_XFlush(display);
   938             }
   939             else if(xevent.xclient.message_type == videodata->XdndDrop) {
   940                 if (data->xdnd_req == None) {
   941                     /* say again - not interested! */
   942                     memset(&m, 0, sizeof(XClientMessageEvent));
   943                     m.type = ClientMessage;
   944                     m.display = xevent.xclient.display;
   945                     m.window = xevent.xclient.data.l[0];
   946                     m.message_type = videodata->XdndFinished;
   947                     m.format=32;
   948                     m.data.l[0] = data->xwindow;
   949                     m.data.l[1] = 0;
   950                     m.data.l[2] = None; /* fail! */
   951                     X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
   952                 } else {
   953                     /* convert */
   954                     if(xdnd_version >= 1) {
   955                         X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, xevent.xclient.data.l[2]);
   956                     } else {
   957                         X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, CurrentTime);
   958                     }
   959                 }
   960             }
   961             else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   962                 (xevent.xclient.format == 32) &&
   963                 (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
   964                 Window root = DefaultRootWindow(display);
   965 
   966 #ifdef DEBUG_XEVENTS
   967                 printf("window %p: _NET_WM_PING\n", data);
   968 #endif
   969                 xevent.xclient.window = root;
   970                 X11_XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
   971                 break;
   972             }
   973 
   974             else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   975                 (xevent.xclient.format == 32) &&
   976                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   977 
   978 #ifdef DEBUG_XEVENTS
   979                 printf("window %p: WM_DELETE_WINDOW\n", data);
   980 #endif
   981                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   982                 break;
   983             }
   984         }
   985         break;
   986 
   987         /* Do we need to refresh ourselves? */
   988     case Expose:{
   989 #ifdef DEBUG_XEVENTS
   990             printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
   991 #endif
   992             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
   993         }
   994         break;
   995 
   996     case MotionNotify:{
   997             SDL_Mouse *mouse = SDL_GetMouse();
   998             if(!mouse->relative_mode || mouse->relative_mode_warp) {
   999 #ifdef DEBUG_MOTION
  1000                 printf("window %p: X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
  1001 #endif
  1002 
  1003                 SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y);
  1004             }
  1005         }
  1006         break;
  1007 
  1008     case ButtonPress:{
  1009             int ticks = 0;
  1010             if (X11_IsWheelEvent(display,&xevent,&ticks)) {
  1011                 SDL_SendMouseWheel(data->window, 0, 0, ticks, SDL_MOUSEWHEEL_NORMAL);
  1012             } else {
  1013                 if(xevent.xbutton.button == Button1) {
  1014                     if (ProcessHitTest(_this, data, &xevent)) {
  1015                         break;  /* don't pass this event on to app. */
  1016                     }
  1017                 }
  1018                 SDL_SendMouseButton(data->window, 0, SDL_PRESSED, xevent.xbutton.button);
  1019             }
  1020         }
  1021         break;
  1022 
  1023     case ButtonRelease:{
  1024             SDL_SendMouseButton(data->window, 0, SDL_RELEASED, xevent.xbutton.button);
  1025         }
  1026         break;
  1027 
  1028     case PropertyNotify:{
  1029 #ifdef DEBUG_XEVENTS
  1030             unsigned char *propdata;
  1031             int status, real_format;
  1032             Atom real_type;
  1033             unsigned long items_read, items_left, i;
  1034 
  1035             char *name = X11_XGetAtomName(display, xevent.xproperty.atom);
  1036             if (name) {
  1037                 printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed");
  1038                 X11_XFree(name);
  1039             }
  1040 
  1041             status = X11_XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata);
  1042             if (status == Success && items_read > 0) {
  1043                 if (real_type == XA_INTEGER) {
  1044                     int *values = (int *)propdata;
  1045 
  1046                     printf("{");
  1047                     for (i = 0; i < items_read; i++) {
  1048                         printf(" %d", values[i]);
  1049                     }
  1050                     printf(" }\n");
  1051                 } else if (real_type == XA_CARDINAL) {
  1052                     if (real_format == 32) {
  1053                         Uint32 *values = (Uint32 *)propdata;
  1054 
  1055                         printf("{");
  1056                         for (i = 0; i < items_read; i++) {
  1057                             printf(" %d", values[i]);
  1058                         }
  1059                         printf(" }\n");
  1060                     } else if (real_format == 16) {
  1061                         Uint16 *values = (Uint16 *)propdata;
  1062 
  1063                         printf("{");
  1064                         for (i = 0; i < items_read; i++) {
  1065                             printf(" %d", values[i]);
  1066                         }
  1067                         printf(" }\n");
  1068                     } else if (real_format == 8) {
  1069                         Uint8 *values = (Uint8 *)propdata;
  1070 
  1071                         printf("{");
  1072                         for (i = 0; i < items_read; i++) {
  1073                             printf(" %d", values[i]);
  1074                         }
  1075                         printf(" }\n");
  1076                     }
  1077                 } else if (real_type == XA_STRING ||
  1078                            real_type == videodata->UTF8_STRING) {
  1079                     printf("{ \"%s\" }\n", propdata);
  1080                 } else if (real_type == XA_ATOM) {
  1081                     Atom *atoms = (Atom *)propdata;
  1082 
  1083                     printf("{");
  1084                     for (i = 0; i < items_read; i++) {
  1085                         char *name = X11_XGetAtomName(display, atoms[i]);
  1086                         if (name) {
  1087                             printf(" %s", name);
  1088                             X11_XFree(name);
  1089                         }
  1090                     }
  1091                     printf(" }\n");
  1092                 } else {
  1093                     char *name = X11_XGetAtomName(display, real_type);
  1094                     printf("Unknown type: %ld (%s)\n", real_type, name ? name : "UNKNOWN");
  1095                     if (name) {
  1096                         X11_XFree(name);
  1097                     }
  1098                 }
  1099             }
  1100             if (status == Success) {
  1101                 X11_XFree(propdata);
  1102             }
  1103 #endif /* DEBUG_XEVENTS */
  1104 
  1105             if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
  1106                 /* Get the new state from the window manager.
  1107                    Compositing window managers can alter visibility of windows
  1108                    without ever mapping / unmapping them, so we handle that here,
  1109                    because they use the NETWM protocol to notify us of changes.
  1110                  */
  1111                 const Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window);
  1112                 const Uint32 changed = flags ^ data->window->flags;
  1113 
  1114                 if ((changed & SDL_WINDOW_HIDDEN) || (changed & SDL_WINDOW_FULLSCREEN)) {
  1115                      if (flags & SDL_WINDOW_HIDDEN) {
  1116                          X11_DispatchUnmapNotify(data);
  1117                      } else {
  1118                          X11_DispatchMapNotify(data);
  1119                     }
  1120                 }
  1121 
  1122                 if (changed & SDL_WINDOW_MAXIMIZED) {
  1123                     if (flags & SDL_WINDOW_MAXIMIZED) {
  1124                         SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
  1125                     } else {
  1126                         SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
  1127                     }
  1128                  }
  1129 
  1130             }
  1131         }
  1132         break;
  1133 
  1134     /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
  1135     case SelectionRequest: {
  1136             XSelectionRequestEvent *req;
  1137             XEvent sevent;
  1138             int seln_format;
  1139             unsigned long nbytes;
  1140             unsigned long overflow;
  1141             unsigned char *seln_data;
  1142 
  1143             req = &xevent.xselectionrequest;
  1144 #ifdef DEBUG_XEVENTS
  1145             printf("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", data,
  1146                 req->requestor, req->target);
  1147 #endif
  1148 
  1149             SDL_zero(sevent);
  1150             sevent.xany.type = SelectionNotify;
  1151             sevent.xselection.selection = req->selection;
  1152             sevent.xselection.target = None;
  1153             sevent.xselection.property = None;
  1154             sevent.xselection.requestor = req->requestor;
  1155             sevent.xselection.time = req->time;
  1156             if (X11_XGetWindowProperty(display, DefaultRootWindow(display),
  1157                     XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
  1158                     &sevent.xselection.target, &seln_format, &nbytes,
  1159                     &overflow, &seln_data) == Success) {
  1160                 Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0);
  1161                 if (sevent.xselection.target == req->target) {
  1162                     X11_XChangeProperty(display, req->requestor, req->property,
  1163                         sevent.xselection.target, seln_format, PropModeReplace,
  1164                         seln_data, nbytes);
  1165                     sevent.xselection.property = req->property;
  1166                 } else if (XA_TARGETS == req->target) {
  1167                     Atom SupportedFormats[] = { sevent.xselection.target, XA_TARGETS };
  1168                     X11_XChangeProperty(display, req->requestor, req->property,
  1169                         XA_ATOM, 32, PropModeReplace,
  1170                         (unsigned char*)SupportedFormats,
  1171                         sizeof(SupportedFormats)/sizeof(*SupportedFormats));
  1172                     sevent.xselection.property = req->property;
  1173                 }
  1174                 X11_XFree(seln_data);
  1175             }
  1176             X11_XSendEvent(display, req->requestor, False, 0, &sevent);
  1177             X11_XSync(display, False);
  1178         }
  1179         break;
  1180 
  1181     case SelectionNotify: {
  1182 #ifdef DEBUG_XEVENTS
  1183             printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
  1184                 xevent.xselection.requestor, xevent.xselection.target);
  1185 #endif
  1186             Atom target = xevent.xselection.target;
  1187             if (target == data->xdnd_req) {
  1188                 /* read data */
  1189                 SDL_x11Prop p;
  1190                 X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY);
  1191 
  1192                 if (p.format == 8) {
  1193                     SDL_bool expect_lf = SDL_FALSE;
  1194                     char *start = NULL;
  1195                     char *scan = (char*)p.data;
  1196                     char *fn;
  1197                     char *uri;
  1198                     int length = 0;
  1199                     while (p.count--) {
  1200                         if (!expect_lf) {
  1201                             if (*scan == 0x0D) {
  1202                                 expect_lf = SDL_TRUE;
  1203                             }
  1204                             if (start == NULL) {
  1205                                 start = scan;
  1206                                 length = 0;
  1207                             }
  1208                             length++;
  1209                         } else {
  1210                             if (*scan == 0x0A && length > 0) {
  1211                                 uri = SDL_malloc(length--);
  1212                                 SDL_memcpy(uri, start, length);
  1213                                 uri[length] = '\0';
  1214                                 fn = X11_URIToLocal(uri);
  1215                                 if (fn) {
  1216                                     SDL_SendDropFile(fn);
  1217                                 }
  1218                                 SDL_free(uri);
  1219                             }
  1220                             expect_lf = SDL_FALSE;
  1221                             start = NULL;
  1222                         }
  1223                         scan++;
  1224                     }
  1225                 }
  1226 
  1227                 X11_XFree(p.data);
  1228 
  1229                 /* send reply */
  1230                 SDL_memset(&m, 0, sizeof(XClientMessageEvent));
  1231                 m.type = ClientMessage;
  1232                 m.display = display;
  1233                 m.window = data->xdnd_source;
  1234                 m.message_type = videodata->XdndFinished;
  1235                 m.format = 32;
  1236                 m.data.l[0] = data->xwindow;
  1237                 m.data.l[1] = 1;
  1238                 m.data.l[2] = videodata->XdndActionCopy;
  1239                 X11_XSendEvent(display, data->xdnd_source, False, NoEventMask, (XEvent*)&m);
  1240 
  1241                 X11_XSync(display, False);
  1242 
  1243             } else {
  1244                 videodata->selection_waiting = SDL_FALSE;
  1245             }
  1246         }
  1247         break;
  1248 
  1249     default:{
  1250 #ifdef DEBUG_XEVENTS
  1251             printf("window %p: Unhandled event %d\n", data, xevent.type);
  1252 #endif
  1253         }
  1254         break;
  1255     }
  1256 }
  1257 
  1258 static void
  1259 X11_HandleFocusChanges(_THIS)
  1260 {
  1261     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1262     int i;
  1263 
  1264     if (videodata && videodata->windowlist) {
  1265         for (i = 0; i < videodata->numwindows; ++i) {
  1266             SDL_WindowData *data = videodata->windowlist[i];
  1267             if (data && data->pending_focus != PENDING_FOCUS_NONE) {
  1268                 Uint32 now = SDL_GetTicks();
  1269                 if (SDL_TICKS_PASSED(now, data->pending_focus_time)) {
  1270                     if ( data->pending_focus == PENDING_FOCUS_IN ) {
  1271                         X11_DispatchFocusIn(data);
  1272                     } else {
  1273                         X11_DispatchFocusOut(data);
  1274                     }
  1275                     data->pending_focus = PENDING_FOCUS_NONE;
  1276                 }
  1277             }
  1278         }
  1279     }
  1280 }
  1281 /* Ack!  X11_XPending() actually performs a blocking read if no events available */
  1282 static int
  1283 X11_Pending(Display * display)
  1284 {
  1285     /* Flush the display connection and look to see if events are queued */
  1286     X11_XFlush(display);
  1287     if (X11_XEventsQueued(display, QueuedAlready)) {
  1288         return (1);
  1289     }
  1290 
  1291     /* More drastic measures are required -- see if X is ready to talk */
  1292     {
  1293         static struct timeval zero_time;        /* static == 0 */
  1294         int x11_fd;
  1295         fd_set fdset;
  1296 
  1297         x11_fd = ConnectionNumber(display);
  1298         FD_ZERO(&fdset);
  1299         FD_SET(x11_fd, &fdset);
  1300         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
  1301             return (X11_XPending(display));
  1302         }
  1303     }
  1304 
  1305     /* Oh well, nothing is ready .. */
  1306     return (0);
  1307 }
  1308 
  1309 void
  1310 X11_PumpEvents(_THIS)
  1311 {
  1312     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  1313 
  1314     if (data->last_mode_change_deadline) {
  1315         if (SDL_TICKS_PASSED(SDL_GetTicks(), data->last_mode_change_deadline)) {
  1316             data->last_mode_change_deadline = 0;  /* assume we're done. */
  1317         }
  1318     }
  1319 
  1320     /* Update activity every 30 seconds to prevent screensaver */
  1321     if (_this->suspend_screensaver) {
  1322         const Uint32 now = SDL_GetTicks();
  1323         if (!data->screensaver_activity ||
  1324             SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) {
  1325             X11_XResetScreenSaver(data->display);
  1326 
  1327 #if SDL_USE_LIBDBUS
  1328             SDL_DBus_ScreensaverTickle();
  1329 #endif
  1330 
  1331             data->screensaver_activity = now;
  1332         }
  1333     }
  1334 
  1335 #ifdef SDL_USE_IBUS
  1336     if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
  1337         SDL_IBus_PumpEvents();
  1338     }
  1339 #endif
  1340 
  1341     /* Keep processing pending events */
  1342     while (X11_Pending(data->display)) {
  1343         X11_DispatchEvent(_this);
  1344     }
  1345 
  1346     /* FIXME: Only need to do this when there are pending focus changes */
  1347     X11_HandleFocusChanges(_this);
  1348 }
  1349 
  1350 
  1351 void
  1352 X11_SuspendScreenSaver(_THIS)
  1353 {
  1354 #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
  1355     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  1356     int dummy;
  1357     int major_version, minor_version;
  1358 #endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */
  1359 
  1360 #if SDL_USE_LIBDBUS
  1361     if (SDL_DBus_ScreensaverInhibit(_this->suspend_screensaver)) {
  1362         return;
  1363     }
  1364 
  1365     if (_this->suspend_screensaver) {
  1366         SDL_DBus_ScreensaverTickle();
  1367     }
  1368 #endif
  1369 
  1370 #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
  1371     if (SDL_X11_HAVE_XSS) {
  1372         /* X11_XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
  1373         if (!X11_XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
  1374             !X11_XScreenSaverQueryVersion(data->display,
  1375                                       &major_version, &minor_version) ||
  1376             major_version < 1 || (major_version == 1 && minor_version < 1)) {
  1377             return;
  1378         }
  1379 
  1380         X11_XScreenSaverSuspend(data->display, _this->suspend_screensaver);
  1381         X11_XResetScreenSaver(data->display);
  1382     }
  1383 #endif
  1384 }
  1385 
  1386 #endif /* SDL_VIDEO_DRIVER_X11 */
  1387 
  1388 /* vi: set ts=4 sw=4 expandtab: */