src/video/x11/SDL_x11events.c
author Sam Lantinga
Tue, 06 Nov 2012 10:34:47 -0800
changeset 6659 4016ef96095a
parent 6638 3d221da309d3
child 6660 4fa0723e6874
permissions -rw-r--r--
Fixed XBadWindow error when iconified under Unity3D
Apparently the root window changes in this case. We want to send to the root window that is being listened to by the window manager, so this should be okay.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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_config.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_x11video.h"
    33 #include "SDL_x11touch.h"
    34 #include "SDL_x11xinput2.h"
    35 #include "../../events/SDL_events_c.h"
    36 #include "../../events/SDL_mouse_c.h"
    37 #include "../../events/SDL_touch_c.h"
    38 
    39 #include "SDL_timer.h"
    40 #include "SDL_syswm.h"
    41 
    42 #include <stdio.h>
    43 
    44 #ifdef SDL_INPUT_LINUXEV
    45 //Touch Input/event* includes
    46 #include <linux/input.h>
    47 #include <fcntl.h>
    48 #endif
    49 
    50 /*#define DEBUG_XEVENTS*/
    51 
    52 /* Check to see if this is a repeated key.
    53    (idea shamelessly lifted from GII -- thanks guys! :)
    54  */
    55 static SDL_bool X11_KeyRepeat(Display *display, XEvent *event)
    56 {
    57     XEvent peekevent;
    58 
    59     if (XPending(display)) {
    60         XPeekEvent(display, &peekevent);
    61         if ((peekevent.type == KeyPress) &&
    62             (peekevent.xkey.keycode == event->xkey.keycode) &&
    63             ((peekevent.xkey.time-event->xkey.time) < 2)) {
    64             return SDL_TRUE;
    65         }
    66     }
    67     return SDL_FALSE;
    68 }
    69 
    70 static SDL_bool X11_IsWheelEvent(Display * display,XEvent * event,int * ticks)
    71 {
    72     XEvent peekevent;
    73     if (XPending(display)) {
    74         /* according to the xlib docs, no specific mouse wheel events exist.
    75            however, mouse wheel events trigger a button press and a button release
    76            immediately. thus, checking if the same button was released at the same
    77            time as it was pressed, should be an adequate hack to derive a mouse 
    78            wheel event. */
    79         XPeekEvent(display,&peekevent);
    80         if ((peekevent.type           == ButtonRelease) &&
    81             (peekevent.xbutton.button == event->xbutton.button) &&
    82             (peekevent.xbutton.time   == event->xbutton.time)) {
    83 
    84             /* by default, X11 only knows 5 buttons. on most 3 button + wheel mouse,
    85                Button4 maps to wheel up, Button5 maps to wheel down. */
    86             if (event->xbutton.button == Button4) {
    87                 *ticks = 1;
    88             }
    89             else if (event->xbutton.button == Button5) {
    90                 *ticks = -1;
    91             }
    92 
    93             /* remove the following release event, as this is now a wheel event */
    94             XNextEvent(display,&peekevent);
    95             return SDL_TRUE;
    96         }
    97     }
    98     return SDL_FALSE;
    99 }
   100 
   101 
   102 #if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
   103 static void X11_HandleGenericEvent(SDL_VideoData *videodata,XEvent event)
   104 {
   105     XGenericEventCookie *cookie = &event.xcookie;
   106     XGetEventData(videodata->display, cookie);
   107     X11_HandleXinput2Event(videodata,cookie);
   108     XFreeEventData(videodata->display,cookie);
   109 }
   110 #endif /* SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS */
   111 
   112 
   113 static void
   114 X11_DispatchFocusIn(SDL_WindowData *data)
   115 {
   116 #ifdef DEBUG_XEVENTS
   117     printf("window %p: Dispatching FocusIn\n", data);
   118 #endif
   119     SDL_SetKeyboardFocus(data->window);
   120 #ifdef X_HAVE_UTF8_STRING
   121     if (data->ic) {
   122         XSetICFocus(data->ic);
   123     }
   124 #endif
   125 }
   126 
   127 static void
   128 X11_DispatchFocusOut(SDL_WindowData *data)
   129 {
   130 #ifdef DEBUG_XEVENTS
   131     printf("window %p: Dispatching FocusOut\n", data);
   132 #endif
   133     SDL_SetKeyboardFocus(NULL);
   134 #ifdef X_HAVE_UTF8_STRING
   135     if (data->ic) {
   136         XUnsetICFocus(data->ic);
   137     }
   138 #endif
   139 }
   140 
   141 static void
   142 X11_DispatchMapNotify(SDL_WindowData *data)
   143 {
   144     SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   145     SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
   146 }
   147 
   148 static void
   149 X11_DispatchUnmapNotify(SDL_WindowData *data)
   150 {
   151     SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   152     SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   153 }
   154 
   155 static void
   156 X11_DispatchEvent(_THIS)
   157 {
   158     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   159     Display *display = videodata->display;
   160     SDL_WindowData *data;
   161     XEvent xevent;
   162     int i;
   163 
   164     SDL_zero(xevent);           /* valgrind fix. --ryan. */
   165     XNextEvent(display, &xevent);
   166 
   167     /* filter events catchs XIM events and sends them to the correct
   168        handler */
   169     if (XFilterEvent(&xevent, None) == True) {
   170 #if 0
   171         printf("Filtered event type = %d display = %d window = %d\n",
   172                xevent.type, xevent.xany.display, xevent.xany.window);
   173 #endif
   174         return;
   175     }
   176 
   177     /* Send a SDL_SYSWMEVENT if the application wants them */
   178     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   179         SDL_SysWMmsg wmmsg;
   180 
   181         SDL_VERSION(&wmmsg.version);
   182         wmmsg.subsystem = SDL_SYSWM_X11;
   183         wmmsg.msg.x11.event = xevent;
   184         SDL_SendSysWMEvent(&wmmsg);
   185     }
   186 
   187 #if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
   188     if(xevent.type == GenericEvent) {
   189         X11_HandleGenericEvent(videodata,xevent);
   190         return;
   191     }
   192 #endif
   193 
   194 #if 0
   195     printf("type = %d display = %d window = %d\n",
   196            xevent.type, xevent.xany.display, xevent.xany.window);
   197 #endif
   198 
   199     data = NULL;
   200     if (videodata && videodata->windowlist) {
   201         for (i = 0; i < videodata->numwindows; ++i) {
   202             if ((videodata->windowlist[i] != NULL) &&
   203                 (videodata->windowlist[i]->xwindow == xevent.xany.window)) {
   204                 data = videodata->windowlist[i];
   205                 break;
   206             }
   207         }
   208     }
   209     if (!data) {
   210         return;
   211     }
   212 
   213     switch (xevent.type) {
   214 
   215         /* Gaining mouse coverage? */
   216     case EnterNotify:{
   217 #ifdef DEBUG_XEVENTS
   218             printf("window %p: EnterNotify! (%d,%d,%d)\n", data,
   219                    xevent.xcrossing.x,
   220                    xevent.xcrossing.y,
   221                    xevent.xcrossing.mode);
   222             if (xevent.xcrossing.mode == NotifyGrab)
   223                 printf("Mode: NotifyGrab\n");
   224             if (xevent.xcrossing.mode == NotifyUngrab)
   225                 printf("Mode: NotifyUngrab\n");
   226 #endif
   227             SDL_SetMouseFocus(data->window);
   228         }
   229         break;
   230         /* Losing mouse coverage? */
   231     case LeaveNotify:{
   232 #ifdef DEBUG_XEVENTS
   233             printf("window %p: LeaveNotify! (%d,%d,%d)\n", data,
   234                    xevent.xcrossing.x,
   235                    xevent.xcrossing.y,
   236                    xevent.xcrossing.mode);
   237             if (xevent.xcrossing.mode == NotifyGrab)
   238                 printf("Mode: NotifyGrab\n");
   239             if (xevent.xcrossing.mode == NotifyUngrab)
   240                 printf("Mode: NotifyUngrab\n");
   241 #endif
   242             if (xevent.xcrossing.mode != NotifyGrab &&
   243                 xevent.xcrossing.mode != NotifyUngrab &&
   244                 xevent.xcrossing.detail != NotifyInferior) {
   245                 SDL_SetMouseFocus(NULL);
   246             }
   247         }
   248         break;
   249 
   250         /* Gaining input focus? */
   251     case FocusIn:{
   252 #ifdef DEBUG_XEVENTS
   253             printf("window %p: FocusIn!\n", data);
   254 #endif
   255             data->pending_focus = PENDING_FOCUS_IN;
   256             data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME;
   257         }
   258         break;
   259 
   260         /* Losing input focus? */
   261     case FocusOut:{
   262 #ifdef DEBUG_XEVENTS
   263             printf("window %p: FocusOut!\n", data);
   264 #endif
   265             data->pending_focus = PENDING_FOCUS_OUT;
   266             data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_OUT_TIME;
   267         }
   268         break;
   269 
   270         /* Generated upon EnterWindow and FocusIn */
   271     case KeymapNotify:{
   272 #ifdef DEBUG_XEVENTS
   273             printf("window %p: KeymapNotify!\n", data);
   274 #endif
   275             /* FIXME:
   276                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   277              */
   278         }
   279         break;
   280 
   281         /* Has the keyboard layout changed? */
   282     case MappingNotify:{
   283 #ifdef DEBUG_XEVENTS
   284             printf("window %p: MappingNotify!\n", data);
   285 #endif
   286             X11_UpdateKeymap(_this);
   287         }
   288         break;
   289 
   290         /* Key press? */
   291     case KeyPress:{
   292             KeyCode keycode = xevent.xkey.keycode;
   293             KeySym keysym = NoSymbol;
   294             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
   295             Status status = 0;
   296 
   297 #ifdef DEBUG_XEVENTS
   298             printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
   299 #endif
   300             SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
   301 #if 1
   302             if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN) {
   303                 int min_keycode, max_keycode;
   304                 XDisplayKeycodes(display, &min_keycode, &max_keycode);
   305 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
   306                 keysym = XkbKeycodeToKeysym(display, keycode, 0, 0);
   307 #else
   308                 keysym = XKeycodeToKeysym(display, keycode, 0);
   309 #endif
   310                 fprintf(stderr,
   311                         "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",
   312                         keycode, keycode - min_keycode, keysym,
   313                         XKeysymToString(keysym));
   314             }
   315 #endif
   316             /* */
   317             SDL_zero(text);
   318 #ifdef X_HAVE_UTF8_STRING
   319             if (data->ic) {
   320                 Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   321                                   &keysym, &status);
   322             }
   323 #else
   324             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   325 #endif
   326             if (*text) {
   327                 SDL_SendKeyboardText(text);
   328             }
   329         }
   330         break;
   331 
   332         /* Key release? */
   333     case KeyRelease:{
   334             KeyCode keycode = xevent.xkey.keycode;
   335 
   336 #ifdef DEBUG_XEVENTS
   337             printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
   338 #endif
   339             if (X11_KeyRepeat(display, &xevent)) {
   340                 /* We're about to get a repeated key down, ignore the key up */
   341                 break;
   342             }
   343             SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
   344         }
   345         break;
   346 
   347         /* Have we been iconified? */
   348     case UnmapNotify:{
   349 #ifdef DEBUG_XEVENTS
   350             printf("window %p: UnmapNotify!\n", data);
   351 #endif
   352             X11_DispatchUnmapNotify(data);
   353         }
   354         break;
   355 
   356         /* Have we been restored? */
   357     case MapNotify:{
   358 #ifdef DEBUG_XEVENTS
   359             printf("window %p: MapNotify!\n", data);
   360 #endif
   361             X11_DispatchMapNotify(data);
   362         }
   363         break;
   364 
   365         /* Have we been resized or moved? */
   366     case ConfigureNotify:{
   367 #ifdef DEBUG_XEVENTS
   368             printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data,
   369                    xevent.xconfigure.x, xevent.xconfigure.y,
   370                    xevent.xconfigure.width, xevent.xconfigure.height);
   371 #endif
   372             if (xevent.xconfigure.x != data->last_xconfigure.x ||
   373                 xevent.xconfigure.y != data->last_xconfigure.y) {
   374                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
   375                                     xevent.xconfigure.x, xevent.xconfigure.y);
   376             }
   377             if (xevent.xconfigure.width != data->last_xconfigure.width ||
   378                 xevent.xconfigure.height != data->last_xconfigure.height) {
   379                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED,
   380                                     xevent.xconfigure.width,
   381                                     xevent.xconfigure.height);
   382             }
   383             data->last_xconfigure = xevent.xconfigure;
   384         }
   385         break;
   386 
   387         /* Have we been requested to quit (or another client message?) */
   388     case ClientMessage:{
   389             if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   390                 (xevent.xclient.format == 32) &&
   391                 (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
   392                 Window root = DefaultRootWindow(display);
   393 
   394 #ifdef DEBUG_XEVENTS
   395                 printf("window %p: _NET_WM_PING\n", data);
   396 #endif
   397                 xevent.xclient.window = root;
   398                 XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
   399                 break;
   400             }
   401 
   402             else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   403                 (xevent.xclient.format == 32) &&
   404                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   405 
   406 #ifdef DEBUG_XEVENTS
   407                 printf("window %p: WM_DELETE_WINDOW\n", data);
   408 #endif
   409                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   410                 break;
   411             }
   412         }
   413         break;
   414 
   415         /* Do we need to refresh ourselves? */
   416     case Expose:{
   417 #ifdef DEBUG_XEVENTS
   418             printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
   419 #endif
   420             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
   421         }
   422         break;
   423 
   424     case MotionNotify:{
   425             SDL_Mouse *mouse = SDL_GetMouse();  
   426             if(!mouse->relative_mode) {
   427 #ifdef DEBUG_MOTION
   428                 printf("window %p: X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
   429 #endif
   430 
   431                 SDL_SendMouseMotion(data->window, 0, xevent.xmotion.x, xevent.xmotion.y);
   432             }
   433         }
   434         break;
   435 
   436     case ButtonPress:{
   437             int ticks = 0;
   438             if (X11_IsWheelEvent(display,&xevent,&ticks) == SDL_TRUE) {
   439                 SDL_SendMouseWheel(data->window, 0, ticks);
   440             }
   441             else {
   442                 SDL_SendMouseButton(data->window, SDL_PRESSED, xevent.xbutton.button);
   443             }
   444         }
   445         break;
   446 
   447     case ButtonRelease:{
   448             SDL_SendMouseButton(data->window, SDL_RELEASED, xevent.xbutton.button);
   449         }
   450         break;
   451 
   452     case PropertyNotify:{
   453 #ifdef DEBUG_XEVENTS
   454             unsigned char *propdata;
   455             int status, real_format;
   456             Atom real_type;
   457             unsigned long items_read, items_left, i;
   458 
   459             char *name = XGetAtomName(display, xevent.xproperty.atom);
   460             if (name) {
   461                 printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed");
   462                 XFree(name);
   463             }
   464 
   465             status = XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata);
   466             if (status == Success && items_read > 0) {
   467                 if (real_type == XA_INTEGER) {
   468                     int *values = (int *)propdata;
   469 
   470                     printf("{");
   471                     for (i = 0; i < items_read; i++) {
   472                         printf(" %d", values[i]);
   473                     }
   474                     printf(" }\n");
   475                 } else if (real_type == XA_CARDINAL) {
   476                     if (real_format == 32) {
   477                         Uint32 *values = (Uint32 *)propdata;
   478 
   479                         printf("{");
   480                         for (i = 0; i < items_read; i++) {
   481                             printf(" %d", values[i]);
   482                         }
   483                         printf(" }\n");
   484                     } else if (real_format == 16) {
   485                         Uint16 *values = (Uint16 *)propdata;
   486 
   487                         printf("{");
   488                         for (i = 0; i < items_read; i++) {
   489                             printf(" %d", values[i]);
   490                         }
   491                         printf(" }\n");
   492                     } else if (real_format == 8) {
   493                         Uint8 *values = (Uint8 *)propdata;
   494 
   495                         printf("{");
   496                         for (i = 0; i < items_read; i++) {
   497                             printf(" %d", values[i]);
   498                         }
   499                         printf(" }\n");
   500                     }
   501                 } else if (real_type == XA_STRING ||
   502                            real_type == videodata->UTF8_STRING) {
   503                     printf("{ \"%s\" }\n", propdata);
   504                 } else if (real_type == XA_ATOM) {
   505                     Atom *atoms = (Atom *)propdata;
   506 
   507                     printf("{");
   508                     for (i = 0; i < items_read; i++) {
   509                         char *name = XGetAtomName(display, atoms[i]);
   510                         if (name) {
   511                             printf(" %s", name);
   512                             XFree(name);
   513                         }
   514                     }
   515                     printf(" }\n");
   516                 } else {
   517                     char *name = XGetAtomName(display, real_type);
   518                     printf("Unknown type: %ld (%s)\n", real_type, name ? name : "UNKNOWN");
   519                     if (name) {
   520                         XFree(name);
   521                     }
   522                 }
   523             }
   524             if (status == Success) {
   525                 XFree(propdata);
   526             }
   527 #endif /* DEBUG_XEVENTS */
   528 
   529             if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
   530                 /* Get the new state from the window manager.
   531                    Compositing window managers can alter visibility of windows
   532                    without ever mapping / unmapping them, so we handle that here,
   533                    because they use the NETWM protocol to notify us of changes.
   534                  */
   535                 Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window);
   536                 if ((flags^data->window->flags) & SDL_WINDOW_HIDDEN) {
   537                     if (flags & SDL_WINDOW_HIDDEN) {
   538                         X11_DispatchUnmapNotify(data);
   539                     } else {
   540                         X11_DispatchMapNotify(data);
   541                     }
   542                 }
   543             }
   544         }
   545         break;
   546 
   547     /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
   548     case SelectionRequest: {
   549             XSelectionRequestEvent *req;
   550             XEvent sevent;
   551             int seln_format;
   552             unsigned long nbytes;
   553             unsigned long overflow;
   554             unsigned char *seln_data;
   555 
   556             req = &xevent.xselectionrequest;
   557 #ifdef DEBUG_XEVENTS
   558             printf("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", data,
   559                 req->requestor, req->target);
   560 #endif
   561 
   562             SDL_zero(sevent);
   563             sevent.xany.type = SelectionNotify;
   564             sevent.xselection.selection = req->selection;
   565             sevent.xselection.target = None;
   566             sevent.xselection.property = None;
   567             sevent.xselection.requestor = req->requestor;
   568             sevent.xselection.time = req->time;
   569             if (XGetWindowProperty(display, DefaultRootWindow(display),
   570                     XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
   571                     &sevent.xselection.target, &seln_format, &nbytes,
   572                     &overflow, &seln_data) == Success) {
   573                 if (sevent.xselection.target == req->target) {
   574                     XChangeProperty(display, req->requestor, req->property,
   575                         sevent.xselection.target, seln_format, PropModeReplace,
   576                         seln_data, nbytes);
   577                     sevent.xselection.property = req->property;
   578                 }
   579                 XFree(seln_data);
   580             }
   581             XSendEvent(display, req->requestor, False, 0, &sevent);
   582             XSync(display, False);
   583         }
   584         break;
   585 
   586     case SelectionNotify: {
   587 #ifdef DEBUG_XEVENTS
   588             printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
   589                 xevent.xselection.requestor, xevent.xselection.target);
   590 #endif
   591             videodata->selection_waiting = SDL_FALSE;
   592         }
   593         break;
   594 
   595     default:{
   596 #ifdef DEBUG_XEVENTS
   597             printf("window %p: Unhandled event %d\n", data, xevent.type);
   598 #endif
   599         }
   600         break;
   601     }
   602 }
   603 
   604 static void
   605 X11_HandleFocusChanges(_THIS)
   606 {
   607     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   608     int i;
   609 
   610     if (videodata && videodata->windowlist) {
   611         for (i = 0; i < videodata->numwindows; ++i) {
   612             SDL_WindowData *data = videodata->windowlist[i];
   613             if (data && data->pending_focus != PENDING_FOCUS_NONE) {
   614                 Uint32 now = SDL_GetTicks();
   615                 if ( (int)(data->pending_focus_time-now) <= 0 ) {
   616                     if ( data->pending_focus == PENDING_FOCUS_IN ) {
   617                         X11_DispatchFocusIn(data);
   618                     } else {
   619                         X11_DispatchFocusOut(data);
   620                     }
   621                     data->pending_focus = PENDING_FOCUS_NONE;
   622                 }
   623             }
   624         }
   625     }
   626 }
   627 /* Ack!  XPending() actually performs a blocking read if no events available */
   628 static int
   629 X11_Pending(Display * display)
   630 {
   631     /* Flush the display connection and look to see if events are queued */
   632     XFlush(display);
   633     if (XEventsQueued(display, QueuedAlready)) {
   634         return (1);
   635     }
   636 
   637     /* More drastic measures are required -- see if X is ready to talk */
   638     {
   639         static struct timeval zero_time;        /* static == 0 */
   640         int x11_fd;
   641         fd_set fdset;
   642 
   643         x11_fd = ConnectionNumber(display);
   644         FD_ZERO(&fdset);
   645         FD_SET(x11_fd, &fdset);
   646         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   647             return (XPending(display));
   648         }
   649     }
   650 
   651     /* Oh well, nothing is ready .. */
   652     return (0);
   653 }
   654 
   655 
   656 /* !!! FIXME: this should be exposed in a header, or something. */
   657 int SDL_GetNumTouch(void);
   658 
   659 
   660 void
   661 X11_PumpEvents(_THIS)
   662 {
   663     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   664 
   665     /* Update activity every 30 seconds to prevent screensaver */
   666     if (_this->suspend_screensaver) {
   667         Uint32 now = SDL_GetTicks();
   668         if (!data->screensaver_activity ||
   669             (int) (now - data->screensaver_activity) >= 30000) {
   670             XResetScreenSaver(data->display);
   671             data->screensaver_activity = now;
   672         }
   673     }   
   674 
   675     /* Keep processing pending events */
   676     while (X11_Pending(data->display)) {
   677         X11_DispatchEvent(_this);
   678     }
   679 
   680     /* FIXME: Only need to do this when there are pending focus changes */
   681     X11_HandleFocusChanges(_this);
   682 
   683     /*Dont process evtouch events if XInput2 multitouch is supported*/
   684     if(X11_Xinput2IsMultitouchSupported()) {
   685         return;
   686     }
   687 
   688 #ifdef SDL_INPUT_LINUXEV
   689     /* Process Touch events*/
   690     int i = 0,rd;
   691     struct input_event ev[64];
   692     int size = sizeof (struct input_event);
   693 
   694 /* !!! FIXME: clean the tabstops out of here. */
   695     for(i = 0;i < SDL_GetNumTouch();++i) {
   696 	SDL_Touch* touch = SDL_GetTouchIndex(i);
   697 	if(!touch) printf("Touch %i/%i DNE\n",i,SDL_GetNumTouch());
   698 	EventTouchData* data;
   699 	data = (EventTouchData*)(touch->driverdata);
   700 	if(data == NULL) {
   701 	  printf("No driver data\n");
   702 	  continue;
   703 	}
   704 	if(data->eventStream <= 0) 
   705 	    printf("Error: Couldn't open stream\n");
   706 	rd = read(data->eventStream, ev, size * 64);
   707 	if(rd >= size) {
   708 	    for (i = 0; i < rd / sizeof(struct input_event); i++) {
   709 		switch (ev[i].type) {
   710 		case EV_ABS:
   711 		    switch (ev[i].code) {
   712 			case ABS_X:
   713 			    data->x = ev[i].value;
   714 			    break;
   715 			case ABS_Y:
   716 			    data->y = ev[i].value;
   717 			    break;
   718 			case ABS_PRESSURE:
   719 			    data->pressure = ev[i].value;
   720 			    if(data->pressure < 0) data->pressure = 0;
   721 			    break;
   722 			case ABS_MISC:
   723 			    if(ev[i].value == 0)
   724 			        data->up = SDL_TRUE;			    
   725 			    break;
   726 			}
   727 		    break;
   728 		case EV_MSC:
   729 			if(ev[i].code == MSC_SERIAL)
   730 				data->finger = ev[i].value;
   731 			break;
   732 		case EV_KEY:
   733 			if(ev[i].code == BTN_TOUCH)
   734 			    if(ev[i].value == 0)
   735 			        data->up = SDL_TRUE;
   736 			break;
   737 		case EV_SYN:
   738 		  if(!data->down) {
   739 		      data->down = SDL_TRUE;
   740 		      SDL_SendFingerDown(touch->id,data->finger,
   741 		    		  data->down, data->x, data->y,
   742 		    		  data->pressure);
   743 		  }
   744 		  else if(!data->up)
   745 		    SDL_SendTouchMotion(touch->id,data->finger, 
   746 					SDL_FALSE, data->x,data->y,
   747 					data->pressure);
   748 		  else
   749 		  {
   750 		      data->down = SDL_FALSE;
   751 			  SDL_SendFingerDown(touch->id,data->finger,
   752 					  data->down, data->x,data->y,
   753 					  data->pressure);
   754 			  data->x = -1;
   755 			  data->y = -1;
   756 			  data->pressure = -1;
   757 			  data->finger = 0;
   758 			  data->up = SDL_FALSE;
   759 		  }
   760 		  break;		
   761 		}
   762 	    }
   763 	}
   764     }
   765 #endif
   766 }
   767 
   768 /* This is so wrong it hurts */
   769 #define GNOME_SCREENSAVER_HACK
   770 #ifdef GNOME_SCREENSAVER_HACK
   771 #include <unistd.h>
   772 static pid_t screensaver_inhibit_pid;
   773 static void
   774 gnome_screensaver_disable()
   775 {
   776     screensaver_inhibit_pid = fork();
   777     if (screensaver_inhibit_pid == 0) {
   778         close(0);
   779         close(1);
   780         close(2);
   781         execl("/usr/bin/gnome-screensaver-command",
   782               "gnome-screensaver-command",
   783               "--inhibit",
   784               "--reason",
   785               "GNOME screensaver doesn't respect MIT-SCREEN-SAVER", NULL);
   786         exit(2);
   787     }
   788 }
   789 static void
   790 gnome_screensaver_enable()
   791 {
   792     kill(screensaver_inhibit_pid, 15);
   793 }
   794 #endif
   795 
   796 void
   797 X11_SuspendScreenSaver(_THIS)
   798 {
   799 #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
   800     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   801     int dummy;
   802     int major_version, minor_version;
   803 
   804     if (SDL_X11_HAVE_XSS) {
   805         /* XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
   806         if (!XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
   807             !XScreenSaverQueryVersion(data->display,
   808                                       &major_version, &minor_version) ||
   809             major_version < 1 || (major_version == 1 && minor_version < 1)) {
   810             return;
   811         }
   812 
   813         XScreenSaverSuspend(data->display, _this->suspend_screensaver);
   814         XResetScreenSaver(data->display);
   815     }
   816 #endif
   817 
   818 #ifdef GNOME_SCREENSAVER_HACK
   819     if (_this->suspend_screensaver) {
   820         gnome_screensaver_disable();
   821     } else {
   822         gnome_screensaver_enable();
   823     }
   824 #endif
   825 }
   826 
   827 #endif /* SDL_VIDEO_DRIVER_X11 */
   828 
   829 /* vi: set ts=4 sw=4 expandtab: */