src/video/x11/SDL_x11events.c
author Bob Pendleton <bob@pendleton.com>
Fri, 07 Mar 2008 20:54:11 +0000
changeset 2325 c7bcf84ba1b9
parent 2324 3202e4826c57
child 2326 133562468ff2
permissions -rw-r--r--
Next version of internationalized input for X11. On my machine (famous last words :-) with a US English keyboard and locale I can compose ` and e and get a text
input event with the character รจ. You still get the keypress keyrelease events for the individual keys that go into composing the character.
     1 #define DEBUG_XEVENTS
     2 /*
     3     SDL - Simple DirectMedia Layer
     4     Copyright (C) 1997-2006 Sam Lantinga
     5 
     6     This library is free software; you can redistribute it and/or
     7     modify it under the terms of the GNU Lesser General Public
     8     License as published by the Free Software Foundation; either
     9     version 2.1 of the License, or (at your option) any later version.
    10 
    11     This library is distributed in the hope that it will be useful,
    12     but WITHOUT ANY WARRANTY; without even the implied warranty of
    13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    14     Lesser General Public License for more details.
    15 
    16     You should have received a copy of the GNU Lesser General Public
    17     License along with this library; if not, write to the Free Software
    18     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    19 
    20     Sam Lantinga
    21     slouken@libsdl.org
    22 */
    23 #include "SDL_config.h"
    24 
    25 #include <sys/types.h>
    26 #include <sys/time.h>
    27 #include <unistd.h>
    28 
    29 #include "SDL_syswm.h"
    30 #include "SDL_x11video.h"
    31 #include "../../events/SDL_events_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 #ifdef DEBUG_XEVENTS
    48         printf("Filtered event of type = 0x%X\n", xevent.type);
    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 
    77     switch (xevent.type) {
    78 
    79         /* Gaining mouse coverage? */
    80     case EnterNotify:{
    81 #ifdef DEBUG_XEVENTS
    82             printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x,
    83                    xevent.xcrossing.y);
    84             if (xevent.xcrossing.mode == NotifyGrab)
    85                 printf("Mode: NotifyGrab\n");
    86             if (xevent.xcrossing.mode == NotifyUngrab)
    87                 printf("Mode: NotifyUngrab\n");
    88 #endif
    89             if ((xevent.xcrossing.mode != NotifyGrab) &&
    90                 (xevent.xcrossing.mode != NotifyUngrab)) {
    91                 SDL_SetMouseFocus(videodata->mouse, data->windowID);
    92                 SDL_SendMouseMotion(videodata->mouse, 0, xevent.xcrossing.x,
    93                                     xevent.xcrossing.y);
    94             }
    95         }
    96         break;
    97 
    98         /* Losing mouse coverage? */
    99     case LeaveNotify:{
   100 #ifdef DEBUG_XEVENTS
   101             printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x,
   102                    xevent.xcrossing.y);
   103             if (xevent.xcrossing.mode == NotifyGrab)
   104                 printf("Mode: NotifyGrab\n");
   105             if (xevent.xcrossing.mode == NotifyUngrab)
   106                 printf("Mode: NotifyUngrab\n");
   107 #endif
   108             if ((xevent.xcrossing.mode != NotifyGrab) &&
   109                 (xevent.xcrossing.mode != NotifyUngrab) &&
   110                 (xevent.xcrossing.detail != NotifyInferior)) {
   111                 SDL_SendMouseMotion(videodata->mouse, 0,
   112                                     xevent.xcrossing.x, xevent.xcrossing.y);
   113                 SDL_SetMouseFocus(videodata->mouse, 0);
   114             }
   115         }
   116         break;
   117 
   118         /* Gaining input focus? */
   119     case FocusIn:{
   120 #ifdef DEBUG_XEVENTS
   121             printf("FocusIn!\n");
   122 #endif
   123             SDL_SetKeyboardFocus(videodata->keyboard, data->windowID);
   124 #ifdef X_HAVE_UTF8_STRING
   125             if (data->ic) {
   126                 XSetICFocus(data->ic);
   127             }
   128 #endif
   129         }
   130         break;
   131 
   132         /* Losing input focus? */
   133     case FocusOut:{
   134 #ifdef DEBUG_XEVENTS
   135             printf("FocusOut!\n");
   136 #endif
   137             SDL_SetKeyboardFocus(videodata->keyboard, 0);
   138 #ifdef X_HAVE_UTF8_STRING
   139             if (data->ic) {
   140                 XUnsetICFocus(data->ic);
   141             }
   142 #endif
   143         }
   144         break;
   145 
   146         /* Generated upon EnterWindow and FocusIn */
   147     case KeymapNotify:{
   148 #ifdef DEBUG_XEVENTS
   149             printf("KeymapNotify!\n");
   150 #endif
   151             /* FIXME:
   152                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   153              */
   154         }
   155         break;
   156 
   157         /* Has the keyboard layout changed? */
   158     case MappingNotify:{
   159 #ifdef DEBUG_XEVENTS
   160             printf("MappingNotify!\n");
   161 #endif
   162             X11_UpdateKeymap(_this);
   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             KeySym keysym = NoSymbol;
   194             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
   195             Status status = 0;
   196 
   197 #ifdef DEBUG_XEVENTS
   198             printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   199 #endif
   200             SDL_SendKeyboardKey(videodata->keyboard, SDL_PRESSED,
   201                                 videodata->key_layout[keycode]);
   202 #if 0
   203             if (videodata->key_layout[keycode] == SDLK_UNKNOWN) {
   204                 int min_keycode, max_keycode;
   205                 XDisplayKeycodes(videodata->display, &min_keycode,
   206                                  &max_keycode);
   207                 keysym = XKeycodeToKeysym(videodata->display, keycode, 0);
   208                 fprintf(stderr,
   209                         "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",
   210                         keycode, keycode - min_keycode, keysym,
   211                         XKeysymToString(keysym));
   212             }
   213 #endif
   214             /* */
   215             SDL_zero(text);
   216 #ifdef X_HAVE_UTF8_STRING
   217             if (data->ic) {
   218                 Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
   219                                   &keysym, status);
   220             }
   221 #else
   222             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
   223 #endif
   224             if (*text) {
   225                 printf("Sending text event %s\n", text);
   226                 SDL_SendKeyboardText(videodata->keyboard, text);
   227             }
   228         }
   229         break;
   230 
   231         /* Key release? */
   232     case KeyRelease:{
   233             KeyCode keycode = xevent.xkey.keycode;
   234 
   235 #ifdef DEBUG_XEVENTS
   236             printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   237 #endif
   238             SDL_SendKeyboardKey(videodata->keyboard, SDL_RELEASED,
   239                                 videodata->key_layout[keycode]);
   240         }
   241         break;
   242 
   243         /* Have we been iconified? */
   244     case UnmapNotify:{
   245 #ifdef DEBUG_XEVENTS
   246             printf("UnmapNotify!\n");
   247 #endif
   248             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   249             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MINIMIZED, 0,
   250                                 0);
   251         }
   252         break;
   253 
   254         /* Have we been restored? */
   255     case MapNotify:{
   256 #ifdef DEBUG_XEVENTS
   257             printf("MapNotify!\n");
   258 #endif
   259             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0);
   260             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESTORED, 0,
   261                                 0);
   262         }
   263         break;
   264 
   265         /* Have we been resized or moved? */
   266     case ConfigureNotify:{
   267 #ifdef DEBUG_XEVENTS
   268             printf("ConfigureNotify! (resize: %dx%d)\n",
   269                    xevent.xconfigure.width, xevent.xconfigure.height);
   270 #endif
   271             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MOVED,
   272                                 xevent.xconfigure.x, xevent.xconfigure.y);
   273             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESIZED,
   274                                 xevent.xconfigure.width,
   275                                 xevent.xconfigure.height);
   276         }
   277         break;
   278 
   279         /* Have we been requested to quit (or another client message?) */
   280     case ClientMessage:{
   281             if ((xevent.xclient.format == 32) &&
   282                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   283 
   284                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_CLOSE, 0,
   285                                     0);
   286             }
   287         }
   288         break;
   289 
   290         /* Do we need to refresh ourselves? */
   291     case Expose:{
   292 #ifdef DEBUG_XEVENTS
   293             printf("Expose (count = %d)\n", xevent.xexpose.count);
   294 #endif
   295             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_EXPOSED, 0,
   296                                 0);
   297         }
   298         break;
   299 
   300     default:{
   301 #ifdef DEBUG_XEVENTS
   302             printf("Unhandled event %d\n", xevent.type);
   303 #endif
   304         }
   305         break;
   306     }
   307 }
   308 
   309 /* Ack!  XPending() actually performs a blocking read if no events available */
   310 int
   311 X11_Pending(Display * display)
   312 {
   313     /* Flush the display connection and look to see if events are queued */
   314     XFlush(display);
   315     if (XEventsQueued(display, QueuedAlready)) {
   316         return (1);
   317     }
   318 
   319     /* More drastic measures are required -- see if X is ready to talk */
   320     {
   321         static struct timeval zero_time;        /* static == 0 */
   322         int x11_fd;
   323         fd_set fdset;
   324 
   325         x11_fd = ConnectionNumber(display);
   326         FD_ZERO(&fdset);
   327         FD_SET(x11_fd, &fdset);
   328         if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
   329             return (XPending(display));
   330         }
   331     }
   332 
   333     /* Oh well, nothing is ready .. */
   334     return (0);
   335 }
   336 
   337 void
   338 X11_PumpEvents(_THIS)
   339 {
   340     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   341 
   342     /* Keep processing pending events */
   343     while (X11_Pending(data->display)) {
   344         X11_DispatchEvent(_this);
   345     }
   346 }
   347 
   348 void
   349 X11_SaveScreenSaver(Display * display, int *saved_timeout, BOOL * dpms)
   350 {
   351     int timeout, interval, prefer_blank, allow_exp;
   352     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   353     *saved_timeout = timeout;
   354 
   355 #if SDL_VIDEO_DRIVER_X11_DPMS
   356     if (SDL_X11_HAVE_DPMS) {
   357         int dummy;
   358         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   359             CARD16 state;
   360             DPMSInfo(display, &state, dpms);
   361         }
   362     }
   363 #else
   364     *dpms = 0;
   365 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   366 }
   367 
   368 void
   369 X11_DisableScreenSaver(Display * display)
   370 {
   371     int timeout, interval, prefer_blank, allow_exp;
   372     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   373     timeout = 0;
   374     XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
   375 
   376 #if SDL_VIDEO_DRIVER_X11_DPMS
   377     if (SDL_X11_HAVE_DPMS) {
   378         int dummy;
   379         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   380             DPMSDisable(display);
   381         }
   382     }
   383 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   384 }
   385 
   386 void
   387 X11_RestoreScreenSaver(Display * display, int saved_timeout, BOOL dpms)
   388 {
   389     int timeout, interval, prefer_blank, allow_exp;
   390     XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
   391     timeout = saved_timeout;
   392     XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
   393 
   394 #if SDL_VIDEO_DRIVER_X11_DPMS
   395     if (SDL_X11_HAVE_DPMS) {
   396         int dummy;
   397         if (DPMSQueryExtension(display, &dummy, &dummy)) {
   398             if (dpms) {
   399                 DPMSEnable(display);
   400             }
   401         }
   402     }
   403 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
   404 }
   405 
   406 /* vi: set ts=4 sw=4 expandtab: */