src/video/x11/SDL_x11events.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Aug 2009 18:39:57 +0000
changeset 3227 458e53d8662c
parent 3195 08747e24a50f
child 3241 08c5964f2a34
permissions -rw-r--r--
Clarified API documentation
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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_syswm.h"
    29 #include "SDL_x11video.h"
    30 #include "../../events/SDL_events_c.h"
    31 #include "../../events/SDL_mouse_c.h"
    32 
    33 static void
    34 X11_DispatchEvent(_THIS)
    35 {
    36     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    37     SDL_WindowData *data;
    38     XEvent xevent;
    39     int i;
    40 
    41     SDL_zero(xevent);           /* valgrind fix. --ryan. */
    42     XNextEvent(videodata->display, &xevent);
    43 
    44     /* filter events catchs XIM events and sends them to the correct
    45        handler */
    46     if (XFilterEvent(&xevent, None) == True) {
    47 #if 0
    48         printf("Filtered event type = %d display = %d window = %d\n",
    49                xevent.type, xevent.xany.display, xevent.xany.window);
    50 #endif
    51         return;
    52     }
    53 
    54     /* Send a SDL_SYSWMEVENT if the application wants them */
    55     if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) {
    56         SDL_SysWMmsg wmmsg;
    57 
    58         SDL_VERSION(&wmmsg.version);
    59         wmmsg.subsystem = SDL_SYSWM_X11;
    60         wmmsg.event.xevent = xevent;
    61         SDL_SendSysWMEvent(&wmmsg);
    62     }
    63 
    64     data = NULL;
    65     if (videodata && videodata->windowlist) {
    66         for (i = 0; i < videodata->numwindows; ++i) {
    67             if ((videodata->windowlist[i] != NULL) &&
    68                 (videodata->windowlist[i]->window == xevent.xany.window)) {
    69                 data = videodata->windowlist[i];
    70                 break;
    71             }
    72         }
    73     }
    74     if (!data) {
    75         return;
    76     }
    77 #if 0
    78     printf("type = %d display = %d window = %d\n",
    79            xevent.type, xevent.xany.display, xevent.xany.window);
    80 #endif
    81     switch (xevent.type) {
    82 
    83         /* Gaining mouse coverage? */
    84     case EnterNotify:{
    85 #ifdef DEBUG_XEVENTS
    86             printf("EnterNotify! (%d,%d,%d)\n", 
    87 	           xevent.xcrossing.x,
    88  	           xevent.xcrossing.y,
    89                    xevent.xcrossing.mode);
    90             if (xevent.xcrossing.mode == NotifyGrab)
    91                 printf("Mode: NotifyGrab\n");
    92             if (xevent.xcrossing.mode == NotifyUngrab)
    93                 printf("Mode: NotifyUngrab\n");
    94 #endif
    95             if ((xevent.xcrossing.mode != NotifyGrab) &&
    96                 (xevent.xcrossing.mode != NotifyUngrab)) {
    97 #if 1
    98                 /* FIXME: Should we reset data for all mice? */
    99 	       for (i = 0; i < SDL_GetNumMice(); ++i) {
   100 		  SDL_Mouse *mouse = SDL_GetMouse(i);
   101 		  SDL_SetMouseFocus(mouse->id, data->windowID);
   102 	       }
   103 #endif
   104             }
   105         }
   106         break;
   107 
   108         /* Losing mouse coverage? */
   109     case LeaveNotify:{
   110 #ifdef DEBUG_XEVENTS
   111             printf("LeaveNotify! (%d,%d,%d)\n", 
   112 	           xevent.xcrossing.x,
   113  	           xevent.xcrossing.y,
   114                    xevent.xcrossing.mode);
   115             if (xevent.xcrossing.mode == NotifyGrab)
   116                 printf("Mode: NotifyGrab\n");
   117             if (xevent.xcrossing.mode == NotifyUngrab)
   118                 printf("Mode: NotifyUngrab\n");
   119 #endif
   120             if ((xevent.xcrossing.mode != NotifyGrab) &&
   121                 (xevent.xcrossing.mode != NotifyUngrab) &&
   122                 (xevent.xcrossing.detail != NotifyInferior)) {
   123 #if 1
   124                 /* FIXME: Should we reset data for all mice? */
   125 	       for (i = 0; i < SDL_GetNumMice(); ++i) {
   126 		  SDL_Mouse *mouse = SDL_GetMouse(i);
   127 		  SDL_SetMouseFocus(mouse->id, 0);
   128 	       }
   129 #endif
   130             }
   131         }
   132         break;
   133 
   134         /* Gaining input focus? */
   135     case FocusIn:{
   136 #ifdef DEBUG_XEVENTS
   137             printf("FocusIn!\n");
   138 #endif
   139             SDL_SetKeyboardFocus(videodata->keyboard, data->windowID);
   140 #ifdef X_HAVE_UTF8_STRING
   141             if (data->ic) {
   142                 XSetICFocus(data->ic);
   143             }
   144 #endif
   145         }
   146         break;
   147 
   148         /* Losing input focus? */
   149     case FocusOut:{
   150 #ifdef DEBUG_XEVENTS
   151             printf("FocusOut!\n");
   152 #endif
   153             SDL_SetKeyboardFocus(videodata->keyboard, 0);
   154 #ifdef X_HAVE_UTF8_STRING
   155             if (data->ic) {
   156                 XUnsetICFocus(data->ic);
   157             }
   158 #endif
   159         }
   160         break;
   161 
   162         /* Generated upon EnterWindow and FocusIn */
   163     case KeymapNotify:{
   164 #ifdef DEBUG_XEVENTS
   165             printf("KeymapNotify!\n");
   166 #endif
   167             /* FIXME:
   168                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   169              */
   170         }
   171         break;
   172 
   173         /* Has the keyboard layout changed? */
   174     case MappingNotify:{
   175 #ifdef DEBUG_XEVENTS
   176             printf("MappingNotify!\n");
   177 #endif
   178             X11_UpdateKeymap(_this);
   179         }
   180         break;
   181 
   182         /* Key press? */
   183     case KeyPress:{
   184             KeyCode keycode = xevent.xkey.keycode;
   185             KeySym keysym = NoSymbol;
   186             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
   187             Status status = 0;
   188 
   189 #ifdef DEBUG_XEVENTS
   190             printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   191 #endif
   192             SDL_SendKeyboardKey(videodata->keyboard, SDL_PRESSED,
   193                                 videodata->key_layout[keycode]);
   194 #if 0
   195             if (videodata->key_layout[keycode] == SDLK_UNKNOWN) {
   196                 int min_keycode, max_keycode;
   197                 XDisplayKeycodes(videodata->display, &min_keycode,
   198                                  &max_keycode);
   199                 keysym = XKeycodeToKeysym(videodata->display, keycode, 0);
   200                 fprintf(stderr,
   201                         "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",
   202                         keycode, keycode - min_keycode, keysym,
   203                         XKeysymToString(keysym));
   204             }
   205 #endif
   206             /* */
   207             SDL_zero(text);
   208 #ifdef X_HAVE_UTF8_STRING
   209             if (data->ic) {
   210                 Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   211                                   &keysym, &status);
   212             }
   213 #else
   214             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   215 #endif
   216             if (*text) {
   217                 SDL_SendKeyboardText(videodata->keyboard, text);
   218             }
   219         }
   220         break;
   221 
   222         /* Key release? */
   223     case KeyRelease:{
   224             KeyCode keycode = xevent.xkey.keycode;
   225 
   226 #ifdef DEBUG_XEVENTS
   227             printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   228 #endif
   229             SDL_SendKeyboardKey(videodata->keyboard, SDL_RELEASED,
   230                                 videodata->key_layout[keycode]);
   231         }
   232         break;
   233 
   234         /* Have we been iconified? */
   235     case UnmapNotify:{
   236 #ifdef DEBUG_XEVENTS
   237             printf("UnmapNotify!\n");
   238 #endif
   239             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   240             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MINIMIZED, 0,
   241                                 0);
   242         }
   243         break;
   244 
   245         /* Have we been restored? */
   246     case MapNotify:{
   247 #ifdef DEBUG_XEVENTS
   248             printf("MapNotify!\n");
   249 #endif
   250             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0);
   251             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESTORED, 0,
   252                                 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->windowID, SDL_WINDOWEVENT_MOVED,
   263                                 xevent.xconfigure.x, xevent.xconfigure.y);
   264             SDL_SendWindowEvent(data->windowID, 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->windowID, SDL_WINDOWEVENT_CLOSE, 0,
   276                                     0);
   277             }
   278         }
   279         break;
   280 
   281         /* Do we need to refresh ourselves? */
   282     case Expose:{
   283 #ifdef DEBUG_XEVENTS
   284             printf("Expose (count = %d)\n", xevent.xexpose.count);
   285 #endif
   286             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_EXPOSED, 0,
   287                                 0);
   288         }
   289         break;
   290 
   291     default:{
   292             for (i = 0; i < SDL_GetNumMice(); ++i) {
   293                 SDL_Mouse *mouse;
   294 #if SDL_VIDEO_DRIVER_X11_XINPUT
   295                 X11_MouseData *data;
   296 #endif
   297 
   298                 mouse = SDL_GetMouse(i);
   299                 if (!mouse->driverdata) {
   300                     switch (xevent.type) {
   301                     case MotionNotify:
   302 #ifdef DEBUG_MOTION
   303                         printf("X11 motion: %d,%d\n", xevent.xmotion.x,
   304                                xevent.xmotion.y);
   305 #endif
   306                         SDL_SendMouseMotion(mouse->id, 0, xevent.xmotion.x,
   307                                             xevent.xmotion.y, 0);
   308                         break;
   309 
   310                     case ButtonPress:
   311                         SDL_SendMouseButton(mouse->id, SDL_PRESSED,
   312                                             xevent.xbutton.button);
   313                         break;
   314 
   315                     case ButtonRelease:
   316                         SDL_SendMouseButton(mouse->id, SDL_RELEASED,
   317                                             xevent.xbutton.button);
   318                         break;
   319                     }
   320                     continue;
   321                 }
   322 #if SDL_VIDEO_DRIVER_X11_XINPUT
   323                 data = (X11_MouseData *) mouse->driverdata;
   324                 if (xevent.type == data->motion) {
   325                     XDeviceMotionEvent *move =
   326                         (XDeviceMotionEvent *) & xevent;
   327 #ifdef DEBUG_MOTION
   328                     printf("X11 motion: %d,%d\n", move->x, move->y);
   329 #endif
   330                     SDL_SendMouseMotion(move->deviceid, 0, move->x, move->y,
   331                                         move->axis_data[2]);
   332                     return;
   333                 }
   334                 if (xevent.type == data->button_pressed) {
   335                     XDeviceButtonPressedEvent *pressed =
   336                         (XDeviceButtonPressedEvent *) & xevent;
   337                     SDL_SendMouseButton(pressed->deviceid, SDL_PRESSED,
   338                                         pressed->button);
   339                     return;
   340                 }
   341                 if (xevent.type == data->button_released) {
   342                     XDeviceButtonReleasedEvent *released =
   343                         (XDeviceButtonReleasedEvent *) & xevent;
   344                     SDL_SendMouseButton(released->deviceid, SDL_RELEASED,
   345                                         released->button);
   346                     return;
   347                 }
   348                 if (xevent.type == data->proximity_in) {
   349                     XProximityNotifyEvent *proximity =
   350                         (XProximityNotifyEvent *) & xevent;
   351                     SDL_SendProximity(proximity->deviceid, proximity->x,
   352                                       proximity->y, SDL_PROXIMITYIN);
   353                     return;
   354                 }
   355                 if (xevent.type == data->proximity_out) {
   356                     XProximityNotifyEvent *proximity =
   357                         (XProximityNotifyEvent *) & xevent;
   358                     SDL_SendProximity(proximity->deviceid, proximity->x,
   359                                       proximity->y, SDL_PROXIMITYOUT);
   360                     return;
   361                 }
   362 #endif
   363             }
   364 #ifdef DEBUG_XEVENTS
   365             printf("Unhandled event %d\n", xevent.type);
   366 #endif
   367         }
   368         break;
   369     }
   370 }
   371 
   372 /* Ack!  XPending() actually performs a blocking read if no events available */
   373 int
   374 X11_Pending(Display * display)
   375 {
   376     /* Flush the display connection and look to see if events are queued */
   377     XFlush(display);
   378     if (XEventsQueued(display, QueuedAlready)) {
   379         return (1);
   380     }
   381 
   382     /* More drastic measures are required -- see if X is ready to talk */
   383     {
   384         static struct timeval zero_time;        /* static == 0 */
   385         int x11_fd;
   386         fd_set fdset;
   387 
   388         x11_fd = ConnectionNumber(display);
   389         FD_ZERO(&fdset);
   390         FD_SET(x11_fd, &fdset);
   391         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   392             return (XPending(display));
   393         }
   394     }
   395 
   396     /* Oh well, nothing is ready .. */
   397     return (0);
   398 }
   399 
   400 void
   401 X11_PumpEvents(_THIS)
   402 {
   403     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   404 
   405     /* Update activity every 30 seconds to prevent screensaver */
   406     if (_this->suspend_screensaver) {
   407         Uint32 now = SDL_GetTicks();
   408         if (!data->screensaver_activity ||
   409             (int) (now - data->screensaver_activity) >= 30000) {
   410             XResetScreenSaver(data->display);
   411             data->screensaver_activity = now;
   412         }
   413     }
   414 
   415     /* Keep processing pending events */
   416     while (X11_Pending(data->display)) {
   417         X11_DispatchEvent(_this);
   418     }
   419 }
   420 
   421 /* This is so wrong it hurts */
   422 #define GNOME_SCREENSAVER_HACK
   423 #ifdef GNOME_SCREENSAVER_HACK
   424 #include <unistd.h>
   425 static pid_t screensaver_inhibit_pid;
   426 static void
   427 gnome_screensaver_disable()
   428 {
   429     screensaver_inhibit_pid = fork();
   430     if (screensaver_inhibit_pid == 0) {
   431         close(0);
   432         close(1);
   433         close(2);
   434         execl("/usr/bin/gnome-screensaver-command",
   435               "gnome-screensaver-command",
   436               "--inhibit",
   437               "--reason",
   438               "GNOME screensaver doesn't respect MIT-SCREEN-SAVER", NULL);
   439         exit(2);
   440     }
   441 }
   442 static void
   443 gnome_screensaver_enable()
   444 {
   445     kill(screensaver_inhibit_pid, 15);
   446 }
   447 #endif
   448 
   449 void
   450 X11_SuspendScreenSaver(_THIS)
   451 {
   452 #if SDL_VIDEO_DRIVER_X11_SCRNSAVER
   453     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   454     int dummy;
   455     int major_version, minor_version;
   456 
   457     if (SDL_X11_HAVE_XSS) {
   458         /* XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
   459         if (!XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
   460             !XScreenSaverQueryVersion(data->display,
   461                                       &major_version, &minor_version) ||
   462             major_version < 1 || (major_version == 1 && minor_version < 1)) {
   463             return;
   464         }
   465 
   466         XScreenSaverSuspend(data->display, _this->suspend_screensaver);
   467         XResetScreenSaver(data->display);
   468     }
   469 #endif
   470 
   471 #ifdef GNOME_SCREENSAVER_HACK
   472     if (_this->suspend_screensaver) {
   473         gnome_screensaver_disable();
   474     } else {
   475         gnome_screensaver_enable();
   476     }
   477 #endif
   478 }
   479 
   480 /* vi: set ts=4 sw=4 expandtab: */