src/video/x11/SDL_x11events.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 17 Sep 2008 08:20:57 +0000
changeset 2763 6fc50bdd88c0
parent 2738 79c1bd651f04
child 2794 f7872b7a8732
permissions -rw-r--r--
Some cleanups on the new XInput code.

One or two things got moved around, but largely this is hooked up correctly
in the Unix configure system now: it can be dynamically loaded and fallback
gracefully if not available, or libXi can be directly linked to libSDL.

XInput support can be --disable'd from the configure script, too (defaults to
enabled).

Please note that while the framework is in place to gracefully fallback, the
current state of the source requires XInput. We'll need to adjust a few
things still to correct this.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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 
    32 static void
    33 X11_DispatchEvent(_THIS)
    34 {
    35     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    36     SDL_WindowData *data;
    37     XEvent xevent;
    38     int i;
    39 
    40     SDL_zero(xevent);           /* valgrind fix. --ryan. */
    41     XNextEvent(videodata->display, &xevent);
    42 
    43     /* filter events catchs XIM events and sends them to the correct
    44        handler */
    45     if (XFilterEvent(&xevent, None) == True) {
    46 #if 0
    47         printf("Filtered event type = %d display = %d window = %d\n",
    48                xevent.type, xevent.xany.display, xevent.xany.window);
    49 #endif
    50         return;
    51     }
    52 
    53     /* Send a SDL_SYSWMEVENT if the application wants them */
    54     if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) {
    55         SDL_SysWMmsg wmmsg;
    56 
    57         SDL_VERSION(&wmmsg.version);
    58         wmmsg.subsystem = SDL_SYSWM_X11;
    59         wmmsg.event.xevent = xevent;
    60         SDL_SendSysWMEvent(&wmmsg);
    61     }
    62 
    63     data = NULL;
    64     if (videodata && videodata->windowlist) {
    65         for (i = 0; i < videodata->numwindows; ++i) {
    66             if ((videodata->windowlist[i] != NULL) &&
    67                 (videodata->windowlist[i]->window == xevent.xany.window)) {
    68                 data = videodata->windowlist[i];
    69                 break;
    70             }
    71         }
    72     }
    73     if (!data) {
    74         return;
    75     }
    76 #if 0
    77     printf("type = %d display = %d window = %d\n",
    78            xevent.type, xevent.xany.display, xevent.xany.window);
    79 #endif
    80     switch (xevent.type) {
    81 
    82         /* Gaining mouse coverage? */
    83     case EnterNotify:{
    84 #ifdef DEBUG_XEVENTS
    85             printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x,
    86                    xevent.xcrossing.y);
    87             if (xevent.xcrossing.mode == NotifyGrab)
    88                 printf("Mode: NotifyGrab\n");
    89             if (xevent.xcrossing.mode == NotifyUngrab)
    90                 printf("Mode: NotifyUngrab\n");
    91 #endif
    92             if ((xevent.xcrossing.mode != NotifyGrab) &&
    93                 (xevent.xcrossing.mode != NotifyUngrab)) {
    94                 XDeviceMotionEvent *move = (XDeviceMotionEvent *) & xevent;
    95                 SDL_SetMouseFocus(move->deviceid, data->windowID);
    96                 SDL_SendMouseMotion(move->deviceid, 0, move->x,
    97                                     move->y, move->axis_data[2]);
    98             }
    99         }
   100         break;
   101 
   102         /* Losing mouse coverage? */
   103     case LeaveNotify:{
   104 #ifdef DEBUG_XEVENTS
   105             printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x,
   106                    xevent.xcrossing.y);
   107             if (xevent.xcrossing.mode == NotifyGrab)
   108                 printf("Mode: NotifyGrab\n");
   109             if (xevent.xcrossing.mode == NotifyUngrab)
   110                 printf("Mode: NotifyUngrab\n");
   111 #endif
   112             if ((xevent.xcrossing.mode != NotifyGrab) &&
   113                 (xevent.xcrossing.mode != NotifyUngrab) &&
   114                 (xevent.xcrossing.detail != NotifyInferior)) {
   115                 XDeviceMotionEvent *move = (XDeviceMotionEvent *) & xevent;
   116                 SDL_SetMouseFocus(move->deviceid, 0);
   117             }
   118         }
   119         break;
   120 
   121         /* Gaining input focus? */
   122     case FocusIn:{
   123 #ifdef DEBUG_XEVENTS
   124             printf("FocusIn!\n");
   125 #endif
   126             SDL_SetKeyboardFocus(videodata->keyboard, data->windowID);
   127 #ifdef X_HAVE_UTF8_STRING
   128             if (data->ic) {
   129                 XSetICFocus(data->ic);
   130             }
   131 #endif
   132         }
   133         break;
   134 
   135         /* Losing input focus? */
   136     case FocusOut:{
   137 #ifdef DEBUG_XEVENTS
   138             printf("FocusOut!\n");
   139 #endif
   140             SDL_SetKeyboardFocus(videodata->keyboard, 0);
   141 #ifdef X_HAVE_UTF8_STRING
   142             if (data->ic) {
   143                 XUnsetICFocus(data->ic);
   144             }
   145 #endif
   146         }
   147         break;
   148 
   149         /* Generated upon EnterWindow and FocusIn */
   150     case KeymapNotify:{
   151 #ifdef DEBUG_XEVENTS
   152             printf("KeymapNotify!\n");
   153 #endif
   154             /* FIXME:
   155                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   156              */
   157         }
   158         break;
   159 
   160         /* Has the keyboard layout changed? */
   161     case MappingNotify:{
   162 #ifdef DEBUG_XEVENTS
   163             printf("MappingNotify!\n");
   164 #endif
   165             X11_UpdateKeymap(_this);
   166         }
   167         break;
   168 
   169         /* Key press? */
   170     case KeyPress:{
   171             KeyCode keycode = xevent.xkey.keycode;
   172             KeySym keysym = NoSymbol;
   173             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
   174             Status status = 0;
   175 
   176 #ifdef DEBUG_XEVENTS
   177             printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   178 #endif
   179             SDL_SendKeyboardKey(videodata->keyboard, SDL_PRESSED,
   180                                 videodata->key_layout[keycode]);
   181 #if 0
   182             if (videodata->key_layout[keycode] == SDLK_UNKNOWN) {
   183                 int min_keycode, max_keycode;
   184                 XDisplayKeycodes(videodata->display, &min_keycode,
   185                                  &max_keycode);
   186                 keysym = XKeycodeToKeysym(videodata->display, keycode, 0);
   187                 fprintf(stderr,
   188                         "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",
   189                         keycode, keycode - min_keycode, keysym,
   190                         XKeysymToString(keysym));
   191             }
   192 #endif
   193             /* */
   194             SDL_zero(text);
   195 #ifdef X_HAVE_UTF8_STRING
   196             if (data->ic) {
   197                 Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   198                                   &keysym, &status);
   199             }
   200 #else
   201             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   202 #endif
   203             if (*text) {
   204                 printf("Sending text event %s\n", text);
   205                 SDL_SendKeyboardText(videodata->keyboard, text);
   206             }
   207         }
   208         break;
   209 
   210         /* Key release? */
   211     case KeyRelease:{
   212             KeyCode keycode = xevent.xkey.keycode;
   213 
   214 #ifdef DEBUG_XEVENTS
   215             printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   216 #endif
   217             SDL_SendKeyboardKey(videodata->keyboard, SDL_RELEASED,
   218                                 videodata->key_layout[keycode]);
   219         }
   220         break;
   221 
   222         /* Have we been iconified? */
   223     case UnmapNotify:{
   224 #ifdef DEBUG_XEVENTS
   225             printf("UnmapNotify!\n");
   226 #endif
   227             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   228             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MINIMIZED, 0,
   229                                 0);
   230         }
   231         break;
   232 
   233         /* Have we been restored? */
   234     case MapNotify:{
   235 #ifdef DEBUG_XEVENTS
   236             printf("MapNotify!\n");
   237 #endif
   238             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0);
   239             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESTORED, 0,
   240                                 0);
   241         }
   242         break;
   243 
   244         /* Have we been resized or moved? */
   245     case ConfigureNotify:{
   246 #ifdef DEBUG_XEVENTS
   247             printf("ConfigureNotify! (resize: %dx%d)\n",
   248                    xevent.xconfigure.width, xevent.xconfigure.height);
   249 #endif
   250             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MOVED,
   251                                 xevent.xconfigure.x, xevent.xconfigure.y);
   252             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESIZED,
   253                                 xevent.xconfigure.width,
   254                                 xevent.xconfigure.height);
   255         }
   256         break;
   257 
   258         /* Have we been requested to quit (or another client message?) */
   259     case ClientMessage:{
   260             if ((xevent.xclient.format == 32) &&
   261                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   262 
   263                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_CLOSE, 0,
   264                                     0);
   265             }
   266         }
   267         break;
   268 
   269         /* Do we need to refresh ourselves? */
   270     case Expose:{
   271 #ifdef DEBUG_XEVENTS
   272             printf("Expose (count = %d)\n", xevent.xexpose.count);
   273 #endif
   274             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_EXPOSED, 0,
   275                                 0);
   276         }
   277         break;
   278 
   279     default:{
   280             if (xevent.type == motion) {        /* MotionNotify */
   281 #ifdef DEBUG_MOTION
   282                 printf("X11 motion: %d,%d\n", xevent.xmotion.x,
   283                        xevent.xmotion.y);
   284 #endif
   285                 XWindowAttributes attrib;
   286                 XGetWindowAttributes(videodata->display,
   287                                      ((XAnyEvent *) & xevent)->window,
   288                                      &attrib);
   289                 SDL_UpdateCoordinates(attrib.width, attrib.height);
   290                 XDeviceMotionEvent *move = (XDeviceMotionEvent *) & xevent;
   291                 SDL_SendMouseMotion(move->deviceid, 0, move->x,
   292                                     move->y, move->axis_data[2]);
   293             } else if (xevent.type == button_pressed) { /* ButtonPress */
   294                 XDeviceButtonPressedEvent *pressed =
   295                     (XDeviceButtonPressedEvent *) & xevent;
   296                 SDL_SendMouseButton(pressed->deviceid, SDL_PRESSED,
   297                                     pressed->button);
   298             } else if (xevent.type == button_released) {        /* ButtonRelease */
   299                 XDeviceButtonReleasedEvent *released =
   300                     (XDeviceButtonReleasedEvent *) & xevent;
   301                 SDL_SendMouseButton(released->deviceid, SDL_RELEASED,
   302                                     released->button);
   303             } else if (xevent.type == proximity_in) {
   304                 XProximityNotifyEvent *proximity =
   305                     (XProximityNotifyEvent *) & xevent;
   306                 SDL_SendProximity(proximity->deviceid, proximity->x,
   307                                   proximity->y, SDL_PROXIMITYIN);
   308             } else if (xevent.type == proximity_out) {
   309                 XProximityNotifyEvent *proximity =
   310                     (XProximityNotifyEvent *) & xevent;
   311                 SDL_SendProximity(proximity->deviceid, proximity->x,
   312                                   proximity->y, SDL_PROXIMITYOUT);
   313             }
   314 #ifdef DEBUG_XEVENTS
   315             else {
   316                 printf("Unhandled event %d\n", xevent.type);
   317             }
   318 #endif
   319         }
   320         break;
   321     }
   322 }
   323 
   324 /* Ack!  XPending() actually performs a blocking read if no events available */
   325 int
   326 X11_Pending(Display * display)
   327 {
   328     /* Flush the display connection and look to see if events are queued */
   329     XFlush(display);
   330     if (XEventsQueued(display, QueuedAlready)) {
   331         return (1);
   332     }
   333 
   334     /* More drastic measures are required -- see if X is ready to talk */
   335     {
   336         static struct timeval zero_time;        /* static == 0 */
   337         int x11_fd;
   338         fd_set fdset;
   339 
   340         x11_fd = ConnectionNumber(display);
   341         FD_ZERO(&fdset);
   342         FD_SET(x11_fd, &fdset);
   343         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   344             return (XPending(display));
   345         }
   346     }
   347 
   348     /* Oh well, nothing is ready .. */
   349     return (0);
   350 }
   351 
   352 void
   353 X11_PumpEvents(_THIS)
   354 {
   355     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   356 
   357     /* Keep processing pending events */
   358     while (X11_Pending(data->display)) {
   359         X11_DispatchEvent(_this);
   360     }
   361 }
   362 
   363 void
   364 X11_SaveScreenSaver(Display * display, int *saved_timeout, BOOL * dpms)
   365 {
   366     int timeout, interval, prefer_blank, allow_exp;
   367     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   368     *saved_timeout = timeout;
   369 
   370 #if SDL_VIDEO_DRIVER_X11_DPMS
   371     if (SDL_X11_HAVE_DPMS) {
   372         int dummy;
   373         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   374             CARD16 state;
   375             DPMSInfo(display, &state, dpms);
   376         }
   377     }
   378 #else
   379     *dpms = 0;
   380 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   381 }
   382 
   383 void
   384 X11_DisableScreenSaver(Display * display)
   385 {
   386     int timeout, interval, prefer_blank, allow_exp;
   387     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   388     timeout = 0;
   389     XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
   390 
   391 #if SDL_VIDEO_DRIVER_X11_DPMS
   392     if (SDL_X11_HAVE_DPMS) {
   393         int dummy;
   394         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   395             DPMSDisable(display);
   396         }
   397     }
   398 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   399 }
   400 
   401 void
   402 X11_RestoreScreenSaver(Display * display, int saved_timeout, BOOL dpms)
   403 {
   404     int timeout, interval, prefer_blank, allow_exp;
   405     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   406     timeout = saved_timeout;
   407     XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
   408 
   409 #if SDL_VIDEO_DRIVER_X11_DPMS
   410     if (SDL_X11_HAVE_DPMS) {
   411         int dummy;
   412         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   413             if (dpms) {
   414                 DPMSEnable(display);
   415             }
   416         }
   417     }
   418 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   419 }
   420 
   421 /* vi: set ts=4 sw=4 expandtab: */