src/video/x11/SDL_x11events.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 12 Apr 2015 20:59:48 -0400
changeset 9555 fff4b6354b99
parent 9331 bb0b744fd1a6
child 9578 e78393ffcd50
permissions -rw-r--r--
Make X11 and Wayland ProcessHitTest() code less verbose.
     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 #ifdef SDL_USE_IBUS
   759             if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
   760                 if(!(handled_by_ime = SDL_IBus_ProcessKeyEvent(keysym, keycode))){
   761 #endif
   762                     if(*text){
   763                         SDL_SendKeyboardText(text);
   764                     }
   765 #ifdef SDL_USE_IBUS
   766                 }
   767             }
   768 #endif
   769             if (!handled_by_ime) {
   770                 SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
   771             }
   772 
   773         }
   774         break;
   775 
   776         /* Key release? */
   777     case KeyRelease:{
   778             KeyCode keycode = xevent.xkey.keycode;
   779 
   780 #ifdef DEBUG_XEVENTS
   781             printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
   782 #endif
   783             if (X11_KeyRepeat(display, &xevent)) {
   784                 /* We're about to get a repeated key down, ignore the key up */
   785                 break;
   786             }
   787             SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
   788         }
   789         break;
   790 
   791         /* Have we been iconified? */
   792     case UnmapNotify:{
   793 #ifdef DEBUG_XEVENTS
   794             printf("window %p: UnmapNotify!\n", data);
   795 #endif
   796             X11_DispatchUnmapNotify(data);
   797         }
   798         break;
   799 
   800         /* Have we been restored? */
   801     case MapNotify:{
   802 #ifdef DEBUG_XEVENTS
   803             printf("window %p: MapNotify!\n", data);
   804 #endif
   805             X11_DispatchMapNotify(data);
   806         }
   807         break;
   808 
   809         /* Have we been resized or moved? */
   810     case ConfigureNotify:{
   811 #ifdef DEBUG_XEVENTS
   812             printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data,
   813                    xevent.xconfigure.x, xevent.xconfigure.y,
   814                    xevent.xconfigure.width, xevent.xconfigure.height);
   815 #endif
   816             long border_left = 0;
   817             long border_top = 0;
   818             if (data->xwindow) {
   819                 Atom _net_frame_extents = X11_XInternAtom(display, "_NET_FRAME_EXTENTS", 0);
   820                 Atom type;
   821                 int format;
   822                 unsigned long nitems, bytes_after;
   823                 unsigned char *property;
   824                 if (X11_XGetWindowProperty(display, data->xwindow,
   825                         _net_frame_extents, 0, 16, 0,
   826                         XA_CARDINAL, &type, &format,
   827                         &nitems, &bytes_after, &property) == Success) {
   828                     if (type != None && nitems == 4)
   829                     {
   830                         border_left = ((long*)property)[0];
   831                         border_top = ((long*)property)[2];
   832                     }
   833                     X11_XFree(property);
   834                 }
   835             }
   836 
   837             if (xevent.xconfigure.x != data->last_xconfigure.x ||
   838                 xevent.xconfigure.y != data->last_xconfigure.y) {
   839                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
   840                                     xevent.xconfigure.x - border_left,
   841                                     xevent.xconfigure.y - border_top);
   842 #ifdef SDL_USE_IBUS
   843                 if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
   844                     /* Update IBus candidate list position */
   845                     SDL_IBus_UpdateTextRect(NULL);
   846                 }
   847 #endif
   848             }
   849             if (xevent.xconfigure.width != data->last_xconfigure.width ||
   850                 xevent.xconfigure.height != data->last_xconfigure.height) {
   851                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED,
   852                                     xevent.xconfigure.width,
   853                                     xevent.xconfigure.height);
   854             }
   855             data->last_xconfigure = xevent.xconfigure;
   856         }
   857         break;
   858 
   859         /* Have we been requested to quit (or another client message?) */
   860     case ClientMessage:{
   861 
   862             static int xdnd_version=0;
   863 
   864             if (xevent.xclient.message_type == videodata->XdndEnter) {
   865 
   866                 SDL_bool use_list = xevent.xclient.data.l[1] & 1;
   867                 data->xdnd_source = xevent.xclient.data.l[0];
   868                 xdnd_version = ( xevent.xclient.data.l[1] >> 24);
   869 #ifdef DEBUG_XEVENTS
   870                 printf("XID of source window : %ld\n", data->xdnd_source);
   871                 printf("Protocol version to use : %ld\n", xdnd_version);
   872                 printf("More then 3 data types : %ld\n", use_list); 
   873 #endif
   874  
   875                 if (use_list) {
   876                     /* fetch conversion targets */
   877                     SDL_x11Prop p;
   878                     X11_ReadProperty(&p, display, data->xdnd_source, videodata->XdndTypeList);
   879                     /* pick one */
   880                     data->xdnd_req = X11_PickTarget(display, (Atom*)p.data, p.count);
   881                     X11_XFree(p.data);
   882                 } else {
   883                     /* pick from list of three */
   884                     data->xdnd_req = X11_PickTargetFromAtoms(display, xevent.xclient.data.l[2], xevent.xclient.data.l[3], xevent.xclient.data.l[4]);
   885                 }
   886             }
   887             else if (xevent.xclient.message_type == videodata->XdndPosition) {
   888             
   889 #ifdef DEBUG_XEVENTS
   890                 Atom act= videodata->XdndActionCopy;
   891                 if(xdnd_version >= 2) {
   892                     act = xevent.xclient.data.l[4];
   893                 }
   894                 printf("Action requested by user is : %s\n", X11_XGetAtomName(display , act));
   895 #endif
   896                 
   897 
   898                 /* reply with status */
   899                 memset(&m, 0, sizeof(XClientMessageEvent));
   900                 m.type = ClientMessage;
   901                 m.display = xevent.xclient.display;
   902                 m.window = xevent.xclient.data.l[0];
   903                 m.message_type = videodata->XdndStatus;
   904                 m.format=32;
   905                 m.data.l[0] = data->xwindow;
   906                 m.data.l[1] = (data->xdnd_req != None);
   907                 m.data.l[2] = 0; /* specify an empty rectangle */
   908                 m.data.l[3] = 0;
   909                 m.data.l[4] = videodata->XdndActionCopy; /* we only accept copying anyway */
   910 
   911                 X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
   912                 X11_XFlush(display);
   913             }
   914             else if(xevent.xclient.message_type == videodata->XdndDrop) {
   915                 if (data->xdnd_req == None) {
   916                     /* say again - not interested! */
   917                     memset(&m, 0, sizeof(XClientMessageEvent));
   918                     m.type = ClientMessage;
   919                     m.display = xevent.xclient.display;
   920                     m.window = xevent.xclient.data.l[0];
   921                     m.message_type = videodata->XdndFinished;
   922                     m.format=32;
   923                     m.data.l[0] = data->xwindow;
   924                     m.data.l[1] = 0;
   925                     m.data.l[2] = None; /* fail! */
   926                     X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
   927                 } else {
   928                     /* convert */
   929                     if(xdnd_version >= 1) {
   930                         X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, xevent.xclient.data.l[2]);
   931                     } else {
   932                         X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, CurrentTime);
   933                     }
   934                 }
   935             }
   936             else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   937                 (xevent.xclient.format == 32) &&
   938                 (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
   939                 Window root = DefaultRootWindow(display);
   940 
   941 #ifdef DEBUG_XEVENTS
   942                 printf("window %p: _NET_WM_PING\n", data);
   943 #endif
   944                 xevent.xclient.window = root;
   945                 X11_XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
   946                 break;
   947             }
   948 
   949             else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   950                 (xevent.xclient.format == 32) &&
   951                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   952 
   953 #ifdef DEBUG_XEVENTS
   954                 printf("window %p: WM_DELETE_WINDOW\n", data);
   955 #endif
   956                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   957                 break;
   958             }
   959         }
   960         break;
   961 
   962         /* Do we need to refresh ourselves? */
   963     case Expose:{
   964 #ifdef DEBUG_XEVENTS
   965             printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
   966 #endif
   967             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
   968         }
   969         break;
   970 
   971     case MotionNotify:{
   972             SDL_Mouse *mouse = SDL_GetMouse();
   973             if(!mouse->relative_mode || mouse->relative_mode_warp) {
   974 #ifdef DEBUG_MOTION
   975                 printf("window %p: X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
   976 #endif
   977 
   978                 SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y);
   979             }
   980         }
   981         break;
   982 
   983     case ButtonPress:{
   984             int ticks = 0;
   985             if (X11_IsWheelEvent(display,&xevent,&ticks)) {
   986                 SDL_SendMouseWheel(data->window, 0, 0, ticks, SDL_MOUSEWHEEL_NORMAL);
   987             } else {
   988                 if(xevent.xbutton.button == Button1) {
   989                     if (ProcessHitTest(_this, data, &xevent)) {
   990                         break;  /* don't pass this event on to app. */
   991                     }
   992                 }
   993                 SDL_SendMouseButton(data->window, 0, SDL_PRESSED, xevent.xbutton.button);
   994             }
   995         }
   996         break;
   997 
   998     case ButtonRelease:{
   999             SDL_SendMouseButton(data->window, 0, SDL_RELEASED, xevent.xbutton.button);
  1000         }
  1001         break;
  1002 
  1003     case PropertyNotify:{
  1004 #ifdef DEBUG_XEVENTS
  1005             unsigned char *propdata;
  1006             int status, real_format;
  1007             Atom real_type;
  1008             unsigned long items_read, items_left, i;
  1009 
  1010             char *name = X11_XGetAtomName(display, xevent.xproperty.atom);
  1011             if (name) {
  1012                 printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed");
  1013                 X11_XFree(name);
  1014             }
  1015 
  1016             status = X11_XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata);
  1017             if (status == Success && items_read > 0) {
  1018                 if (real_type == XA_INTEGER) {
  1019                     int *values = (int *)propdata;
  1020 
  1021                     printf("{");
  1022                     for (i = 0; i < items_read; i++) {
  1023                         printf(" %d", values[i]);
  1024                     }
  1025                     printf(" }\n");
  1026                 } else if (real_type == XA_CARDINAL) {
  1027                     if (real_format == 32) {
  1028                         Uint32 *values = (Uint32 *)propdata;
  1029 
  1030                         printf("{");
  1031                         for (i = 0; i < items_read; i++) {
  1032                             printf(" %d", values[i]);
  1033                         }
  1034                         printf(" }\n");
  1035                     } else if (real_format == 16) {
  1036                         Uint16 *values = (Uint16 *)propdata;
  1037 
  1038                         printf("{");
  1039                         for (i = 0; i < items_read; i++) {
  1040                             printf(" %d", values[i]);
  1041                         }
  1042                         printf(" }\n");
  1043                     } else if (real_format == 8) {
  1044                         Uint8 *values = (Uint8 *)propdata;
  1045 
  1046                         printf("{");
  1047                         for (i = 0; i < items_read; i++) {
  1048                             printf(" %d", values[i]);
  1049                         }
  1050                         printf(" }\n");
  1051                     }
  1052                 } else if (real_type == XA_STRING ||
  1053                            real_type == videodata->UTF8_STRING) {
  1054                     printf("{ \"%s\" }\n", propdata);
  1055                 } else if (real_type == XA_ATOM) {
  1056                     Atom *atoms = (Atom *)propdata;
  1057 
  1058                     printf("{");
  1059                     for (i = 0; i < items_read; i++) {
  1060                         char *name = X11_XGetAtomName(display, atoms[i]);
  1061                         if (name) {
  1062                             printf(" %s", name);
  1063                             X11_XFree(name);
  1064                         }
  1065                     }
  1066                     printf(" }\n");
  1067                 } else {
  1068                     char *name = X11_XGetAtomName(display, real_type);
  1069                     printf("Unknown type: %ld (%s)\n", real_type, name ? name : "UNKNOWN");
  1070                     if (name) {
  1071                         X11_XFree(name);
  1072                     }
  1073                 }
  1074             }
  1075             if (status == Success) {
  1076                 X11_XFree(propdata);
  1077             }
  1078 #endif /* DEBUG_XEVENTS */
  1079 
  1080             if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
  1081                 /* Get the new state from the window manager.
  1082                    Compositing window managers can alter visibility of windows
  1083                    without ever mapping / unmapping them, so we handle that here,
  1084                    because they use the NETWM protocol to notify us of changes.
  1085                  */
  1086                 const Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window);
  1087                 const Uint32 changed = flags ^ data->window->flags;
  1088 
  1089                 if ((changed & SDL_WINDOW_HIDDEN) || (changed & SDL_WINDOW_FULLSCREEN)) {
  1090                      if (flags & SDL_WINDOW_HIDDEN) {
  1091                          X11_DispatchUnmapNotify(data);
  1092                      } else {
  1093                          X11_DispatchMapNotify(data);
  1094                     }
  1095                 }
  1096 
  1097                 if (changed & SDL_WINDOW_MAXIMIZED) {
  1098                     if (flags & SDL_WINDOW_MAXIMIZED) {
  1099                         SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
  1100                     } else {
  1101                         SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
  1102                     }
  1103                  }
  1104 
  1105             }
  1106         }
  1107         break;
  1108 
  1109     /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
  1110     case SelectionRequest: {
  1111             XSelectionRequestEvent *req;
  1112             XEvent sevent;
  1113             int seln_format;
  1114             unsigned long nbytes;
  1115             unsigned long overflow;
  1116             unsigned char *seln_data;
  1117 
  1118             req = &xevent.xselectionrequest;
  1119 #ifdef DEBUG_XEVENTS
  1120             printf("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", data,
  1121                 req->requestor, req->target);
  1122 #endif
  1123 
  1124             SDL_zero(sevent);
  1125             sevent.xany.type = SelectionNotify;
  1126             sevent.xselection.selection = req->selection;
  1127             sevent.xselection.target = None;
  1128             sevent.xselection.property = None;
  1129             sevent.xselection.requestor = req->requestor;
  1130             sevent.xselection.time = req->time;
  1131             if (X11_XGetWindowProperty(display, DefaultRootWindow(display),
  1132                     XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
  1133                     &sevent.xselection.target, &seln_format, &nbytes,
  1134                     &overflow, &seln_data) == Success) {
  1135                 Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0);
  1136                 if (sevent.xselection.target == req->target) {
  1137                     X11_XChangeProperty(display, req->requestor, req->property,
  1138                         sevent.xselection.target, seln_format, PropModeReplace,
  1139                         seln_data, nbytes);
  1140                     sevent.xselection.property = req->property;
  1141                 } else if (XA_TARGETS == req->target) {
  1142                     Atom SupportedFormats[] = { sevent.xselection.target, XA_TARGETS };
  1143                     X11_XChangeProperty(display, req->requestor, req->property,
  1144                         XA_ATOM, 32, PropModeReplace,
  1145                         (unsigned char*)SupportedFormats,
  1146                         sizeof(SupportedFormats)/sizeof(*SupportedFormats));
  1147                     sevent.xselection.property = req->property;
  1148                 }
  1149                 X11_XFree(seln_data);
  1150             }
  1151             X11_XSendEvent(display, req->requestor, False, 0, &sevent);
  1152             X11_XSync(display, False);
  1153         }
  1154         break;
  1155 
  1156     case SelectionNotify: {
  1157 #ifdef DEBUG_XEVENTS
  1158             printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
  1159                 xevent.xselection.requestor, xevent.xselection.target);
  1160 #endif
  1161             Atom target = xevent.xselection.target;
  1162             if (target == data->xdnd_req) {
  1163                 /* read data */
  1164                 SDL_x11Prop p;
  1165                 X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY);
  1166 
  1167                 if (p.format == 8) {
  1168                     SDL_bool expect_lf = SDL_FALSE;
  1169                     char *start = NULL;
  1170                     char *scan = (char*)p.data;
  1171                     char *fn;
  1172                     char *uri;
  1173                     int length = 0;
  1174                     while (p.count--) {
  1175                         if (!expect_lf) {
  1176                             if (*scan == 0x0D) {
  1177                                 expect_lf = SDL_TRUE;
  1178                             }
  1179                             if (start == NULL) {
  1180                                 start = scan;
  1181                                 length = 0;
  1182                             }
  1183                             length++;
  1184                         } else {
  1185                             if (*scan == 0x0A && length > 0) {
  1186                                 uri = SDL_malloc(length--);
  1187                                 SDL_memcpy(uri, start, length);
  1188                                 uri[length] = '\0';
  1189                                 fn = X11_URIToLocal(uri);
  1190                                 if (fn) {
  1191                                     SDL_SendDropFile(fn);
  1192                                 }
  1193                                 SDL_free(uri);
  1194                             }
  1195                             expect_lf = SDL_FALSE;
  1196                             start = NULL;
  1197                         }
  1198                         scan++;
  1199                     }
  1200                 }
  1201 
  1202                 X11_XFree(p.data);
  1203 
  1204                 /* send reply */
  1205                 SDL_memset(&m, 0, sizeof(XClientMessageEvent));
  1206                 m.type = ClientMessage;
  1207                 m.display = display;
  1208                 m.window = data->xdnd_source;
  1209                 m.message_type = videodata->XdndFinished;
  1210                 m.format = 32;
  1211                 m.data.l[0] = data->xwindow;
  1212                 m.data.l[1] = 1;
  1213                 m.data.l[2] = videodata->XdndActionCopy;
  1214                 X11_XSendEvent(display, data->xdnd_source, False, NoEventMask, (XEvent*)&m);
  1215 
  1216                 X11_XSync(display, False);
  1217 
  1218             } else {
  1219                 videodata->selection_waiting = SDL_FALSE;
  1220             }
  1221         }
  1222         break;
  1223 
  1224     default:{
  1225 #ifdef DEBUG_XEVENTS
  1226             printf("window %p: Unhandled event %d\n", data, xevent.type);
  1227 #endif
  1228         }
  1229         break;
  1230     }
  1231 }
  1232 
  1233 static void
  1234 X11_HandleFocusChanges(_THIS)
  1235 {
  1236     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1237     int i;
  1238 
  1239     if (videodata && videodata->windowlist) {
  1240         for (i = 0; i < videodata->numwindows; ++i) {
  1241             SDL_WindowData *data = videodata->windowlist[i];
  1242             if (data && data->pending_focus != PENDING_FOCUS_NONE) {
  1243                 Uint32 now = SDL_GetTicks();
  1244                 if (SDL_TICKS_PASSED(now, data->pending_focus_time)) {
  1245                     if ( data->pending_focus == PENDING_FOCUS_IN ) {
  1246                         X11_DispatchFocusIn(data);
  1247                     } else {
  1248                         X11_DispatchFocusOut(data);
  1249                     }
  1250                     data->pending_focus = PENDING_FOCUS_NONE;
  1251                 }
  1252             }
  1253         }
  1254     }
  1255 }
  1256 /* Ack!  X11_XPending() actually performs a blocking read if no events available */
  1257 static int
  1258 X11_Pending(Display * display)
  1259 {
  1260     /* Flush the display connection and look to see if events are queued */
  1261     X11_XFlush(display);
  1262     if (X11_XEventsQueued(display, QueuedAlready)) {
  1263         return (1);
  1264     }
  1265 
  1266     /* More drastic measures are required -- see if X is ready to talk */
  1267     {
  1268         static struct timeval zero_time;        /* static == 0 */
  1269         int x11_fd;
  1270         fd_set fdset;
  1271 
  1272         x11_fd = ConnectionNumber(display);
  1273         FD_ZERO(&fdset);
  1274         FD_SET(x11_fd, &fdset);
  1275         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
  1276             return (X11_XPending(display));
  1277         }
  1278     }
  1279 
  1280     /* Oh well, nothing is ready .. */
  1281     return (0);
  1282 }
  1283 
  1284 void
  1285 X11_PumpEvents(_THIS)
  1286 {
  1287     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  1288 
  1289     if (data->last_mode_change_deadline) {
  1290         if (SDL_TICKS_PASSED(SDL_GetTicks(), data->last_mode_change_deadline)) {
  1291             data->last_mode_change_deadline = 0;  /* assume we're done. */
  1292         }
  1293     }
  1294 
  1295     /* Update activity every 30 seconds to prevent screensaver */
  1296     if (_this->suspend_screensaver) {
  1297         const Uint32 now = SDL_GetTicks();
  1298         if (!data->screensaver_activity ||
  1299             SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) {
  1300             X11_XResetScreenSaver(data->display);
  1301 
  1302 #if SDL_USE_LIBDBUS
  1303             SDL_DBus_ScreensaverTickle();
  1304 #endif
  1305 
  1306             data->screensaver_activity = now;
  1307         }
  1308     }
  1309 
  1310 #ifdef SDL_USE_IBUS
  1311     if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
  1312         SDL_IBus_PumpEvents();
  1313     }
  1314 #endif
  1315 
  1316     /* Keep processing pending events */
  1317     while (X11_Pending(data->display)) {
  1318         X11_DispatchEvent(_this);
  1319     }
  1320 
  1321     /* FIXME: Only need to do this when there are pending focus changes */
  1322     X11_HandleFocusChanges(_this);
  1323 }
  1324 
  1325 
  1326 void
  1327 X11_SuspendScreenSaver(_THIS)
  1328 {
  1329 #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
  1330     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  1331     int dummy;
  1332     int major_version, minor_version;
  1333 #endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */
  1334 
  1335 #if SDL_USE_LIBDBUS
  1336     if (SDL_DBus_ScreensaverInhibit(_this->suspend_screensaver)) {
  1337         return;
  1338     }
  1339 
  1340     if (_this->suspend_screensaver) {
  1341         SDL_DBus_ScreensaverTickle();
  1342     }
  1343 #endif
  1344 
  1345 #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
  1346     if (SDL_X11_HAVE_XSS) {
  1347         /* X11_XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
  1348         if (!X11_XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
  1349             !X11_XScreenSaverQueryVersion(data->display,
  1350                                       &major_version, &minor_version) ||
  1351             major_version < 1 || (major_version == 1 && minor_version < 1)) {
  1352             return;
  1353         }
  1354 
  1355         X11_XScreenSaverSuspend(data->display, _this->suspend_screensaver);
  1356         X11_XResetScreenSaver(data->display);
  1357     }
  1358 #endif
  1359 }
  1360 
  1361 #endif /* SDL_VIDEO_DRIVER_X11 */
  1362 
  1363 /* vi: set ts=4 sw=4 expandtab: */