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