src/video/x11/SDL_x11events.c
author Jim Grandpre <jim.tla@gmail.com>
Mon, 31 May 2010 00:24:37 -0400
changeset 4645 0375d020e7e3
parent 4644 fb500b3e1717
child 4646 eea1bf53effa
permissions -rw-r--r--
Auto-detects Wacom touch devices.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include <sys/types.h>
    25 #include <sys/time.h>
    26 #include <unistd.h>
    27 
    28 #include "SDL_x11video.h"
    29 #include "../../events/SDL_events_c.h"
    30 #include "../../events/SDL_mouse_c.h"
    31 #include "../../events/SDL_touch_c.h"
    32 
    33 #include "SDL_syswm.h"
    34 
    35 #include <stdio.h>
    36 
    37 //Touch Input/event* includes
    38 #include <linux/input.h>
    39 #include <fcntl.h>
    40 
    41 static void
    42 X11_DispatchEvent(_THIS)
    43 {
    44     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    45     SDL_WindowData *data;
    46     XEvent xevent;
    47     int i;
    48 
    49     SDL_zero(xevent);           /* valgrind fix. --ryan. */
    50     XNextEvent(videodata->display, &xevent);
    51 
    52     /* filter events catchs XIM events and sends them to the correct
    53        handler */
    54     if (XFilterEvent(&xevent, None) == True) {
    55 #if 0
    56         printf("Filtered event type = %d display = %d window = %d\n",
    57                xevent.type, xevent.xany.display, xevent.xany.window);
    58 #endif
    59         return;
    60     }
    61 
    62     /* Send a SDL_SYSWMEVENT if the application wants them */
    63     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
    64         SDL_SysWMmsg wmmsg;
    65 
    66         SDL_VERSION(&wmmsg.version);
    67         wmmsg.subsystem = SDL_SYSWM_X11;
    68         wmmsg.event.xevent = xevent;
    69         SDL_SendSysWMEvent(&wmmsg);
    70     }
    71 
    72     data = NULL;
    73     if (videodata && videodata->windowlist) {
    74         for (i = 0; i < videodata->numwindows; ++i) {
    75             if ((videodata->windowlist[i] != NULL) &&
    76                 (videodata->windowlist[i]->xwindow == xevent.xany.window)) {
    77                 data = videodata->windowlist[i];
    78                 break;
    79             }
    80         }
    81     }
    82     if (!data) {
    83         return;
    84     }
    85 #if 0
    86     printf("type = %d display = %d window = %d\n",
    87            xevent.type, xevent.xany.display, xevent.xany.window);
    88 #endif
    89     switch (xevent.type) {
    90 
    91         /* Gaining mouse coverage? */
    92     case EnterNotify:{
    93 #ifdef DEBUG_XEVENTS
    94             printf("EnterNotify! (%d,%d,%d)\n", 
    95 	           xevent.xcrossing.x,
    96  	           xevent.xcrossing.y,
    97                    xevent.xcrossing.mode);
    98             if (xevent.xcrossing.mode == NotifyGrab)
    99                 printf("Mode: NotifyGrab\n");
   100             if (xevent.xcrossing.mode == NotifyUngrab)
   101                 printf("Mode: NotifyUngrab\n");
   102 #endif
   103 #if 1
   104             /* FIXME: Should we reset data for all mice? */
   105             for (i = 0; i < SDL_GetNumMice(); ++i) {
   106                 SDL_Mouse *mouse = SDL_GetMouse(i);
   107                 SDL_SetMouseFocus(mouse->id, data->window);
   108             }
   109 #endif
   110         }
   111         break;
   112         /* Losing mouse coverage? */
   113     case LeaveNotify:{
   114 #ifdef DEBUG_XEVENTS
   115             printf("LeaveNotify! (%d,%d,%d)\n", 
   116 	           xevent.xcrossing.x,
   117  	           xevent.xcrossing.y,
   118                    xevent.xcrossing.mode);
   119             if (xevent.xcrossing.mode == NotifyGrab)
   120                 printf("Mode: NotifyGrab\n");
   121             if (xevent.xcrossing.mode == NotifyUngrab)
   122                 printf("Mode: NotifyUngrab\n");
   123 #endif
   124             if (xevent.xcrossing.detail != NotifyInferior) {
   125 #if 1
   126                 /* FIXME: Should we reset data for all mice? */
   127 	        for (i = 0; i < SDL_GetNumMice(); ++i) {
   128 		    SDL_Mouse *mouse = SDL_GetMouse(i);
   129 		    SDL_SetMouseFocus(mouse->id, 0);
   130 	        }
   131 #endif
   132             }
   133         }
   134         break;
   135 
   136         /* Gaining input focus? */
   137     case FocusIn:{
   138 #ifdef DEBUG_XEVENTS
   139             printf("FocusIn!\n");
   140 #endif
   141             SDL_SetKeyboardFocus(videodata->keyboard, data->window);
   142 #ifdef X_HAVE_UTF8_STRING
   143             if (data->ic) {
   144                 XSetICFocus(data->ic);
   145             }
   146 #endif
   147         }
   148         break;
   149 
   150         /* Losing input focus? */
   151     case FocusOut:{
   152 #ifdef DEBUG_XEVENTS
   153             printf("FocusOut!\n");
   154 #endif
   155             SDL_SetKeyboardFocus(videodata->keyboard, 0);
   156 #ifdef X_HAVE_UTF8_STRING
   157             if (data->ic) {
   158                 XUnsetICFocus(data->ic);
   159             }
   160 #endif
   161         }
   162         break;
   163 
   164         /* Generated upon EnterWindow and FocusIn */
   165     case KeymapNotify:{
   166 #ifdef DEBUG_XEVENTS
   167             printf("KeymapNotify!\n");
   168 #endif
   169             /* FIXME:
   170                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   171              */
   172         }
   173         break;
   174 
   175         /* Has the keyboard layout changed? */
   176     case MappingNotify:{
   177 #ifdef DEBUG_XEVENTS
   178             printf("MappingNotify!\n");
   179 #endif
   180             X11_UpdateKeymap(_this);
   181         }
   182         break;
   183 
   184         /* Key press? */
   185     case KeyPress:{
   186             KeyCode keycode = xevent.xkey.keycode;
   187             KeySym keysym = NoSymbol;
   188             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
   189             Status status = 0;
   190 
   191 #ifdef DEBUG_XEVENTS
   192             printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   193 #endif
   194             SDL_SendKeyboardKey(videodata->keyboard, SDL_PRESSED,
   195                                 videodata->key_layout[keycode]);
   196 #if 0
   197             if (videodata->key_layout[keycode] == SDLK_UNKNOWN) {
   198                 int min_keycode, max_keycode;
   199                 XDisplayKeycodes(videodata->display, &min_keycode,
   200                                  &max_keycode);
   201                 keysym = XKeycodeToKeysym(videodata->display, keycode, 0);
   202                 fprintf(stderr,
   203                         "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%X (%s).\n",
   204                         keycode, keycode - min_keycode, keysym,
   205                         XKeysymToString(keysym));
   206             }
   207 #endif
   208             /* */
   209             SDL_zero(text);
   210 #ifdef X_HAVE_UTF8_STRING
   211             if (data->ic) {
   212                 Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   213                                   &keysym, &status);
   214             }
   215 #else
   216             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   217 #endif
   218             if (*text) {
   219                 SDL_SendKeyboardText(videodata->keyboard, text);
   220             }
   221         }
   222         break;
   223 
   224         /* Key release? */
   225     case KeyRelease:{
   226             KeyCode keycode = xevent.xkey.keycode;
   227 
   228 #ifdef DEBUG_XEVENTS
   229             printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   230 #endif
   231             SDL_SendKeyboardKey(videodata->keyboard, SDL_RELEASED,
   232                                 videodata->key_layout[keycode]);
   233         }
   234         break;
   235 
   236         /* Have we been iconified? */
   237     case UnmapNotify:{
   238 #ifdef DEBUG_XEVENTS
   239             printf("UnmapNotify!\n");
   240 #endif
   241             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   242             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   243         }
   244         break;
   245 
   246         /* Have we been restored? */
   247     case MapNotify:{
   248 #ifdef DEBUG_XEVENTS
   249             printf("MapNotify!\n");
   250 #endif
   251             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   252             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
   253         }
   254         break;
   255 
   256         /* Have we been resized or moved? */
   257     case ConfigureNotify:{
   258 #ifdef DEBUG_XEVENTS
   259             printf("ConfigureNotify! (resize: %dx%d)\n",
   260                    xevent.xconfigure.width, xevent.xconfigure.height);
   261 #endif
   262             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
   263                                 xevent.xconfigure.x, xevent.xconfigure.y);
   264             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED,
   265                                 xevent.xconfigure.width,
   266                                 xevent.xconfigure.height);
   267         }
   268         break;
   269 
   270         /* Have we been requested to quit (or another client message?) */
   271     case ClientMessage:{
   272             if ((xevent.xclient.format == 32) &&
   273                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   274 
   275                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   276             }
   277         }
   278         break;
   279 
   280         /* Do we need to refresh ourselves? */
   281     case Expose:{
   282 #ifdef DEBUG_XEVENTS
   283             printf("Expose (count = %d)\n", xevent.xexpose.count);
   284 #endif
   285             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
   286         }
   287         break;
   288 
   289     default:{
   290             for (i = 0; i < SDL_GetNumMice(); ++i) {
   291                 SDL_Mouse *mouse;
   292 #if SDL_VIDEO_DRIVER_X11_XINPUT
   293                 X11_MouseData *data;
   294 #endif
   295 
   296                 mouse = SDL_GetMouse(i);
   297                 if (!mouse->driverdata) {
   298                     switch (xevent.type) {
   299                     case MotionNotify:
   300 #ifdef DEBUG_MOTION
   301                         printf("X11 motion: %d,%d\n", xevent.xmotion.x,
   302                                xevent.xmotion.y);
   303 #endif
   304                         SDL_SendMouseMotion(mouse->id, 0, xevent.xmotion.x,
   305                                             xevent.xmotion.y, 0);
   306                         break;
   307 
   308                     case ButtonPress:
   309                         SDL_SendMouseButton(mouse->id, SDL_PRESSED,
   310                                             xevent.xbutton.button);
   311                         break;
   312 
   313                     case ButtonRelease:
   314                         SDL_SendMouseButton(mouse->id, SDL_RELEASED,
   315                                             xevent.xbutton.button);
   316                         break;
   317                     }
   318                     continue;
   319                 }
   320 #if SDL_VIDEO_DRIVER_X11_XINPUT
   321                 data = (X11_MouseData *) mouse->driverdata;
   322                 if (xevent.type == data->motion) {
   323                     XDeviceMotionEvent *move =
   324                         (XDeviceMotionEvent *) & xevent;
   325 #ifdef DEBUG_MOTION
   326                     printf("X11 motion: %d,%d\n", move->x, move->y);
   327 #endif
   328                     SDL_SendMouseMotion(move->deviceid, 0, move->x, move->y,
   329                                         move->axis_data[2]);
   330                     return;
   331                 }
   332                 if (xevent.type == data->button_pressed) {
   333                     XDeviceButtonPressedEvent *pressed =
   334                         (XDeviceButtonPressedEvent *) & xevent;
   335                     SDL_SendMouseButton(pressed->deviceid, SDL_PRESSED,
   336                                         pressed->button);
   337                     return;
   338                 }
   339                 if (xevent.type == data->button_released) {
   340                     XDeviceButtonReleasedEvent *released =
   341                         (XDeviceButtonReleasedEvent *) & xevent;
   342                     SDL_SendMouseButton(released->deviceid, SDL_RELEASED,
   343                                         released->button);
   344                     return;
   345                 }
   346                 if (xevent.type == data->proximity_in) {
   347                     XProximityNotifyEvent *proximity =
   348                         (XProximityNotifyEvent *) & xevent;
   349                     SDL_SendProximity(proximity->deviceid, proximity->x,
   350                                       proximity->y, SDL_PROXIMITYIN);
   351                     return;
   352                 }
   353                 if (xevent.type == data->proximity_out) {
   354                     XProximityNotifyEvent *proximity =
   355                         (XProximityNotifyEvent *) & xevent;
   356                     SDL_SendProximity(proximity->deviceid, proximity->x,
   357                                       proximity->y, SDL_PROXIMITYOUT);
   358                     return;
   359                 }
   360 #endif
   361             }
   362 #ifdef DEBUG_XEVENTS
   363             printf("Unhandled event %d\n", xevent.type);
   364 #endif
   365         }
   366         break;
   367     }
   368 }
   369 
   370 /* Ack!  XPending() actually performs a blocking read if no events available */
   371 int
   372 X11_Pending(Display * display)
   373 {
   374     /* Flush the display connection and look to see if events are queued */
   375     XFlush(display);
   376     if (XEventsQueued(display, QueuedAlready)) {
   377         return (1);
   378     }
   379 
   380     /* More drastic measures are required -- see if X is ready to talk */
   381     {
   382         static struct timeval zero_time;        /* static == 0 */
   383         int x11_fd;
   384         fd_set fdset;
   385 
   386         x11_fd = ConnectionNumber(display);
   387         FD_ZERO(&fdset);
   388         FD_SET(x11_fd, &fdset);
   389         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   390             return (XPending(display));
   391         }
   392     }
   393 
   394     /* Oh well, nothing is ready .. */
   395     return (0);
   396 }
   397 
   398 void
   399 X11_PumpEvents(_THIS)
   400 {
   401     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   402 
   403     /* Update activity every 30 seconds to prevent screensaver */
   404     if (_this->suspend_screensaver) {
   405         Uint32 now = SDL_GetTicks();
   406         if (!data->screensaver_activity ||
   407             (int) (now - data->screensaver_activity) >= 30000) {
   408             XResetScreenSaver(data->display);
   409             data->screensaver_activity = now;
   410         }
   411     }
   412 
   413     /* Keep processing pending events */
   414     while (X11_Pending(data->display)) {
   415         X11_DispatchEvent(_this);
   416     }
   417 
   418 
   419     /* Process Touch events - TODO When X gets touch support, use that instead*/
   420     int i = 0,rd;
   421     char name[256];
   422     struct input_event ev[64];
   423     int size = sizeof (struct input_event);
   424 
   425     for(i = 0;i < SDL_GetNumTouch();++i) {
   426 	SDL_Touch* touch = SDL_GetTouchIndex(i);
   427 	if(!touch) printf("Touch %i/%i DNE\n",i,SDL_GetNumTouch());
   428 	EventTouchData* data;
   429 	data = (EventTouchData*)(touch->driverdata);
   430 	if(data == NULL) {
   431 	  printf("No driver data\n");
   432 	  continue;
   433 	}
   434 	if(data->eventStream <= 0) 
   435 	    printf("Error: Couldn't open stream\n");
   436 	rd = read(data->eventStream, ev, size * 64);
   437 	//printf("Got %i/%i bytes\n",rd,size);
   438 	if(rd >= size) {
   439 	    for (i = 0; i < rd / sizeof(struct input_event); i++) {
   440 		switch (ev[i].type) {
   441 		case EV_ABS:
   442 		    //printf("Got position x: %i!\n",data->x);
   443 		    switch (ev[i].code) {
   444 			case ABS_X:
   445 			    data->x = ev[i].value;
   446 			    break;
   447 			case ABS_Y:
   448 			    data->y = ev[i].value;
   449 			    break;
   450 			case ABS_PRESSURE:
   451 			    data->pressure = ev[i].value;
   452 			    break;
   453 			case ABS_MISC:
   454 			    data->up = SDL_TRUE;
   455 			    data->finger = ev[i].value;
   456 			    break;
   457 			}
   458 		    break;
   459 		case EV_MSC:
   460 		    if(ev[i].code == MSC_SERIAL)
   461 			data->finger = ev[i].value;
   462 		    break;
   463 		case EV_SYN:
   464   		    printf("Id: %i\n",touch->id); 
   465 		    if(data->x >= 0 || data->y >= 0)
   466 			SDL_SendTouchMotion(touch->id,data->finger, 
   467 					    SDL_FALSE,data->x,data->y,
   468 					    data->pressure);
   469 		    if(data->up) 
   470 			SDL_SendFingerDown(touch->id,data->finger,
   471 					   SDL_FALSE,data->x,data->y,
   472 					   data->pressure);
   473 		    //printf("Synched: %i tx: %i, ty: %i\n",
   474 		    //	   data->finger,data->x,data->y);
   475 		    data->x = -1;
   476 		    data->y = -1;
   477 		    data->pressure = -1;
   478 		    data->finger = 0;
   479 		    data->up = SDL_FALSE;
   480 		    
   481 		    break;		
   482 		}
   483 	    }
   484 	}
   485     }
   486 }
   487 
   488 /* This is so wrong it hurts */
   489 #define GNOME_SCREENSAVER_HACK
   490 #ifdef GNOME_SCREENSAVER_HACK
   491 #include <unistd.h>
   492 static pid_t screensaver_inhibit_pid;
   493 static void
   494 gnome_screensaver_disable()
   495 {
   496     screensaver_inhibit_pid = fork();
   497     if (screensaver_inhibit_pid == 0) {
   498         close(0);
   499         close(1);
   500         close(2);
   501         execl("/usr/bin/gnome-screensaver-command",
   502               "gnome-screensaver-command",
   503               "--inhibit",
   504               "--reason",
   505               "GNOME screensaver doesn't respect MIT-SCREEN-SAVER", NULL);
   506         exit(2);
   507     }
   508 }
   509 static void
   510 gnome_screensaver_enable()
   511 {
   512     kill(screensaver_inhibit_pid, 15);
   513 }
   514 #endif
   515 
   516 void
   517 X11_SuspendScreenSaver(_THIS)
   518 {
   519 #if SDL_VIDEO_DRIVER_X11_SCRNSAVER
   520     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   521     int dummy;
   522     int major_version, minor_version;
   523 
   524     if (SDL_X11_HAVE_XSS) {
   525         /* XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
   526         if (!XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
   527             !XScreenSaverQueryVersion(data->display,
   528                                       &major_version, &minor_version) ||
   529             major_version < 1 || (major_version == 1 && minor_version < 1)) {
   530             return;
   531         }
   532 
   533         XScreenSaverSuspend(data->display, _this->suspend_screensaver);
   534         XResetScreenSaver(data->display);
   535     }
   536 #endif
   537 
   538 #ifdef GNOME_SCREENSAVER_HACK
   539     if (_this->suspend_screensaver) {
   540         gnome_screensaver_disable();
   541     } else {
   542         gnome_screensaver_enable();
   543     }
   544 #endif
   545 }
   546 
   547 /* vi: set ts=4 sw=4 expandtab: */