src/video/x11/SDL_x11events.c
author jimtla
Thu, 22 Jul 2010 08:12:28 +0400
changeset 4669 62e6a6e9720b
parent 4661 03dcb795c583
child 4681 5378f2d0754f
permissions -rw-r--r--
Fixed x11 compile bugs.
     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 <signal.h>
    27 #include <unistd.h>
    28 #include <limits.h>	/* For INT_MAX */
    29 
    30 #include "SDL_x11video.h"
    31 #include "../../events/SDL_events_c.h"
    32 #include "../../events/SDL_mouse_c.h"
    33 #include "../../events/SDL_touch_c.h"
    34 
    35 #include "SDL_timer.h"
    36 #include "SDL_syswm.h"
    37 
    38 #include <stdio.h>
    39 
    40 #ifdef HAVE_LINUX_INPUT_H
    41 //Touch Input/event* includes
    42 #include <linux/input.h>
    43 #include <fcntl.h>
    44 #endif
    45 /*#define DEBUG_XEVENTS*/
    46 
    47 static void
    48 X11_DispatchEvent(_THIS)
    49 {
    50     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    51     SDL_WindowData *data;
    52     XEvent xevent;
    53     int i;
    54 
    55     SDL_zero(xevent);           /* valgrind fix. --ryan. */
    56     XNextEvent(videodata->display, &xevent);
    57 
    58     /* filter events catchs XIM events and sends them to the correct
    59        handler */
    60     if (XFilterEvent(&xevent, None) == True) {
    61 #if 0
    62         printf("Filtered event type = %d display = %d window = %d\n",
    63                xevent.type, xevent.xany.display, xevent.xany.window);
    64 #endif
    65         return;
    66     }
    67 
    68     /* Send a SDL_SYSWMEVENT if the application wants them */
    69     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
    70         SDL_SysWMmsg wmmsg;
    71 
    72         SDL_VERSION(&wmmsg.version);
    73         wmmsg.subsystem = SDL_SYSWM_X11;
    74         wmmsg.event.xevent = xevent;
    75         SDL_SendSysWMEvent(&wmmsg);
    76     }
    77 
    78     data = NULL;
    79     if (videodata && videodata->windowlist) {
    80         for (i = 0; i < videodata->numwindows; ++i) {
    81             if ((videodata->windowlist[i] != NULL) &&
    82                 (videodata->windowlist[i]->xwindow == xevent.xany.window)) {
    83                 data = videodata->windowlist[i];
    84                 break;
    85             }
    86         }
    87     }
    88     if (!data) {
    89         return;
    90     }
    91 #if 0
    92     printf("type = %d display = %d window = %d\n",
    93            xevent.type, xevent.xany.display, xevent.xany.window);
    94 #endif
    95     switch (xevent.type) {
    96 
    97         /* Gaining mouse coverage? */
    98     case EnterNotify:{
    99 #ifdef DEBUG_XEVENTS
   100             printf("EnterNotify! (%d,%d,%d)\n", 
   101 	           xevent.xcrossing.x,
   102  	           xevent.xcrossing.y,
   103                    xevent.xcrossing.mode);
   104             if (xevent.xcrossing.mode == NotifyGrab)
   105                 printf("Mode: NotifyGrab\n");
   106             if (xevent.xcrossing.mode == NotifyUngrab)
   107                 printf("Mode: NotifyUngrab\n");
   108 #endif
   109             SDL_SetMouseFocus(data->window);
   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                 SDL_SetMouseFocus(NULL);
   126             }
   127         }
   128         break;
   129 
   130         /* Gaining input focus? */
   131     case FocusIn:{
   132 #ifdef DEBUG_XEVENTS
   133             printf("FocusIn!\n");
   134 #endif
   135             SDL_SetKeyboardFocus(data->window);
   136 #ifdef X_HAVE_UTF8_STRING
   137             if (data->ic) {
   138                 XSetICFocus(data->ic);
   139             }
   140 #endif
   141         }
   142         break;
   143 
   144         /* Losing input focus? */
   145     case FocusOut:{
   146 #ifdef DEBUG_XEVENTS
   147             printf("FocusOut!\n");
   148 #endif
   149             SDL_SetKeyboardFocus(NULL);
   150 #ifdef X_HAVE_UTF8_STRING
   151             if (data->ic) {
   152                 XUnsetICFocus(data->ic);
   153             }
   154 #endif
   155         }
   156         break;
   157 
   158         /* Generated upon EnterWindow and FocusIn */
   159     case KeymapNotify:{
   160 #ifdef DEBUG_XEVENTS
   161             printf("KeymapNotify!\n");
   162 #endif
   163             /* FIXME:
   164                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   165              */
   166         }
   167         break;
   168 
   169         /* Has the keyboard layout changed? */
   170     case MappingNotify:{
   171 #ifdef DEBUG_XEVENTS
   172             printf("MappingNotify!\n");
   173 #endif
   174             X11_UpdateKeymap(_this);
   175         }
   176         break;
   177 
   178         /* Key press? */
   179     case KeyPress:{
   180             KeyCode keycode = xevent.xkey.keycode;
   181             KeySym keysym = NoSymbol;
   182             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
   183             Status status = 0;
   184 
   185 #ifdef DEBUG_XEVENTS
   186             printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   187 #endif
   188             SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
   189 #if 0
   190             if (videodata->key_layout[keycode] == SDLK_UNKNOWN) {
   191                 int min_keycode, max_keycode;
   192                 XDisplayKeycodes(videodata->display, &min_keycode,
   193                                  &max_keycode);
   194                 keysym = XKeycodeToKeysym(videodata->display, keycode, 0);
   195                 fprintf(stderr,
   196                         "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",
   197                         keycode, keycode - min_keycode, keysym,
   198                         XKeysymToString(keysym));
   199             }
   200 #endif
   201             /* */
   202             SDL_zero(text);
   203 #ifdef X_HAVE_UTF8_STRING
   204             if (data->ic) {
   205                 Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   206                                   &keysym, &status);
   207             }
   208 #else
   209             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   210 #endif
   211             if (*text) {
   212                 SDL_SendKeyboardText(text);
   213             }
   214         }
   215         break;
   216 
   217         /* Key release? */
   218     case KeyRelease:{
   219             KeyCode keycode = xevent.xkey.keycode;
   220 
   221 #ifdef DEBUG_XEVENTS
   222             printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   223 #endif
   224             SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
   225         }
   226         break;
   227 
   228         /* Have we been iconified? */
   229     case UnmapNotify:{
   230 #ifdef DEBUG_XEVENTS
   231             printf("UnmapNotify!\n");
   232 #endif
   233             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   234             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   235         }
   236         break;
   237 
   238         /* Have we been restored? */
   239     case MapNotify:{
   240 #ifdef DEBUG_XEVENTS
   241             printf("MapNotify!\n");
   242 #endif
   243             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   244             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
   245         }
   246         break;
   247 
   248         /* Have we been resized or moved? */
   249     case ConfigureNotify:{
   250 #ifdef DEBUG_XEVENTS
   251             printf("ConfigureNotify! (resize: %dx%d)\n",
   252                    xevent.xconfigure.width, xevent.xconfigure.height);
   253 #endif
   254             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
   255                                 xevent.xconfigure.x, xevent.xconfigure.y);
   256             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED,
   257                                 xevent.xconfigure.width,
   258                                 xevent.xconfigure.height);
   259         }
   260         break;
   261 
   262         /* Have we been requested to quit (or another client message?) */
   263     case ClientMessage:{
   264             if ((xevent.xclient.format == 32) &&
   265                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   266 
   267                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   268             }
   269         }
   270         break;
   271 
   272         /* Do we need to refresh ourselves? */
   273     case Expose:{
   274 #ifdef DEBUG_XEVENTS
   275             printf("Expose (count = %d)\n", xevent.xexpose.count);
   276 #endif
   277             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
   278         }
   279         break;
   280 
   281     case MotionNotify:{
   282 #ifdef DEBUG_MOTION
   283             printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
   284 #endif
   285             SDL_SendMouseMotion(data->window, 0, xevent.xmotion.x, xevent.xmotion.y);
   286         }
   287         break;
   288 
   289     case ButtonPress:{
   290             SDL_SendMouseButton(data->window, SDL_PRESSED, xevent.xbutton.button);
   291         }
   292         break;
   293 
   294     case ButtonRelease:{
   295             SDL_SendMouseButton(data->window, SDL_RELEASED, xevent.xbutton.button);
   296         }
   297         break;
   298 
   299     /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
   300     case SelectionRequest: {
   301             Display *display = videodata->display;
   302             XSelectionRequestEvent *req;
   303             XEvent sevent;
   304             int seln_format;
   305             unsigned long nbytes;
   306             unsigned long overflow;
   307             unsigned char *seln_data;
   308 
   309             req = &xevent.xselectionrequest;
   310 #ifdef DEBUG_XEVENTS
   311             printf("SelectionRequest (requestor = %ld, target = %ld)\n",
   312                 req->requestor, req->target);
   313 #endif
   314 
   315             sevent.xselection.type = SelectionNotify;
   316             sevent.xselection.display = req->display;
   317             sevent.xselection.selection = req->selection;
   318             sevent.xselection.target = None;
   319             sevent.xselection.property = None;
   320             sevent.xselection.requestor = req->requestor;
   321             sevent.xselection.time = req->time;
   322             if (XGetWindowProperty(display, DefaultRootWindow(display),
   323                     XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
   324                     &sevent.xselection.target, &seln_format, &nbytes,
   325                     &overflow, &seln_data) == Success) {
   326                 if (sevent.xselection.target == req->target) {
   327                     XChangeProperty(display, req->requestor, req->property,
   328                         sevent.xselection.target, seln_format, PropModeReplace,
   329                         seln_data, nbytes);
   330                     sevent.xselection.property = req->property;
   331                 }
   332                 XFree(seln_data);
   333             }
   334             XSendEvent(display, req->requestor, False, 0, &sevent);
   335             XSync(display, False);
   336         }
   337         break;
   338 
   339     case SelectionNotify: {
   340 #ifdef DEBUG_XEVENTS
   341             printf("SelectionNotify (requestor = %ld, target = %ld)\n",
   342                 xevent.xselection.requestor, xevent.xselection.target);
   343 #endif
   344             videodata->selection_waiting = SDL_FALSE;
   345         }
   346         break;
   347 
   348     default:{
   349 #ifdef DEBUG_XEVENTS
   350             printf("Unhandled event %d\n", xevent.type);
   351 #endif
   352         }
   353         break;
   354     }
   355 }
   356 
   357 /* Ack!  XPending() actually performs a blocking read if no events available */
   358 static int
   359 X11_Pending(Display * display)
   360 {
   361     /* Flush the display connection and look to see if events are queued */
   362     XFlush(display);
   363     if (XEventsQueued(display, QueuedAlready)) {
   364         return (1);
   365     }
   366 
   367     /* More drastic measures are required -- see if X is ready to talk */
   368     {
   369         static struct timeval zero_time;        /* static == 0 */
   370         int x11_fd;
   371         fd_set fdset;
   372 
   373         x11_fd = ConnectionNumber(display);
   374         FD_ZERO(&fdset);
   375         FD_SET(x11_fd, &fdset);
   376         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   377             return (XPending(display));
   378         }
   379     }
   380 
   381     /* Oh well, nothing is ready .. */
   382     return (0);
   383 }
   384 
   385 void
   386 X11_PumpEvents(_THIS)
   387 {
   388     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   389 
   390     /* Update activity every 30 seconds to prevent screensaver */
   391     if (_this->suspend_screensaver) {
   392         Uint32 now = SDL_GetTicks();
   393         if (!data->screensaver_activity ||
   394             (int) (now - data->screensaver_activity) >= 30000) {
   395             XResetScreenSaver(data->display);
   396             data->screensaver_activity = now;
   397         }
   398     }
   399 
   400     /* Keep processing pending events */
   401     while (X11_Pending(data->display)) {
   402         X11_DispatchEvent(_this);
   403     }
   404 
   405 #ifdef HAVE_LINUX_INPUT_H
   406     /* Process Touch events - TODO When X gets touch support, use that instead*/
   407     int i = 0,rd;
   408     char name[256];
   409     struct input_event ev[64];
   410     int size = sizeof (struct input_event);
   411 
   412     for(i = 0;i < SDL_GetNumTouch();++i) {
   413 	SDL_Touch* touch = SDL_GetTouchIndex(i);
   414 	if(!touch) printf("Touch %i/%i DNE\n",i,SDL_GetNumTouch());
   415 	EventTouchData* data;
   416 	data = (EventTouchData*)(touch->driverdata);
   417 	if(data == NULL) {
   418 	  printf("No driver data\n");
   419 	  continue;
   420 	}
   421 	if(data->eventStream <= 0) 
   422 	    printf("Error: Couldn't open stream\n");
   423 	rd = read(data->eventStream, ev, size * 64);
   424 	//printf("Got %i/%i bytes\n",rd,size);
   425 	if(rd >= size) {
   426 	    for (i = 0; i < rd / sizeof(struct input_event); i++) {
   427 		switch (ev[i].type) {
   428 		case EV_ABS:
   429 		    //printf("Got position x: %i!\n",data->x);
   430 		    switch (ev[i].code) {
   431 			case ABS_X:
   432 			    data->x = ev[i].value;
   433 			    break;
   434 			case ABS_Y:
   435 			    data->y = ev[i].value;
   436 			    break;
   437 			case ABS_PRESSURE:
   438 			    data->pressure = ev[i].value;
   439 			    if(data->pressure < 0) data->pressure = 0;
   440 			    break;
   441 			case ABS_MISC:
   442 			    data->up = SDL_TRUE;
   443 			    data->finger = ev[i].value;
   444 			    break;
   445 			}
   446 		    break;
   447 		case EV_MSC:
   448 		    if(ev[i].code == MSC_SERIAL)
   449 			data->finger = ev[i].value;
   450 		    break;
   451 		case EV_SYN:
   452 		  //printf("Id: %i\n",touch->id); 
   453 		  if(data->up) {
   454 		      SDL_SendFingerDown(touch->id,data->finger,
   455 			  	       SDL_FALSE,data->x,data->y,
   456 				       data->pressure);
   457 		  }
   458 		  else if(data->x >= 0 || data->y >= 0)
   459 		      SDL_SendTouchMotion(touch->id,data->finger, 
   460 					SDL_FALSE,data->x,data->y,
   461 					    data->pressure);
   462 		  
   463 		    //printf("Synched: %i tx: %i, ty: %i\n",
   464 		    //	   data->finger,data->x,data->y);
   465 		    data->x = -1;
   466 		    data->y = -1;
   467 		    data->pressure = -1;
   468 		    data->finger = 0;
   469 		    data->up = SDL_FALSE;
   470 		    
   471 		    break;		
   472 		}
   473 	    }
   474 	}
   475     }
   476 #endif
   477 }
   478 
   479 /* This is so wrong it hurts */
   480 #define GNOME_SCREENSAVER_HACK
   481 #ifdef GNOME_SCREENSAVER_HACK
   482 #include <unistd.h>
   483 static pid_t screensaver_inhibit_pid;
   484 static void
   485 gnome_screensaver_disable()
   486 {
   487     screensaver_inhibit_pid = fork();
   488     if (screensaver_inhibit_pid == 0) {
   489         close(0);
   490         close(1);
   491         close(2);
   492         execl("/usr/bin/gnome-screensaver-command",
   493               "gnome-screensaver-command",
   494               "--inhibit",
   495               "--reason",
   496               "GNOME screensaver doesn't respect MIT-SCREEN-SAVER", NULL);
   497         exit(2);
   498     }
   499 }
   500 static void
   501 gnome_screensaver_enable()
   502 {
   503     kill(screensaver_inhibit_pid, 15);
   504 }
   505 #endif
   506 
   507 void
   508 X11_SuspendScreenSaver(_THIS)
   509 {
   510 #if SDL_VIDEO_DRIVER_X11_SCRNSAVER
   511     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   512     int dummy;
   513     int major_version, minor_version;
   514 
   515     if (SDL_X11_HAVE_XSS) {
   516         /* XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
   517         if (!XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
   518             !XScreenSaverQueryVersion(data->display,
   519                                       &major_version, &minor_version) ||
   520             major_version < 1 || (major_version == 1 && minor_version < 1)) {
   521             return;
   522         }
   523 
   524         XScreenSaverSuspend(data->display, _this->suspend_screensaver);
   525         XResetScreenSaver(data->display);
   526     }
   527 #endif
   528 
   529 #ifdef GNOME_SCREENSAVER_HACK
   530     if (_this->suspend_screensaver) {
   531         gnome_screensaver_disable();
   532     } else {
   533         gnome_screensaver_enable();
   534     }
   535 #endif
   536 }
   537 
   538 /* vi: set ts=4 sw=4 expandtab: */