src/video/x11/SDL_x11events.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 15 Dec 2009 08:11:06 +0000
changeset 3565 f43c8f688f77
parent 3322 d9dd6cbba4c0
child 3685 64ce267332c6
permissions -rw-r--r--
Fixed bug #906

Added better error reporting for OpenGL context creation failing.
     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_x11video.h"
    29 #include "../../events/SDL_events_c.h"
    30 #include "../../events/SDL_mouse_c.h"
    31 
    32 #include "SDL_syswm.h"
    33 
    34 static void
    35 X11_DispatchEvent(_THIS)
    36 {
    37     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    38     SDL_WindowData *data;
    39     XEvent xevent;
    40     int i;
    41 
    42     SDL_zero(xevent);           /* valgrind fix. --ryan. */
    43     XNextEvent(videodata->display, &xevent);
    44 
    45     /* filter events catchs XIM events and sends them to the correct
    46        handler */
    47     if (XFilterEvent(&xevent, None) == True) {
    48 #if 0
    49         printf("Filtered event type = %d display = %d window = %d\n",
    50                xevent.type, xevent.xany.display, xevent.xany.window);
    51 #endif
    52         return;
    53     }
    54 
    55     /* Send a SDL_SYSWMEVENT if the application wants them */
    56     if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) {
    57         SDL_SysWMmsg wmmsg;
    58 
    59         SDL_VERSION(&wmmsg.version);
    60         wmmsg.subsystem = SDL_SYSWM_X11;
    61         wmmsg.event.xevent = xevent;
    62         SDL_SendSysWMEvent(&wmmsg);
    63     }
    64 
    65     data = NULL;
    66     if (videodata && videodata->windowlist) {
    67         for (i = 0; i < videodata->numwindows; ++i) {
    68             if ((videodata->windowlist[i] != NULL) &&
    69                 (videodata->windowlist[i]->window == xevent.xany.window)) {
    70                 data = videodata->windowlist[i];
    71                 break;
    72             }
    73         }
    74     }
    75     if (!data) {
    76         return;
    77     }
    78 #if 0
    79     printf("type = %d display = %d window = %d\n",
    80            xevent.type, xevent.xany.display, xevent.xany.window);
    81 #endif
    82     switch (xevent.type) {
    83 
    84         /* Gaining mouse coverage? */
    85     case EnterNotify:{
    86 #ifdef DEBUG_XEVENTS
    87             printf("EnterNotify! (%d,%d,%d)\n", 
    88 	           xevent.xcrossing.x,
    89  	           xevent.xcrossing.y,
    90                    xevent.xcrossing.mode);
    91             if (xevent.xcrossing.mode == NotifyGrab)
    92                 printf("Mode: NotifyGrab\n");
    93             if (xevent.xcrossing.mode == NotifyUngrab)
    94                 printf("Mode: NotifyUngrab\n");
    95 #endif
    96 #if 1
    97             /* FIXME: Should we reset data for all mice? */
    98             for (i = 0; i < SDL_GetNumMice(); ++i) {
    99                 SDL_Mouse *mouse = SDL_GetMouse(i);
   100                 SDL_SetMouseFocus(mouse->id, data->windowID);
   101             }
   102 #endif
   103         }
   104         break;
   105 
   106         /* Losing mouse coverage? */
   107     case LeaveNotify:{
   108 #ifdef DEBUG_XEVENTS
   109             printf("LeaveNotify! (%d,%d,%d)\n", 
   110 	           xevent.xcrossing.x,
   111  	           xevent.xcrossing.y,
   112                    xevent.xcrossing.mode);
   113             if (xevent.xcrossing.mode == NotifyGrab)
   114                 printf("Mode: NotifyGrab\n");
   115             if (xevent.xcrossing.mode == NotifyUngrab)
   116                 printf("Mode: NotifyUngrab\n");
   117 #endif
   118             if (xevent.xcrossing.detail != NotifyInferior) {
   119 #if 1
   120                 /* FIXME: Should we reset data for all mice? */
   121 	        for (i = 0; i < SDL_GetNumMice(); ++i) {
   122 		    SDL_Mouse *mouse = SDL_GetMouse(i);
   123 		    SDL_SetMouseFocus(mouse->id, 0);
   124 	        }
   125 #endif
   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(videodata->keyboard, data->windowID);
   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(videodata->keyboard, 0);
   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(videodata->keyboard, SDL_PRESSED,
   189                                 videodata->key_layout[keycode]);
   190 #if 0
   191             if (videodata->key_layout[keycode] == SDLK_UNKNOWN) {
   192                 int min_keycode, max_keycode;
   193                 XDisplayKeycodes(videodata->display, &min_keycode,
   194                                  &max_keycode);
   195                 keysym = XKeycodeToKeysym(videodata->display, keycode, 0);
   196                 fprintf(stderr,
   197                         "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",
   198                         keycode, keycode - min_keycode, keysym,
   199                         XKeysymToString(keysym));
   200             }
   201 #endif
   202             /* */
   203             SDL_zero(text);
   204 #ifdef X_HAVE_UTF8_STRING
   205             if (data->ic) {
   206                 Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   207                                   &keysym, &status);
   208             }
   209 #else
   210             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   211 #endif
   212             if (*text) {
   213                 SDL_SendKeyboardText(videodata->keyboard, text);
   214             }
   215         }
   216         break;
   217 
   218         /* Key release? */
   219     case KeyRelease:{
   220             KeyCode keycode = xevent.xkey.keycode;
   221 
   222 #ifdef DEBUG_XEVENTS
   223             printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   224 #endif
   225             SDL_SendKeyboardKey(videodata->keyboard, SDL_RELEASED,
   226                                 videodata->key_layout[keycode]);
   227         }
   228         break;
   229 
   230         /* Have we been iconified? */
   231     case UnmapNotify:{
   232 #ifdef DEBUG_XEVENTS
   233             printf("UnmapNotify!\n");
   234 #endif
   235             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   236             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MINIMIZED, 0,
   237                                 0);
   238         }
   239         break;
   240 
   241         /* Have we been restored? */
   242     case MapNotify:{
   243 #ifdef DEBUG_XEVENTS
   244             printf("MapNotify!\n");
   245 #endif
   246             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0);
   247             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESTORED, 0,
   248                                 0);
   249         }
   250         break;
   251 
   252         /* Have we been resized or moved? */
   253     case ConfigureNotify:{
   254 #ifdef DEBUG_XEVENTS
   255             printf("ConfigureNotify! (resize: %dx%d)\n",
   256                    xevent.xconfigure.width, xevent.xconfigure.height);
   257 #endif
   258             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MOVED,
   259                                 xevent.xconfigure.x, xevent.xconfigure.y);
   260             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESIZED,
   261                                 xevent.xconfigure.width,
   262                                 xevent.xconfigure.height);
   263         }
   264         break;
   265 
   266         /* Have we been requested to quit (or another client message?) */
   267     case ClientMessage:{
   268             if ((xevent.xclient.format == 32) &&
   269                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   270 
   271                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_CLOSE, 0,
   272                                     0);
   273             }
   274         }
   275         break;
   276 
   277         /* Do we need to refresh ourselves? */
   278     case Expose:{
   279 #ifdef DEBUG_XEVENTS
   280             printf("Expose (count = %d)\n", xevent.xexpose.count);
   281 #endif
   282             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_EXPOSED, 0,
   283                                 0);
   284         }
   285         break;
   286 
   287     default:{
   288             for (i = 0; i < SDL_GetNumMice(); ++i) {
   289                 SDL_Mouse *mouse;
   290 #if SDL_VIDEO_DRIVER_X11_XINPUT
   291                 X11_MouseData *data;
   292 #endif
   293 
   294                 mouse = SDL_GetMouse(i);
   295                 if (!mouse->driverdata) {
   296                     switch (xevent.type) {
   297                     case MotionNotify:
   298 #ifdef DEBUG_MOTION
   299                         printf("X11 motion: %d,%d\n", xevent.xmotion.x,
   300                                xevent.xmotion.y);
   301 #endif
   302                         SDL_SendMouseMotion(mouse->id, 0, xevent.xmotion.x,
   303                                             xevent.xmotion.y, 0);
   304                         break;
   305 
   306                     case ButtonPress:
   307                         SDL_SendMouseButton(mouse->id, SDL_PRESSED,
   308                                             xevent.xbutton.button);
   309                         break;
   310 
   311                     case ButtonRelease:
   312                         SDL_SendMouseButton(mouse->id, SDL_RELEASED,
   313                                             xevent.xbutton.button);
   314                         break;
   315                     }
   316                     continue;
   317                 }
   318 #if SDL_VIDEO_DRIVER_X11_XINPUT
   319                 data = (X11_MouseData *) mouse->driverdata;
   320                 if (xevent.type == data->motion) {
   321                     XDeviceMotionEvent *move =
   322                         (XDeviceMotionEvent *) & xevent;
   323 #ifdef DEBUG_MOTION
   324                     printf("X11 motion: %d,%d\n", move->x, move->y);
   325 #endif
   326                     SDL_SendMouseMotion(move->deviceid, 0, move->x, move->y,
   327                                         move->axis_data[2]);
   328                     return;
   329                 }
   330                 if (xevent.type == data->button_pressed) {
   331                     XDeviceButtonPressedEvent *pressed =
   332                         (XDeviceButtonPressedEvent *) & xevent;
   333                     SDL_SendMouseButton(pressed->deviceid, SDL_PRESSED,
   334                                         pressed->button);
   335                     return;
   336                 }
   337                 if (xevent.type == data->button_released) {
   338                     XDeviceButtonReleasedEvent *released =
   339                         (XDeviceButtonReleasedEvent *) & xevent;
   340                     SDL_SendMouseButton(released->deviceid, SDL_RELEASED,
   341                                         released->button);
   342                     return;
   343                 }
   344                 if (xevent.type == data->proximity_in) {
   345                     XProximityNotifyEvent *proximity =
   346                         (XProximityNotifyEvent *) & xevent;
   347                     SDL_SendProximity(proximity->deviceid, proximity->x,
   348                                       proximity->y, SDL_PROXIMITYIN);
   349                     return;
   350                 }
   351                 if (xevent.type == data->proximity_out) {
   352                     XProximityNotifyEvent *proximity =
   353                         (XProximityNotifyEvent *) & xevent;
   354                     SDL_SendProximity(proximity->deviceid, proximity->x,
   355                                       proximity->y, SDL_PROXIMITYOUT);
   356                     return;
   357                 }
   358 #endif
   359             }
   360 #ifdef DEBUG_XEVENTS
   361             printf("Unhandled event %d\n", xevent.type);
   362 #endif
   363         }
   364         break;
   365     }
   366 }
   367 
   368 /* Ack!  XPending() actually performs a blocking read if no events available */
   369 int
   370 X11_Pending(Display * display)
   371 {
   372     /* Flush the display connection and look to see if events are queued */
   373     XFlush(display);
   374     if (XEventsQueued(display, QueuedAlready)) {
   375         return (1);
   376     }
   377 
   378     /* More drastic measures are required -- see if X is ready to talk */
   379     {
   380         static struct timeval zero_time;        /* static == 0 */
   381         int x11_fd;
   382         fd_set fdset;
   383 
   384         x11_fd = ConnectionNumber(display);
   385         FD_ZERO(&fdset);
   386         FD_SET(x11_fd, &fdset);
   387         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   388             return (XPending(display));
   389         }
   390     }
   391 
   392     /* Oh well, nothing is ready .. */
   393     return (0);
   394 }
   395 
   396 void
   397 X11_PumpEvents(_THIS)
   398 {
   399     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   400 
   401     /* Update activity every 30 seconds to prevent screensaver */
   402     if (_this->suspend_screensaver) {
   403         Uint32 now = SDL_GetTicks();
   404         if (!data->screensaver_activity ||
   405             (int) (now - data->screensaver_activity) >= 30000) {
   406             XResetScreenSaver(data->display);
   407             data->screensaver_activity = now;
   408         }
   409     }
   410 
   411     /* Keep processing pending events */
   412     while (X11_Pending(data->display)) {
   413         X11_DispatchEvent(_this);
   414     }
   415 }
   416 
   417 /* This is so wrong it hurts */
   418 #define GNOME_SCREENSAVER_HACK
   419 #ifdef GNOME_SCREENSAVER_HACK
   420 #include <unistd.h>
   421 static pid_t screensaver_inhibit_pid;
   422 static void
   423 gnome_screensaver_disable()
   424 {
   425     screensaver_inhibit_pid = fork();
   426     if (screensaver_inhibit_pid == 0) {
   427         close(0);
   428         close(1);
   429         close(2);
   430         execl("/usr/bin/gnome-screensaver-command",
   431               "gnome-screensaver-command",
   432               "--inhibit",
   433               "--reason",
   434               "GNOME screensaver doesn't respect MIT-SCREEN-SAVER", NULL);
   435         exit(2);
   436     }
   437 }
   438 static void
   439 gnome_screensaver_enable()
   440 {
   441     kill(screensaver_inhibit_pid, 15);
   442 }
   443 #endif
   444 
   445 void
   446 X11_SuspendScreenSaver(_THIS)
   447 {
   448 #if SDL_VIDEO_DRIVER_X11_SCRNSAVER
   449     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   450     int dummy;
   451     int major_version, minor_version;
   452 
   453     if (SDL_X11_HAVE_XSS) {
   454         /* XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
   455         if (!XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
   456             !XScreenSaverQueryVersion(data->display,
   457                                       &major_version, &minor_version) ||
   458             major_version < 1 || (major_version == 1 && minor_version < 1)) {
   459             return;
   460         }
   461 
   462         XScreenSaverSuspend(data->display, _this->suspend_screensaver);
   463         XResetScreenSaver(data->display);
   464     }
   465 #endif
   466 
   467 #ifdef GNOME_SCREENSAVER_HACK
   468     if (_this->suspend_screensaver) {
   469         gnome_screensaver_disable();
   470     } else {
   471         gnome_screensaver_enable();
   472     }
   473 #endif
   474 }
   475 
   476 /* vi: set ts=4 sw=4 expandtab: */