src/video/x11/SDL_x11events.c
author Sam Lantinga
Wed, 10 Jun 2009 13:54:13 +0000
changeset 3190 c68d2ca5970f
parent 3188 102b7880543a
child 3195 08747e24a50f
permissions -rw-r--r--
Added missing files for OpenGL ES support
     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)\n", xevent.xcrossing.x,
    87                    xevent.xcrossing.y);
    88             if (xevent.xcrossing.mode == NotifyGrab)
    89                 printf("Mode: NotifyGrab\n");
    90             if (xevent.xcrossing.mode == NotifyUngrab)
    91                 printf("Mode: NotifyUngrab\n");
    92 #endif
    93             if ((xevent.xcrossing.mode != NotifyGrab) &&
    94                 (xevent.xcrossing.mode != NotifyUngrab)) {
    95                 /* FIXME: Should we reset data for all mice? */
    96 #if 0
    97                 SDL_SetMouseFocus(0, data->windowID);
    98                 SDL_SendMouseMotion(0, 0, move->x, move->y, 0);
    99 #endif
   100             }
   101         }
   102         break;
   103 
   104         /* Losing mouse coverage? */
   105     case LeaveNotify:{
   106 #ifdef DEBUG_XEVENTS
   107             printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x,
   108                    xevent.xcrossing.y);
   109             if (xevent.xcrossing.mode == NotifyGrab)
   110                 printf("Mode: NotifyGrab\n");
   111             if (xevent.xcrossing.mode == NotifyUngrab)
   112                 printf("Mode: NotifyUngrab\n");
   113 #endif
   114             if ((xevent.xcrossing.mode != NotifyGrab) &&
   115                 (xevent.xcrossing.mode != NotifyUngrab) &&
   116                 (xevent.xcrossing.detail != NotifyInferior)) {
   117                 /* FIXME: Should we reset data for all mice? */
   118 #if 0
   119                 SDL_SetMouseFocus(0, 0);
   120 #endif
   121             }
   122         }
   123         break;
   124 
   125         /* Gaining input focus? */
   126     case FocusIn:{
   127 #ifdef DEBUG_XEVENTS
   128             printf("FocusIn!\n");
   129 #endif
   130             SDL_SetKeyboardFocus(videodata->keyboard, data->windowID);
   131 #ifdef X_HAVE_UTF8_STRING
   132             if (data->ic) {
   133                 XSetICFocus(data->ic);
   134             }
   135 #endif
   136         }
   137         break;
   138 
   139         /* Losing input focus? */
   140     case FocusOut:{
   141 #ifdef DEBUG_XEVENTS
   142             printf("FocusOut!\n");
   143 #endif
   144             SDL_SetKeyboardFocus(videodata->keyboard, 0);
   145 #ifdef X_HAVE_UTF8_STRING
   146             if (data->ic) {
   147                 XUnsetICFocus(data->ic);
   148             }
   149 #endif
   150         }
   151         break;
   152 
   153         /* Generated upon EnterWindow and FocusIn */
   154     case KeymapNotify:{
   155 #ifdef DEBUG_XEVENTS
   156             printf("KeymapNotify!\n");
   157 #endif
   158             /* FIXME:
   159                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   160              */
   161         }
   162         break;
   163 
   164         /* Has the keyboard layout changed? */
   165     case MappingNotify:{
   166 #ifdef DEBUG_XEVENTS
   167             printf("MappingNotify!\n");
   168 #endif
   169             X11_UpdateKeymap(_this);
   170         }
   171         break;
   172 
   173         /* Key press? */
   174     case KeyPress:{
   175             KeyCode keycode = xevent.xkey.keycode;
   176             KeySym keysym = NoSymbol;
   177             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
   178             Status status = 0;
   179 
   180 #ifdef DEBUG_XEVENTS
   181             printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   182 #endif
   183             SDL_SendKeyboardKey(videodata->keyboard, SDL_PRESSED,
   184                                 videodata->key_layout[keycode]);
   185 #if 0
   186             if (videodata->key_layout[keycode] == SDLK_UNKNOWN) {
   187                 int min_keycode, max_keycode;
   188                 XDisplayKeycodes(videodata->display, &min_keycode,
   189                                  &max_keycode);
   190                 keysym = XKeycodeToKeysym(videodata->display, keycode, 0);
   191                 fprintf(stderr,
   192                         "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",
   193                         keycode, keycode - min_keycode, keysym,
   194                         XKeysymToString(keysym));
   195             }
   196 #endif
   197             /* */
   198             SDL_zero(text);
   199 #ifdef X_HAVE_UTF8_STRING
   200             if (data->ic) {
   201                 Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   202                                   &keysym, &status);
   203             }
   204 #else
   205             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   206 #endif
   207             if (*text) {
   208                 SDL_SendKeyboardText(videodata->keyboard, text);
   209             }
   210         }
   211         break;
   212 
   213         /* Key release? */
   214     case KeyRelease:{
   215             KeyCode keycode = xevent.xkey.keycode;
   216 
   217 #ifdef DEBUG_XEVENTS
   218             printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   219 #endif
   220             SDL_SendKeyboardKey(videodata->keyboard, SDL_RELEASED,
   221                                 videodata->key_layout[keycode]);
   222         }
   223         break;
   224 
   225         /* Have we been iconified? */
   226     case UnmapNotify:{
   227 #ifdef DEBUG_XEVENTS
   228             printf("UnmapNotify!\n");
   229 #endif
   230             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   231             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MINIMIZED, 0,
   232                                 0);
   233         }
   234         break;
   235 
   236         /* Have we been restored? */
   237     case MapNotify:{
   238 #ifdef DEBUG_XEVENTS
   239             printf("MapNotify!\n");
   240 #endif
   241             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0);
   242             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESTORED, 0,
   243                                 0);
   244         }
   245         break;
   246 
   247         /* Have we been resized or moved? */
   248     case ConfigureNotify:{
   249 #ifdef DEBUG_XEVENTS
   250             printf("ConfigureNotify! (resize: %dx%d)\n",
   251                    xevent.xconfigure.width, xevent.xconfigure.height);
   252 #endif
   253             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MOVED,
   254                                 xevent.xconfigure.x, xevent.xconfigure.y);
   255             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESIZED,
   256                                 xevent.xconfigure.width,
   257                                 xevent.xconfigure.height);
   258         }
   259         break;
   260 
   261         /* Have we been requested to quit (or another client message?) */
   262     case ClientMessage:{
   263             if ((xevent.xclient.format == 32) &&
   264                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   265 
   266                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_CLOSE, 0,
   267                                     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->windowID, SDL_WINDOWEVENT_EXPOSED, 0,
   278                                 0);
   279         }
   280         break;
   281 
   282     default:{
   283             for (i = 0; i < SDL_GetNumMice(); ++i) {
   284                 SDL_Mouse *mouse;
   285 #if SDL_VIDEO_DRIVER_X11_XINPUT
   286                 X11_MouseData *data;
   287 #endif
   288 
   289                 mouse = SDL_GetMouse(i);
   290                 if (!mouse->driverdata) {
   291                     switch (xevent.type) {
   292                     case MotionNotify:
   293 #ifdef DEBUG_MOTION
   294                         printf("X11 motion: %d,%d\n", xevent.xmotion.x,
   295                                xevent.xmotion.y);
   296 #endif
   297                         SDL_SendMouseMotion(mouse->id, 0, xevent.xmotion.x,
   298                                             xevent.xmotion.y, 0);
   299                         break;
   300 
   301                     case ButtonPress:
   302                         SDL_SendMouseButton(mouse->id, SDL_PRESSED,
   303                                             xevent.xbutton.button);
   304                         break;
   305 
   306                     case ButtonRelease:
   307                         SDL_SendMouseButton(mouse->id, SDL_RELEASED,
   308                                             xevent.xbutton.button);
   309                         break;
   310                     }
   311                     continue;
   312                 }
   313 #if SDL_VIDEO_DRIVER_X11_XINPUT
   314                 data = (X11_MouseData *) mouse->driverdata;
   315                 if (xevent.type == data->motion) {
   316                     XDeviceMotionEvent *move =
   317                         (XDeviceMotionEvent *) & xevent;
   318 #ifdef DEBUG_MOTION
   319                     printf("X11 motion: %d,%d\n", move->x, move->y);
   320 #endif
   321                     SDL_SendMouseMotion(move->deviceid, 0, move->x, move->y,
   322                                         move->axis_data[2]);
   323                     return;
   324                 }
   325                 if (xevent.type == data->button_pressed) {
   326                     XDeviceButtonPressedEvent *pressed =
   327                         (XDeviceButtonPressedEvent *) & xevent;
   328                     SDL_SendMouseButton(pressed->deviceid, SDL_PRESSED,
   329                                         pressed->button);
   330                     return;
   331                 }
   332                 if (xevent.type == data->button_released) {
   333                     XDeviceButtonReleasedEvent *released =
   334                         (XDeviceButtonReleasedEvent *) & xevent;
   335                     SDL_SendMouseButton(released->deviceid, SDL_RELEASED,
   336                                         released->button);
   337                     return;
   338                 }
   339                 if (xevent.type == data->proximity_in) {
   340                     XProximityNotifyEvent *proximity =
   341                         (XProximityNotifyEvent *) & xevent;
   342                     SDL_SendProximity(proximity->deviceid, proximity->x,
   343                                       proximity->y, SDL_PROXIMITYIN);
   344                     return;
   345                 }
   346                 if (xevent.type == data->proximity_out) {
   347                     XProximityNotifyEvent *proximity =
   348                         (XProximityNotifyEvent *) & xevent;
   349                     SDL_SendProximity(proximity->deviceid, proximity->x,
   350                                       proximity->y, SDL_PROXIMITYOUT);
   351                     return;
   352                 }
   353 #endif
   354             }
   355 #ifdef DEBUG_XEVENTS
   356             printf("Unhandled event %d\n", xevent.type);
   357 #endif
   358         }
   359         break;
   360     }
   361 }
   362 
   363 /* Ack!  XPending() actually performs a blocking read if no events available */
   364 int
   365 X11_Pending(Display * display)
   366 {
   367     /* Flush the display connection and look to see if events are queued */
   368     XFlush(display);
   369     if (XEventsQueued(display, QueuedAlready)) {
   370         return (1);
   371     }
   372 
   373     /* More drastic measures are required -- see if X is ready to talk */
   374     {
   375         static struct timeval zero_time;        /* static == 0 */
   376         int x11_fd;
   377         fd_set fdset;
   378 
   379         x11_fd = ConnectionNumber(display);
   380         FD_ZERO(&fdset);
   381         FD_SET(x11_fd, &fdset);
   382         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   383             return (XPending(display));
   384         }
   385     }
   386 
   387     /* Oh well, nothing is ready .. */
   388     return (0);
   389 }
   390 
   391 void
   392 X11_PumpEvents(_THIS)
   393 {
   394     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   395 
   396     /* Update activity every 30 seconds to prevent screensaver */
   397     if (_this->suspend_screensaver) {
   398         Uint32 now = SDL_GetTicks();
   399         if (!data->screensaver_activity ||
   400             (int) (now - data->screensaver_activity) >= 30000) {
   401             XResetScreenSaver(data->display);
   402             data->screensaver_activity = now;
   403         }
   404     }
   405 
   406     /* Keep processing pending events */
   407     while (X11_Pending(data->display)) {
   408         X11_DispatchEvent(_this);
   409     }
   410 }
   411 
   412 /* This is so wrong it hurts */
   413 #define GNOME_SCREENSAVER_HACK
   414 #ifdef GNOME_SCREENSAVER_HACK
   415 #include <unistd.h>
   416 static pid_t screensaver_inhibit_pid;
   417 static void
   418 gnome_screensaver_disable()
   419 {
   420     screensaver_inhibit_pid = fork();
   421     if (screensaver_inhibit_pid == 0) {
   422         close(0);
   423         close(1);
   424         close(2);
   425         execl("/usr/bin/gnome-screensaver-command",
   426               "gnome-screensaver-command",
   427               "--inhibit",
   428               "--reason",
   429               "GNOME screensaver doesn't respect MIT-SCREEN-SAVER", NULL);
   430         exit(2);
   431     }
   432 }
   433 static void
   434 gnome_screensaver_enable()
   435 {
   436     kill(screensaver_inhibit_pid, 15);
   437 }
   438 #endif
   439 
   440 void
   441 X11_SuspendScreenSaver(_THIS)
   442 {
   443 #if SDL_VIDEO_DRIVER_X11_SCRNSAVER
   444     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   445     int dummy;
   446     int major_version, minor_version;
   447 
   448     if (SDL_X11_HAVE_XSS) {
   449         /* XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
   450         if (!XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
   451             !XScreenSaverQueryVersion(data->display,
   452                                       &major_version, &minor_version) ||
   453             major_version < 1 || (major_version == 1 && minor_version < 1)) {
   454             return;
   455         }
   456 
   457         XScreenSaverSuspend(data->display, _this->suspend_screensaver);
   458         XResetScreenSaver(data->display);
   459     }
   460 #endif
   461 
   462 #ifdef GNOME_SCREENSAVER_HACK
   463     if (_this->suspend_screensaver) {
   464         gnome_screensaver_disable();
   465     } else {
   466         gnome_screensaver_enable();
   467     }
   468 #endif
   469 }
   470 
   471 /* vi: set ts=4 sw=4 expandtab: */