src/video/x11/SDL_x11events.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 27 Nov 2008 21:53:18 +0000
changeset 2794 f7872b7a8732
parent 2763 6fc50bdd88c0
child 2859 99210400e8b9
permissions -rw-r--r--
Fixed mouse coordinate range on Mac OS X
     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                 XDeviceMotionEvent *move = (XDeviceMotionEvent *) & xevent;
   282 #ifdef DEBUG_MOTION
   283                 printf("X11 motion: %d,%d\n", move->x, move->y);
   284 #endif
   285                 SDL_SendMouseMotion(move->deviceid, 0, move->x,
   286                                     move->y, move->axis_data[2]);
   287             } else if (xevent.type == button_pressed) { /* ButtonPress */
   288                 XDeviceButtonPressedEvent *pressed =
   289                     (XDeviceButtonPressedEvent *) & xevent;
   290                 SDL_SendMouseButton(pressed->deviceid, SDL_PRESSED,
   291                                     pressed->button);
   292             } else if (xevent.type == button_released) {        /* ButtonRelease */
   293                 XDeviceButtonReleasedEvent *released =
   294                     (XDeviceButtonReleasedEvent *) & xevent;
   295                 SDL_SendMouseButton(released->deviceid, SDL_RELEASED,
   296                                     released->button);
   297             } else if (xevent.type == proximity_in) {
   298                 XProximityNotifyEvent *proximity =
   299                     (XProximityNotifyEvent *) & xevent;
   300                 SDL_SendProximity(proximity->deviceid, proximity->x,
   301                                   proximity->y, SDL_PROXIMITYIN);
   302             } else if (xevent.type == proximity_out) {
   303                 XProximityNotifyEvent *proximity =
   304                     (XProximityNotifyEvent *) & xevent;
   305                 SDL_SendProximity(proximity->deviceid, proximity->x,
   306                                   proximity->y, SDL_PROXIMITYOUT);
   307             }
   308 #ifdef DEBUG_XEVENTS
   309             else {
   310                 printf("Unhandled event %d\n", xevent.type);
   311             }
   312 #endif
   313         }
   314         break;
   315     }
   316 }
   317 
   318 /* Ack!  XPending() actually performs a blocking read if no events available */
   319 int
   320 X11_Pending(Display * display)
   321 {
   322     /* Flush the display connection and look to see if events are queued */
   323     XFlush(display);
   324     if (XEventsQueued(display, QueuedAlready)) {
   325         return (1);
   326     }
   327 
   328     /* More drastic measures are required -- see if X is ready to talk */
   329     {
   330         static struct timeval zero_time;        /* static == 0 */
   331         int x11_fd;
   332         fd_set fdset;
   333 
   334         x11_fd = ConnectionNumber(display);
   335         FD_ZERO(&fdset);
   336         FD_SET(x11_fd, &fdset);
   337         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   338             return (XPending(display));
   339         }
   340     }
   341 
   342     /* Oh well, nothing is ready .. */
   343     return (0);
   344 }
   345 
   346 void
   347 X11_PumpEvents(_THIS)
   348 {
   349     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   350 
   351     /* Keep processing pending events */
   352     while (X11_Pending(data->display)) {
   353         X11_DispatchEvent(_this);
   354     }
   355 }
   356 
   357 void
   358 X11_SaveScreenSaver(Display * display, int *saved_timeout, BOOL * dpms)
   359 {
   360     int timeout, interval, prefer_blank, allow_exp;
   361     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   362     *saved_timeout = timeout;
   363 
   364 #if SDL_VIDEO_DRIVER_X11_DPMS
   365     if (SDL_X11_HAVE_DPMS) {
   366         int dummy;
   367         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   368             CARD16 state;
   369             DPMSInfo(display, &state, dpms);
   370         }
   371     }
   372 #else
   373     *dpms = 0;
   374 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   375 }
   376 
   377 void
   378 X11_DisableScreenSaver(Display * display)
   379 {
   380     int timeout, interval, prefer_blank, allow_exp;
   381     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   382     timeout = 0;
   383     XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
   384 
   385 #if SDL_VIDEO_DRIVER_X11_DPMS
   386     if (SDL_X11_HAVE_DPMS) {
   387         int dummy;
   388         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   389             DPMSDisable(display);
   390         }
   391     }
   392 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   393 }
   394 
   395 void
   396 X11_RestoreScreenSaver(Display * display, int saved_timeout, BOOL dpms)
   397 {
   398     int timeout, interval, prefer_blank, allow_exp;
   399     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   400     timeout = saved_timeout;
   401     XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
   402 
   403 #if SDL_VIDEO_DRIVER_X11_DPMS
   404     if (SDL_X11_HAVE_DPMS) {
   405         int dummy;
   406         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   407             if (dpms) {
   408                 DPMSEnable(display);
   409             }
   410         }
   411     }
   412 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   413 }
   414 
   415 /* vi: set ts=4 sw=4 expandtab: */