src/video/x11/SDL_x11events.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 27 Jul 2006 06:53:23 +0000
changeset 1951 7177581dc9fa
child 2046 da8332c8f480
permissions -rw-r--r--
Initial work on X11 window code in.
     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 "SDL_syswm.h"
    25 #include "SDL_x11video.h"
    26 #include "../../events/SDL_events_c.h"
    27 
    28 
    29 static void
    30 X11_DispatchEvent(_THIS)
    31 {
    32     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    33     SDL_WindowData *data;
    34     XEvent xevent;
    35     int i;
    36 
    37     SDL_zero(xevent);           /* valgrind fix. --ryan. */
    38     XNextEvent(videodata->display, &xevent);
    39 
    40     /* Send a SDL_SYSWMEVENT if the application wants them */
    41     if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) {
    42         SDL_SysWMmsg wmmsg;
    43 
    44         SDL_VERSION(&wmmsg.version);
    45         wmmsg.subsystem = SDL_SYSWM_X11;
    46         wmmsg.event.xevent = xevent;
    47         SDL_SendSysWMEvent(&wmmsg);
    48     }
    49 
    50     data = NULL;
    51     for (i = 0; i < videodata->numwindows; ++i) {
    52         if (videodata->windowlist[i]->window == xevent.xany.window) {
    53             data = videodata->windowlist[i];
    54         }
    55     }
    56     if (!data) {
    57         return;
    58     }
    59 
    60     switch (xevent.type) {
    61 
    62         /* Gaining mouse coverage? */
    63     case EnterNotify:{
    64 #ifdef DEBUG_XEVENTS
    65             printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x,
    66                    xevent.xcrossing.y);
    67             if (xevent.xcrossing.mode == NotifyGrab)
    68                 printf("Mode: NotifyGrab\n");
    69             if (xevent.xcrossing.mode == NotifyUngrab)
    70                 printf("Mode: NotifyUngrab\n");
    71 #endif
    72             if ((xevent.xcrossing.mode != NotifyGrab) &&
    73                 (xevent.xcrossing.mode != NotifyUngrab)) {
    74                 SDL_SetMouseFocus(videodata->mouse, data->windowID);
    75                 SDL_SendMouseMotion(videodata->mouse, 0, xevent.xcrossing.x,
    76                                     xevent.xcrossing.y);
    77             }
    78         }
    79         break;
    80 
    81         /* Losing mouse coverage? */
    82     case LeaveNotify:{
    83 #ifdef DEBUG_XEVENTS
    84             printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x,
    85                    xevent.xcrossing.y);
    86             if (xevent.xcrossing.mode == NotifyGrab)
    87                 printf("Mode: NotifyGrab\n");
    88             if (xevent.xcrossing.mode == NotifyUngrab)
    89                 printf("Mode: NotifyUngrab\n");
    90 #endif
    91             if ((xevent.xcrossing.mode != NotifyGrab) &&
    92                 (xevent.xcrossing.mode != NotifyUngrab) &&
    93                 (xevent.xcrossing.detail != NotifyInferior)) {
    94                 SDL_SendMouseMotion(videodata->mouse, 0,
    95                                     xevent.xcrossing.x, xevent.xcrossing.y);
    96                 SDL_SetMouseFocus(videodata->mouse, 0);
    97             }
    98         }
    99         break;
   100 
   101         /* Gaining input focus? */
   102     case FocusIn:{
   103 #ifdef DEBUG_XEVENTS
   104             printf("FocusIn!\n");
   105 #endif
   106             SDL_SetKeyboardFocus(videodata->keyboard, data->windowID);
   107 #ifdef X_HAVE_UTF8_STRING
   108             if (data->ic) {
   109                 XSetICFocus(data->ic);
   110             }
   111 #endif
   112         }
   113         break;
   114 
   115         /* Losing input focus? */
   116     case FocusOut:{
   117 #ifdef DEBUG_XEVENTS
   118             printf("FocusOut!\n");
   119 #endif
   120             SDL_SetKeyboardFocus(videodata->keyboard, 0);
   121 #ifdef X_HAVE_UTF8_STRING
   122             if (data->ic) {
   123                 XUnsetICFocus(data->ic);
   124             }
   125 #endif
   126         }
   127         break;
   128 
   129         /* Generated upon EnterWindow and FocusIn */
   130     case KeymapNotify:{
   131 #ifdef DEBUG_XEVENTS
   132             printf("KeymapNotify!\n");
   133 #endif
   134             /* FIXME:
   135                X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   136              */
   137         }
   138         break;
   139 
   140         /* Mouse motion? */
   141     case MotionNotify:{
   142 #ifdef DEBUG_MOTION
   143             printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
   144 #endif
   145             SDL_SendMouseMotion(videodata->mouse, 0, xevent.xmotion.x,
   146                                 xevent.xmotion.y);
   147         }
   148         break;
   149 
   150         /* Mouse button press? */
   151     case ButtonPress:{
   152             SDL_SendMouseButton(videodata->mouse, SDL_PRESSED,
   153                                 xevent.xbutton.button);
   154         }
   155         break;
   156 
   157         /* Mouse button release? */
   158     case ButtonRelease:{
   159             SDL_SendMouseButton(videodata->mouse, SDL_RELEASED,
   160                                 xevent.xbutton.button);
   161         }
   162         break;
   163 
   164         /* Key press? */
   165     case KeyPress:{
   166 #if 0                           /* FIXME */
   167             static SDL_keysym saved_keysym;
   168             SDL_keysym keysym;
   169             KeyCode keycode = xevent.xkey.keycode;
   170 
   171 #ifdef DEBUG_XEVENTS
   172             printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   173 #endif
   174             /* Get the translated SDL virtual keysym */
   175             if (keycode) {
   176                 keysym.scancode = keycode;
   177                 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
   178                 keysym.mod = KMOD_NONE;
   179                 keysym.unicode = 0;
   180             } else {
   181                 keysym = saved_keysym;
   182             }
   183 
   184             /* If we're not doing translation, we're done! */
   185             if (!SDL_TranslateUNICODE) {
   186                 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   187                 break;
   188             }
   189 
   190             if (XFilterEvent(&xevent, None)) {
   191                 if (xevent.xkey.keycode) {
   192                     posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   193                 } else {
   194                     /* Save event to be associated with IM text
   195                        In 1.3 we'll have a text event instead.. */
   196                     saved_keysym = keysym;
   197                 }
   198                 break;
   199             }
   200 
   201             /* Look up the translated value for the key event */
   202 #ifdef X_HAVE_UTF8_STRING
   203             if (data->ic != NULL) {
   204                 static Status state;
   205                 /* A UTF-8 character can be at most 6 bytes */
   206                 char keybuf[6];
   207                 if (Xutf8LookupString(data->ic, &xevent.xkey,
   208                                       keybuf, sizeof(keybuf), NULL, &state)) {
   209                     keysym.unicode = Utf8ToUcs4((Uint8 *) keybuf);
   210                 }
   211             } else
   212 #endif
   213             {
   214                 static XComposeStatus state;
   215                 char keybuf[32];
   216 
   217                 if (XLookupString(&xevent.xkey,
   218                                   keybuf, sizeof(keybuf), NULL, &state)) {
   219                     /*
   220                      * FIXME: XLookupString() may yield more than one
   221                      * character, so we need a mechanism to allow for
   222                      * this (perhaps null keypress events with a
   223                      * unicode value)
   224                      */
   225                     keysym.unicode = (Uint8) keybuf[0];
   226                 }
   227             }
   228             posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   229 #endif // 0
   230         }
   231         break;
   232 
   233         /* Key release? */
   234     case KeyRelease:{
   235 #if 0                           /* FIXME */
   236             SDL_keysym keysym;
   237             KeyCode keycode = xevent.xkey.keycode;
   238 
   239 #ifdef DEBUG_XEVENTS
   240             printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   241 #endif
   242             /* Check to see if this is a repeated key */
   243             if (X11_KeyRepeat(SDL_Display, &xevent)) {
   244                 break;
   245             }
   246 
   247             /* Get the translated SDL virtual keysym */
   248             keysym.scancode = keycode;
   249             keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
   250             keysym.mod = KMOD_NONE;
   251             keysym.unicode = 0;
   252 
   253             posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym);
   254 #endif // 0
   255         }
   256         break;
   257 
   258         /* Have we been iconified? */
   259     case UnmapNotify:{
   260 #ifdef DEBUG_XEVENTS
   261             printf("UnmapNotify!\n");
   262 #endif
   263             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   264             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MINIMIZED, 0,
   265                                 0);
   266         }
   267         break;
   268 
   269         /* Have we been restored? */
   270     case MapNotify:{
   271 #ifdef DEBUG_XEVENTS
   272             printf("MapNotify!\n");
   273 #endif
   274             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0);
   275             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESTORED, 0,
   276                                 0);
   277         }
   278         break;
   279 
   280         /* Have we been resized or moved? */
   281     case ConfigureNotify:{
   282 #ifdef DEBUG_XEVENTS
   283             printf("ConfigureNotify! (resize: %dx%d)\n",
   284                    xevent.xconfigure.width, xevent.xconfigure.height);
   285 #endif
   286             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MOVED,
   287                                 xevent.xconfigure.x, xevent.xconfigure.y);
   288             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESIZED,
   289                                 xevent.xconfigure.width,
   290                                 xevent.xconfigure.height);
   291         }
   292         break;
   293 
   294         /* Have we been requested to quit (or another client message?) */
   295     case ClientMessage:{
   296             if ((xevent.xclient.format == 32) &&
   297                 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
   298 
   299                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_CLOSE, 0,
   300                                     0);
   301             }
   302         }
   303         break;
   304 
   305         /* Do we need to refresh ourselves? */
   306     case Expose:{
   307 #ifdef DEBUG_XEVENTS
   308             printf("Expose (count = %d)\n", xevent.xexpose.count);
   309 #endif
   310             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_EXPOSED, 0,
   311                                 0);
   312         }
   313         break;
   314 
   315     default:{
   316 #ifdef DEBUG_XEVENTS
   317             printf("Unhandled event %d\n", xevent.type);
   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: */