src/video/x11/SDL_x11events.c
author Bob Pendleton <bob@pendleton.com>
Tue, 08 Jan 2008 00:10:46 +0000
changeset 2295 dbc6d1893869
parent 2046 da8332c8f480
child 2299 a7cbc25071b6
permissions -rw-r--r--
Checking in Christian Walther's patch for x11 keyboard input. Minor code tweaks by Bob.
     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 
    33 /* Check to see if this is a repeated key.
    34    (idea shamelessly lifted from GII -- thanks guys! :)
    35  */
    36 static int
    37 X11_KeyRepeat(Display * display, XEvent * event)
    38 {
    39     XEvent peekevent;
    40     int repeated;
    41 
    42     repeated = 0;
    43     if (XPending(display)) {
    44         XPeekEvent(display, &peekevent);
    45         if ((peekevent.type == KeyPress) &&
    46             (peekevent.xkey.keycode == event->xkey.keycode) &&
    47             ((peekevent.xkey.time - event->xkey.time) < 2)) {
    48             repeated = 1;
    49             XNextEvent(display, &peekevent);
    50         }
    51     }
    52     return (repeated);
    53 }
    54 
    55 static void
    56 X11_DispatchEvent(_THIS)
    57 {
    58     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    59     SDL_WindowData *data;
    60     XEvent xevent;
    61     int i;
    62 
    63     SDL_zero(xevent);           /* valgrind fix. --ryan. */
    64     XNextEvent(videodata->display, &xevent);
    65 
    66     /* Send a SDL_SYSWMEVENT if the application wants them */
    67     if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) {
    68         SDL_SysWMmsg wmmsg;
    69 
    70         SDL_VERSION(&wmmsg.version);
    71         wmmsg.subsystem = SDL_SYSWM_X11;
    72         wmmsg.event.xevent = xevent;
    73         SDL_SendSysWMEvent(&wmmsg);
    74     }
    75 
    76     data = NULL;
    77     for (i = 0; i < videodata->numwindows; ++i) {
    78         if (videodata->windowlist[i]->window == xevent.xany.window) {
    79             data = videodata->windowlist[i];
    80         }
    81     }
    82     if (!data) {
    83         return;
    84     }
    85 
    86     switch (xevent.type) {
    87 
    88         /* Gaining mouse coverage? */
    89     case EnterNotify:{
    90 #ifdef DEBUG_XEVENTS
    91             printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x,
    92                    xevent.xcrossing.y);
    93             if (xevent.xcrossing.mode == NotifyGrab)
    94                 printf("Mode: NotifyGrab\n");
    95             if (xevent.xcrossing.mode == NotifyUngrab)
    96                 printf("Mode: NotifyUngrab\n");
    97 #endif
    98             if ((xevent.xcrossing.mode != NotifyGrab) &&
    99                 (xevent.xcrossing.mode != NotifyUngrab)) {
   100                 SDL_SetMouseFocus(videodata->mouse, data->windowID);
   101                 SDL_SendMouseMotion(videodata->mouse, 0, xevent.xcrossing.x,
   102                                     xevent.xcrossing.y);
   103             }
   104         }
   105         break;
   106 
   107         /* Losing mouse coverage? */
   108     case LeaveNotify:{
   109 #ifdef DEBUG_XEVENTS
   110             printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x,
   111                    xevent.xcrossing.y);
   112             if (xevent.xcrossing.mode == NotifyGrab)
   113                 printf("Mode: NotifyGrab\n");
   114             if (xevent.xcrossing.mode == NotifyUngrab)
   115                 printf("Mode: NotifyUngrab\n");
   116 #endif
   117             if ((xevent.xcrossing.mode != NotifyGrab) &&
   118                 (xevent.xcrossing.mode != NotifyUngrab) &&
   119                 (xevent.xcrossing.detail != NotifyInferior)) {
   120                 SDL_SendMouseMotion(videodata->mouse, 0,
   121                                     xevent.xcrossing.x, xevent.xcrossing.y);
   122                 SDL_SetMouseFocus(videodata->mouse, 0);
   123             }
   124         }
   125         break;
   126 
   127         /* Gaining input focus? */
   128     case FocusIn:{
   129 #ifdef DEBUG_XEVENTS
   130             printf("FocusIn!\n");
   131 #endif
   132             SDL_SetKeyboardFocus(videodata->keyboard, data->windowID);
   133 #ifdef X_HAVE_UTF8_STRING
   134             if (data->ic) {
   135                 XSetICFocus(data->ic);
   136             }
   137 #endif
   138         }
   139         break;
   140 
   141         /* Losing input focus? */
   142     case FocusOut:{
   143 #ifdef DEBUG_XEVENTS
   144             printf("FocusOut!\n");
   145 #endif
   146             SDL_SetKeyboardFocus(videodata->keyboard, 0);
   147 #ifdef X_HAVE_UTF8_STRING
   148             if (data->ic) {
   149                 XUnsetICFocus(data->ic);
   150             }
   151 #endif
   152         }
   153         break;
   154 
   155         /* Generated upon EnterWindow and FocusIn */
   156     case KeymapNotify:{
   157 #ifdef DEBUG_XEVENTS
   158             printf("KeymapNotify!\n");
   159 #endif
   160             /* FIXME:
   161                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   162              */
   163         }
   164         break;
   165 
   166         /* Mouse motion? */
   167     case MotionNotify:{
   168 #ifdef DEBUG_MOTION
   169             printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
   170 #endif
   171             SDL_SendMouseMotion(videodata->mouse, 0, xevent.xmotion.x,
   172                                 xevent.xmotion.y);
   173         }
   174         break;
   175 
   176         /* Mouse button press? */
   177     case ButtonPress:{
   178             SDL_SendMouseButton(videodata->mouse, SDL_PRESSED,
   179                                 xevent.xbutton.button);
   180         }
   181         break;
   182 
   183         /* Mouse button release? */
   184     case ButtonRelease:{
   185             SDL_SendMouseButton(videodata->mouse, SDL_RELEASED,
   186                                 xevent.xbutton.button);
   187         }
   188         break;
   189 
   190         /* Key press? */
   191     case KeyPress:{
   192             KeyCode keycode = xevent.xkey.keycode;
   193 
   194 #ifdef DEBUG_XEVENTS
   195             printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   196 #endif
   197             if (!X11_KeyRepeat(videodata->display, &xevent)) {
   198                 SDLKey physicalKey = videodata->keyCodeToSDLKTable[keycode];
   199                 SDL_SendKeyboardKey(videodata->keyboard, SDL_PRESSED,
   200                                     (Uint8) keycode, physicalKey);
   201 #if 1
   202                 if (physicalKey == SDLK_UNKNOWN) {
   203                     fprintf(stderr,
   204                             "The key you just pressed is not recognized by SDL. To help get this fixed, report this to the SDL mailing list <sdl@libsdl.org> or to Christian Walther <cwalther@gmx.ch>. X11 KeyCode is %d, X11 KeySym 0x%X.\n",
   205                             (int) keycode,
   206                             (unsigned int) XKeycodeToKeysym(videodata->
   207                                                             display, keycode,
   208                                                             0));
   209                 }
   210 #endif
   211             }
   212         }
   213         break;
   214 
   215         /* Key release? */
   216     case KeyRelease:{
   217             KeyCode keycode = xevent.xkey.keycode;
   218 
   219 #ifdef DEBUG_XEVENTS
   220             printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   221 #endif
   222             /* Check to see if this is a repeated key */
   223             if (X11_KeyRepeat(videodata->display, &xevent)) {
   224                 break;
   225             }
   226 
   227             SDL_SendKeyboardKey(videodata->keyboard, SDL_RELEASED,
   228                                 (Uint8) keycode,
   229                                 videodata->keyCodeToSDLKTable[keycode]);
   230         }
   231         break;
   232 
   233         /* Have we been iconified? */
   234     case UnmapNotify:{
   235 #ifdef DEBUG_XEVENTS
   236             printf("UnmapNotify!\n");
   237 #endif
   238             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   239             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MINIMIZED, 0,
   240                                 0);
   241         }
   242         break;
   243 
   244         /* Have we been restored? */
   245     case MapNotify:{
   246 #ifdef DEBUG_XEVENTS
   247             printf("MapNotify!\n");
   248 #endif
   249             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0);
   250             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESTORED, 0,
   251                                 0);
   252         }
   253         break;
   254 
   255         /* Have we been resized or moved? */
   256     case ConfigureNotify:{
   257 #ifdef DEBUG_XEVENTS
   258             printf("ConfigureNotify! (resize: %dx%d)\n",
   259                    xevent.xconfigure.width, xevent.xconfigure.height);
   260 #endif
   261             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MOVED,
   262                                 xevent.xconfigure.x, xevent.xconfigure.y);
   263             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESIZED,
   264                                 xevent.xconfigure.width,
   265                                 xevent.xconfigure.height);
   266         }
   267         break;
   268 
   269         /* Have we been requested to quit (or another client message?) */
   270     case ClientMessage:{
   271             if ((xevent.xclient.format == 32) &&
   272                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   273 
   274                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_CLOSE, 0,
   275                                     0);
   276             }
   277         }
   278         break;
   279 
   280         /* Do we need to refresh ourselves? */
   281     case Expose:{
   282 #ifdef DEBUG_XEVENTS
   283             printf("Expose (count = %d)\n", xevent.xexpose.count);
   284 #endif
   285             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_EXPOSED, 0,
   286                                 0);
   287         }
   288         break;
   289 
   290     default:{
   291 #ifdef DEBUG_XEVENTS
   292             printf("Unhandled event %d\n", xevent.type);
   293 #endif
   294         }
   295         break;
   296     }
   297 }
   298 
   299 /* Ack!  XPending() actually performs a blocking read if no events available */
   300 int
   301 X11_Pending(Display * display)
   302 {
   303     /* Flush the display connection and look to see if events are queued */
   304     XFlush(display);
   305     if (XEventsQueued(display, QueuedAlready)) {
   306         return (1);
   307     }
   308 
   309     /* More drastic measures are required -- see if X is ready to talk */
   310     {
   311         static struct timeval zero_time;        /* static == 0 */
   312         int x11_fd;
   313         fd_set fdset;
   314 
   315         x11_fd = ConnectionNumber(display);
   316         FD_ZERO(&fdset);
   317         FD_SET(x11_fd, &fdset);
   318         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   319             return (XPending(display));
   320         }
   321     }
   322 
   323     /* Oh well, nothing is ready .. */
   324     return (0);
   325 }
   326 
   327 void
   328 X11_PumpEvents(_THIS)
   329 {
   330     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   331 
   332     /* Keep processing pending events */
   333     while (X11_Pending(data->display)) {
   334         X11_DispatchEvent(_this);
   335     }
   336 }
   337 
   338 void
   339 X11_SaveScreenSaver(Display * display, int *saved_timeout, BOOL * dpms)
   340 {
   341     int timeout, interval, prefer_blank, allow_exp;
   342     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   343     *saved_timeout = timeout;
   344 
   345 #if SDL_VIDEO_DRIVER_X11_DPMS
   346     if (SDL_X11_HAVE_DPMS) {
   347         int dummy;
   348         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   349             CARD16 state;
   350             DPMSInfo(display, &state, dpms);
   351         }
   352     }
   353 #else
   354     *dpms = 0;
   355 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   356 }
   357 
   358 void
   359 X11_DisableScreenSaver(Display * display)
   360 {
   361     int timeout, interval, prefer_blank, allow_exp;
   362     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   363     timeout = 0;
   364     XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
   365 
   366 #if SDL_VIDEO_DRIVER_X11_DPMS
   367     if (SDL_X11_HAVE_DPMS) {
   368         int dummy;
   369         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   370             DPMSDisable(display);
   371         }
   372     }
   373 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   374 }
   375 
   376 void
   377 X11_RestoreScreenSaver(Display * display, int saved_timeout, BOOL dpms)
   378 {
   379     int timeout, interval, prefer_blank, allow_exp;
   380     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   381     timeout = saved_timeout;
   382     XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
   383 
   384 #if SDL_VIDEO_DRIVER_X11_DPMS
   385     if (SDL_X11_HAVE_DPMS) {
   386         int dummy;
   387         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   388             if (dpms) {
   389                 DPMSEnable(display);
   390             }
   391         }
   392     }
   393 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   394 }
   395 
   396 /* vi: set ts=4 sw=4 expandtab: */