src/video/x11/SDL_x11events.c
author Sam Lantinga
Wed, 07 Nov 2012 08:49:59 -0800
changeset 6660 4fa0723e6874
parent 6659 4016ef96095a
child 6661 cd8befc0a969
permissions -rw-r--r--
Don't lose focus if a child window gains focus
     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             if (xevent.xfocus.detail == NotifyInferior) {
   253 #ifdef DEBUG_XEVENTS
   254                 printf("window %p: FocusIn (NotifierInferior, ignoring)\n", data);
   255 #endif
   256                 break;
   257             }
   258 #ifdef DEBUG_XEVENTS
   259             printf("window %p: FocusIn!\n", data);
   260 #endif
   261             data->pending_focus = PENDING_FOCUS_IN;
   262             data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME;
   263         }
   264         break;
   265 
   266         /* Losing input focus? */
   267     case FocusOut:{
   268             if (xevent.xfocus.detail == NotifyInferior) {
   269                 /* We still have focus if a child gets focus */
   270 #ifdef DEBUG_XEVENTS
   271                 printf("window %p: FocusOut (NotifierInferior, ignoring)\n", data);
   272 #endif
   273                 break;
   274             }
   275 #ifdef DEBUG_XEVENTS
   276             printf("window %p: FocusOut!\n", data);
   277 #endif
   278             data->pending_focus = PENDING_FOCUS_OUT;
   279             data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_OUT_TIME;
   280         }
   281         break;
   282 
   283         /* Generated upon EnterWindow and FocusIn */
   284     case KeymapNotify:{
   285 #ifdef DEBUG_XEVENTS
   286             printf("window %p: KeymapNotify!\n", data);
   287 #endif
   288             /* FIXME:
   289                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   290              */
   291         }
   292         break;
   293 
   294         /* Has the keyboard layout changed? */
   295     case MappingNotify:{
   296 #ifdef DEBUG_XEVENTS
   297             printf("window %p: MappingNotify!\n", data);
   298 #endif
   299             X11_UpdateKeymap(_this);
   300         }
   301         break;
   302 
   303         /* Key press? */
   304     case KeyPress:{
   305             KeyCode keycode = xevent.xkey.keycode;
   306             KeySym keysym = NoSymbol;
   307             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
   308             Status status = 0;
   309 
   310 #ifdef DEBUG_XEVENTS
   311             printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
   312 #endif
   313             SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
   314 #if 1
   315             if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN) {
   316                 int min_keycode, max_keycode;
   317                 XDisplayKeycodes(display, &min_keycode, &max_keycode);
   318 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
   319                 keysym = XkbKeycodeToKeysym(display, keycode, 0, 0);
   320 #else
   321                 keysym = XKeycodeToKeysym(display, keycode, 0);
   322 #endif
   323                 fprintf(stderr,
   324                         "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",
   325                         keycode, keycode - min_keycode, keysym,
   326                         XKeysymToString(keysym));
   327             }
   328 #endif
   329             /* */
   330             SDL_zero(text);
   331 #ifdef X_HAVE_UTF8_STRING
   332             if (data->ic) {
   333                 Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   334                                   &keysym, &status);
   335             }
   336 #else
   337             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   338 #endif
   339             if (*text) {
   340                 SDL_SendKeyboardText(text);
   341             }
   342         }
   343         break;
   344 
   345         /* Key release? */
   346     case KeyRelease:{
   347             KeyCode keycode = xevent.xkey.keycode;
   348 
   349 #ifdef DEBUG_XEVENTS
   350             printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
   351 #endif
   352             if (X11_KeyRepeat(display, &xevent)) {
   353                 /* We're about to get a repeated key down, ignore the key up */
   354                 break;
   355             }
   356             SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
   357         }
   358         break;
   359 
   360         /* Have we been iconified? */
   361     case UnmapNotify:{
   362 #ifdef DEBUG_XEVENTS
   363             printf("window %p: UnmapNotify!\n", data);
   364 #endif
   365             X11_DispatchUnmapNotify(data);
   366         }
   367         break;
   368 
   369         /* Have we been restored? */
   370     case MapNotify:{
   371 #ifdef DEBUG_XEVENTS
   372             printf("window %p: MapNotify!\n", data);
   373 #endif
   374             X11_DispatchMapNotify(data);
   375         }
   376         break;
   377 
   378         /* Have we been resized or moved? */
   379     case ConfigureNotify:{
   380 #ifdef DEBUG_XEVENTS
   381             printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data,
   382                    xevent.xconfigure.x, xevent.xconfigure.y,
   383                    xevent.xconfigure.width, xevent.xconfigure.height);
   384 #endif
   385             if (xevent.xconfigure.x != data->last_xconfigure.x ||
   386                 xevent.xconfigure.y != data->last_xconfigure.y) {
   387                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
   388                                     xevent.xconfigure.x, xevent.xconfigure.y);
   389             }
   390             if (xevent.xconfigure.width != data->last_xconfigure.width ||
   391                 xevent.xconfigure.height != data->last_xconfigure.height) {
   392                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED,
   393                                     xevent.xconfigure.width,
   394                                     xevent.xconfigure.height);
   395             }
   396             data->last_xconfigure = xevent.xconfigure;
   397         }
   398         break;
   399 
   400         /* Have we been requested to quit (or another client message?) */
   401     case ClientMessage:{
   402             if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   403                 (xevent.xclient.format == 32) &&
   404                 (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
   405                 Window root = DefaultRootWindow(display);
   406 
   407 #ifdef DEBUG_XEVENTS
   408                 printf("window %p: _NET_WM_PING\n", data);
   409 #endif
   410                 xevent.xclient.window = root;
   411                 XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
   412                 break;
   413             }
   414 
   415             else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
   416                 (xevent.xclient.format == 32) &&
   417                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   418 
   419 #ifdef DEBUG_XEVENTS
   420                 printf("window %p: WM_DELETE_WINDOW\n", data);
   421 #endif
   422                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   423                 break;
   424             }
   425         }
   426         break;
   427 
   428         /* Do we need to refresh ourselves? */
   429     case Expose:{
   430 #ifdef DEBUG_XEVENTS
   431             printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
   432 #endif
   433             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
   434         }
   435         break;
   436 
   437     case MotionNotify:{
   438             SDL_Mouse *mouse = SDL_GetMouse();  
   439             if(!mouse->relative_mode) {
   440 #ifdef DEBUG_MOTION
   441                 printf("window %p: X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
   442 #endif
   443 
   444                 SDL_SendMouseMotion(data->window, 0, xevent.xmotion.x, xevent.xmotion.y);
   445             }
   446         }
   447         break;
   448 
   449     case ButtonPress:{
   450             int ticks = 0;
   451             if (X11_IsWheelEvent(display,&xevent,&ticks) == SDL_TRUE) {
   452                 SDL_SendMouseWheel(data->window, 0, ticks);
   453             }
   454             else {
   455                 SDL_SendMouseButton(data->window, SDL_PRESSED, xevent.xbutton.button);
   456             }
   457         }
   458         break;
   459 
   460     case ButtonRelease:{
   461             SDL_SendMouseButton(data->window, SDL_RELEASED, xevent.xbutton.button);
   462         }
   463         break;
   464 
   465     case PropertyNotify:{
   466 #ifdef DEBUG_XEVENTS
   467             unsigned char *propdata;
   468             int status, real_format;
   469             Atom real_type;
   470             unsigned long items_read, items_left, i;
   471 
   472             char *name = XGetAtomName(display, xevent.xproperty.atom);
   473             if (name) {
   474                 printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed");
   475                 XFree(name);
   476             }
   477 
   478             status = XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata);
   479             if (status == Success && items_read > 0) {
   480                 if (real_type == XA_INTEGER) {
   481                     int *values = (int *)propdata;
   482 
   483                     printf("{");
   484                     for (i = 0; i < items_read; i++) {
   485                         printf(" %d", values[i]);
   486                     }
   487                     printf(" }\n");
   488                 } else if (real_type == XA_CARDINAL) {
   489                     if (real_format == 32) {
   490                         Uint32 *values = (Uint32 *)propdata;
   491 
   492                         printf("{");
   493                         for (i = 0; i < items_read; i++) {
   494                             printf(" %d", values[i]);
   495                         }
   496                         printf(" }\n");
   497                     } else if (real_format == 16) {
   498                         Uint16 *values = (Uint16 *)propdata;
   499 
   500                         printf("{");
   501                         for (i = 0; i < items_read; i++) {
   502                             printf(" %d", values[i]);
   503                         }
   504                         printf(" }\n");
   505                     } else if (real_format == 8) {
   506                         Uint8 *values = (Uint8 *)propdata;
   507 
   508                         printf("{");
   509                         for (i = 0; i < items_read; i++) {
   510                             printf(" %d", values[i]);
   511                         }
   512                         printf(" }\n");
   513                     }
   514                 } else if (real_type == XA_STRING ||
   515                            real_type == videodata->UTF8_STRING) {
   516                     printf("{ \"%s\" }\n", propdata);
   517                 } else if (real_type == XA_ATOM) {
   518                     Atom *atoms = (Atom *)propdata;
   519 
   520                     printf("{");
   521                     for (i = 0; i < items_read; i++) {
   522                         char *name = XGetAtomName(display, atoms[i]);
   523                         if (name) {
   524                             printf(" %s", name);
   525                             XFree(name);
   526                         }
   527                     }
   528                     printf(" }\n");
   529                 } else {
   530                     char *name = XGetAtomName(display, real_type);
   531                     printf("Unknown type: %ld (%s)\n", real_type, name ? name : "UNKNOWN");
   532                     if (name) {
   533                         XFree(name);
   534                     }
   535                 }
   536             }
   537             if (status == Success) {
   538                 XFree(propdata);
   539             }
   540 #endif /* DEBUG_XEVENTS */
   541 
   542             if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
   543                 /* Get the new state from the window manager.
   544                    Compositing window managers can alter visibility of windows
   545                    without ever mapping / unmapping them, so we handle that here,
   546                    because they use the NETWM protocol to notify us of changes.
   547                  */
   548                 Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window);
   549                 if ((flags^data->window->flags) & SDL_WINDOW_HIDDEN) {
   550                     if (flags & SDL_WINDOW_HIDDEN) {
   551                         X11_DispatchUnmapNotify(data);
   552                     } else {
   553                         X11_DispatchMapNotify(data);
   554                     }
   555                 }
   556             }
   557         }
   558         break;
   559 
   560     /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
   561     case SelectionRequest: {
   562             XSelectionRequestEvent *req;
   563             XEvent sevent;
   564             int seln_format;
   565             unsigned long nbytes;
   566             unsigned long overflow;
   567             unsigned char *seln_data;
   568 
   569             req = &xevent.xselectionrequest;
   570 #ifdef DEBUG_XEVENTS
   571             printf("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", data,
   572                 req->requestor, req->target);
   573 #endif
   574 
   575             SDL_zero(sevent);
   576             sevent.xany.type = SelectionNotify;
   577             sevent.xselection.selection = req->selection;
   578             sevent.xselection.target = None;
   579             sevent.xselection.property = None;
   580             sevent.xselection.requestor = req->requestor;
   581             sevent.xselection.time = req->time;
   582             if (XGetWindowProperty(display, DefaultRootWindow(display),
   583                     XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
   584                     &sevent.xselection.target, &seln_format, &nbytes,
   585                     &overflow, &seln_data) == Success) {
   586                 if (sevent.xselection.target == req->target) {
   587                     XChangeProperty(display, req->requestor, req->property,
   588                         sevent.xselection.target, seln_format, PropModeReplace,
   589                         seln_data, nbytes);
   590                     sevent.xselection.property = req->property;
   591                 }
   592                 XFree(seln_data);
   593             }
   594             XSendEvent(display, req->requestor, False, 0, &sevent);
   595             XSync(display, False);
   596         }
   597         break;
   598 
   599     case SelectionNotify: {
   600 #ifdef DEBUG_XEVENTS
   601             printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
   602                 xevent.xselection.requestor, xevent.xselection.target);
   603 #endif
   604             videodata->selection_waiting = SDL_FALSE;
   605         }
   606         break;
   607 
   608     default:{
   609 #ifdef DEBUG_XEVENTS
   610             printf("window %p: Unhandled event %d\n", data, xevent.type);
   611 #endif
   612         }
   613         break;
   614     }
   615 }
   616 
   617 static void
   618 X11_HandleFocusChanges(_THIS)
   619 {
   620     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   621     int i;
   622 
   623     if (videodata && videodata->windowlist) {
   624         for (i = 0; i < videodata->numwindows; ++i) {
   625             SDL_WindowData *data = videodata->windowlist[i];
   626             if (data && data->pending_focus != PENDING_FOCUS_NONE) {
   627                 Uint32 now = SDL_GetTicks();
   628                 if ( (int)(data->pending_focus_time-now) <= 0 ) {
   629                     if ( data->pending_focus == PENDING_FOCUS_IN ) {
   630                         X11_DispatchFocusIn(data);
   631                     } else {
   632                         X11_DispatchFocusOut(data);
   633                     }
   634                     data->pending_focus = PENDING_FOCUS_NONE;
   635                 }
   636             }
   637         }
   638     }
   639 }
   640 /* Ack!  XPending() actually performs a blocking read if no events available */
   641 static int
   642 X11_Pending(Display * display)
   643 {
   644     /* Flush the display connection and look to see if events are queued */
   645     XFlush(display);
   646     if (XEventsQueued(display, QueuedAlready)) {
   647         return (1);
   648     }
   649 
   650     /* More drastic measures are required -- see if X is ready to talk */
   651     {
   652         static struct timeval zero_time;        /* static == 0 */
   653         int x11_fd;
   654         fd_set fdset;
   655 
   656         x11_fd = ConnectionNumber(display);
   657         FD_ZERO(&fdset);
   658         FD_SET(x11_fd, &fdset);
   659         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   660             return (XPending(display));
   661         }
   662     }
   663 
   664     /* Oh well, nothing is ready .. */
   665     return (0);
   666 }
   667 
   668 
   669 /* !!! FIXME: this should be exposed in a header, or something. */
   670 int SDL_GetNumTouch(void);
   671 
   672 
   673 void
   674 X11_PumpEvents(_THIS)
   675 {
   676     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   677 
   678     /* Update activity every 30 seconds to prevent screensaver */
   679     if (_this->suspend_screensaver) {
   680         Uint32 now = SDL_GetTicks();
   681         if (!data->screensaver_activity ||
   682             (int) (now - data->screensaver_activity) >= 30000) {
   683             XResetScreenSaver(data->display);
   684             data->screensaver_activity = now;
   685         }
   686     }   
   687 
   688     /* Keep processing pending events */
   689     while (X11_Pending(data->display)) {
   690         X11_DispatchEvent(_this);
   691     }
   692 
   693     /* FIXME: Only need to do this when there are pending focus changes */
   694     X11_HandleFocusChanges(_this);
   695 
   696     /*Dont process evtouch events if XInput2 multitouch is supported*/
   697     if(X11_Xinput2IsMultitouchSupported()) {
   698         return;
   699     }
   700 
   701 #ifdef SDL_INPUT_LINUXEV
   702     /* Process Touch events*/
   703     int i = 0,rd;
   704     struct input_event ev[64];
   705     int size = sizeof (struct input_event);
   706 
   707 /* !!! FIXME: clean the tabstops out of here. */
   708     for(i = 0;i < SDL_GetNumTouch();++i) {
   709 	SDL_Touch* touch = SDL_GetTouchIndex(i);
   710 	if(!touch) printf("Touch %i/%i DNE\n",i,SDL_GetNumTouch());
   711 	EventTouchData* data;
   712 	data = (EventTouchData*)(touch->driverdata);
   713 	if(data == NULL) {
   714 	  printf("No driver data\n");
   715 	  continue;
   716 	}
   717 	if(data->eventStream <= 0) 
   718 	    printf("Error: Couldn't open stream\n");
   719 	rd = read(data->eventStream, ev, size * 64);
   720 	if(rd >= size) {
   721 	    for (i = 0; i < rd / sizeof(struct input_event); i++) {
   722 		switch (ev[i].type) {
   723 		case EV_ABS:
   724 		    switch (ev[i].code) {
   725 			case ABS_X:
   726 			    data->x = ev[i].value;
   727 			    break;
   728 			case ABS_Y:
   729 			    data->y = ev[i].value;
   730 			    break;
   731 			case ABS_PRESSURE:
   732 			    data->pressure = ev[i].value;
   733 			    if(data->pressure < 0) data->pressure = 0;
   734 			    break;
   735 			case ABS_MISC:
   736 			    if(ev[i].value == 0)
   737 			        data->up = SDL_TRUE;			    
   738 			    break;
   739 			}
   740 		    break;
   741 		case EV_MSC:
   742 			if(ev[i].code == MSC_SERIAL)
   743 				data->finger = ev[i].value;
   744 			break;
   745 		case EV_KEY:
   746 			if(ev[i].code == BTN_TOUCH)
   747 			    if(ev[i].value == 0)
   748 			        data->up = SDL_TRUE;
   749 			break;
   750 		case EV_SYN:
   751 		  if(!data->down) {
   752 		      data->down = SDL_TRUE;
   753 		      SDL_SendFingerDown(touch->id,data->finger,
   754 		    		  data->down, data->x, data->y,
   755 		    		  data->pressure);
   756 		  }
   757 		  else if(!data->up)
   758 		    SDL_SendTouchMotion(touch->id,data->finger, 
   759 					SDL_FALSE, data->x,data->y,
   760 					data->pressure);
   761 		  else
   762 		  {
   763 		      data->down = SDL_FALSE;
   764 			  SDL_SendFingerDown(touch->id,data->finger,
   765 					  data->down, data->x,data->y,
   766 					  data->pressure);
   767 			  data->x = -1;
   768 			  data->y = -1;
   769 			  data->pressure = -1;
   770 			  data->finger = 0;
   771 			  data->up = SDL_FALSE;
   772 		  }
   773 		  break;		
   774 		}
   775 	    }
   776 	}
   777     }
   778 #endif
   779 }
   780 
   781 /* This is so wrong it hurts */
   782 #define GNOME_SCREENSAVER_HACK
   783 #ifdef GNOME_SCREENSAVER_HACK
   784 #include <unistd.h>
   785 static pid_t screensaver_inhibit_pid;
   786 static void
   787 gnome_screensaver_disable()
   788 {
   789     screensaver_inhibit_pid = fork();
   790     if (screensaver_inhibit_pid == 0) {
   791         close(0);
   792         close(1);
   793         close(2);
   794         execl("/usr/bin/gnome-screensaver-command",
   795               "gnome-screensaver-command",
   796               "--inhibit",
   797               "--reason",
   798               "GNOME screensaver doesn't respect MIT-SCREEN-SAVER", NULL);
   799         exit(2);
   800     }
   801 }
   802 static void
   803 gnome_screensaver_enable()
   804 {
   805     kill(screensaver_inhibit_pid, 15);
   806 }
   807 #endif
   808 
   809 void
   810 X11_SuspendScreenSaver(_THIS)
   811 {
   812 #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
   813     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   814     int dummy;
   815     int major_version, minor_version;
   816 
   817     if (SDL_X11_HAVE_XSS) {
   818         /* XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
   819         if (!XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
   820             !XScreenSaverQueryVersion(data->display,
   821                                       &major_version, &minor_version) ||
   822             major_version < 1 || (major_version == 1 && minor_version < 1)) {
   823             return;
   824         }
   825 
   826         XScreenSaverSuspend(data->display, _this->suspend_screensaver);
   827         XResetScreenSaver(data->display);
   828     }
   829 #endif
   830 
   831 #ifdef GNOME_SCREENSAVER_HACK
   832     if (_this->suspend_screensaver) {
   833         gnome_screensaver_disable();
   834     } else {
   835         gnome_screensaver_enable();
   836     }
   837 #endif
   838 }
   839 
   840 #endif /* SDL_VIDEO_DRIVER_X11 */
   841 
   842 /* vi: set ts=4 sw=4 expandtab: */