Edit

kc3-lang/SDL/src/video/x11/SDL_x11events.c

Branch :

  • Show log

    Commit

  • Author : Gabriel Jacobo
    Date : 2013-08-21 10:12:16
    Hash : 2490166d
    Message : Fixes for -Wdeclaration-after-statement

  • src/video/x11/SDL_x11events.c
  • /*
      Simple DirectMedia Layer
      Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
    
      This software is provided 'as-is', without any express or implied
      warranty.  In no event will the authors be held liable for any damages
      arising from the use of this software.
    
      Permission is granted to anyone to use this software for any purpose,
      including commercial applications, and to alter it and redistribute it
      freely, subject to the following restrictions:
    
      1. The origin of this software must not be misrepresented; you must not
         claim that you wrote the original software. If you use this software
         in a product, an acknowledgment in the product documentation would be
         appreciated but is not required.
      2. Altered source versions must be plainly marked as such, and must not be
         misrepresented as being the original software.
      3. This notice may not be removed or altered from any source distribution.
    */
    #include "SDL_config.h"
    
    #if SDL_VIDEO_DRIVER_X11
    
    #include <sys/types.h>
    #include <sys/time.h>
    #include <signal.h>
    #include <unistd.h>
    #include <limits.h> /* For INT_MAX */
    
    #include "SDL_x11video.h"
    #include "SDL_x11video.h"
    #include "SDL_x11touch.h"
    #include "SDL_x11xinput2.h"
    #include "../../events/SDL_events_c.h"
    #include "../../events/SDL_mouse_c.h"
    #include "../../events/SDL_touch_c.h"
    
    #include "SDL_timer.h"
    #include "SDL_syswm.h"
    
    #include <stdio.h>
    
    typedef struct {
        unsigned char *data;
        int format, count;
        Atom type;
    } SDL_x11Prop;
    
    /* Reads property
       Must call XFree on results
     */
    static void X11_ReadProperty(SDL_x11Prop *p, Display *disp, Window w, Atom prop)
    {
        unsigned char *ret=NULL;
        Atom type;
        int fmt;
        unsigned long count;
        unsigned long bytes_left;
        int bytes_fetch = 0;
    
        do {
            if (ret != 0) XFree(ret);
            XGetWindowProperty(disp, w, prop, 0, bytes_fetch, False, AnyPropertyType, &type, &fmt, &count, &bytes_left, &ret);
            bytes_fetch += bytes_left;
        } while (bytes_left != 0);
    
        p->data=ret;
        p->format=fmt;
        p->count=count;
        p->type=type;
    }
    
    /* Find text-uri-list in a list of targets and return it's atom
       if available, else return None */
    static Atom X11_PickTarget(Display *disp, Atom list[], int list_count)
    {
        Atom request = None;
        char *name;
        int i;
        for (i=0; i < list_count && request == None; i++) {
            name = XGetAtomName(disp, list[i]);
            if (strcmp("text/uri-list", name)==0) request = list[i];
            XFree(name);
        }
        return request;
    }
    
    /* Wrapper for X11_PickTarget for a maximum of three targets, a special
       case in the Xdnd protocol */
    static Atom X11_PickTargetFromAtoms(Display *disp, Atom a0, Atom a1, Atom a2)
    {
        int count=0;
        Atom atom[3];
        if (a0 != None) atom[count++] = a0;
        if (a1 != None) atom[count++] = a1;
        if (a2 != None) atom[count++] = a2;
        return X11_PickTarget(disp, atom, count);
    }
    /* #define DEBUG_XEVENTS */
    
    struct KeyRepeatCheckData
    {
        XEvent *event;
        SDL_bool found;
    };
    
    static Bool X11_KeyRepeatCheckIfEvent(Display *display, XEvent *chkev,
        XPointer arg)
    {
        struct KeyRepeatCheckData *d = (struct KeyRepeatCheckData *) arg;
        if (chkev->type == KeyPress &&
            chkev->xkey.keycode == d->event->xkey.keycode &&
            chkev->xkey.time - d->event->xkey.time < 2)
            d->found = SDL_TRUE;
        return False;
    }
    
    /* Check to see if this is a repeated key.
       (idea shamelessly lifted from GII -- thanks guys! :)
     */
    static SDL_bool X11_KeyRepeat(Display *display, XEvent *event)
    {
        XEvent dummyev;
        struct KeyRepeatCheckData d;
        d.event = event;
        d.found = SDL_FALSE;
        if (XPending(display))
            XCheckIfEvent(display, &dummyev, X11_KeyRepeatCheckIfEvent,
                (XPointer) &d);
        return d.found;
    }
    
    static Bool X11_IsWheelCheckIfEvent(Display *display, XEvent *chkev,
        XPointer arg)
    {
        XEvent *event = (XEvent *) arg;
        if (chkev->type == ButtonRelease &&
            chkev->xbutton.button == event->xbutton.button &&
            chkev->xbutton.time == event->xbutton.time)
            return True;
        return False;
    }
    
    static SDL_bool X11_IsWheelEvent(Display * display,XEvent * event,int * ticks)
    {
        XEvent relevent;
        if (XPending(display)) {
            /* according to the xlib docs, no specific mouse wheel events exist.
               however, mouse wheel events trigger a button press and a button release
               immediately. thus, checking if the same button was released at the same
               time as it was pressed, should be an adequate hack to derive a mouse
               wheel event. */
            if (XCheckIfEvent(display, &relevent, X11_IsWheelCheckIfEvent,
                (XPointer) event)) {
    
                /* by default, X11 only knows 5 buttons. on most 3 button + wheel mouse,
                   Button4 maps to wheel up, Button5 maps to wheel down. */
                if (event->xbutton.button == Button4) {
                    *ticks = 1;
                }
                else if (event->xbutton.button == Button5) {
                    *ticks = -1;
                }
                return SDL_TRUE;
            }
        }
        return SDL_FALSE;
    }
    
    /* Convert URI to local filename
       return filename if possible, else NULL
    */
    static char* X11_URIToLocal(char* uri) {
        char *file = NULL;
        SDL_bool local;
    
        if (memcmp(uri,"file:/",6) == 0) uri += 6;      /* local file? */
        else if (strstr(uri,":/") != NULL) return file; /* wrong scheme */
    
        local = uri[0] != '/' || ( uri[0] != '\0' && uri[1] == '/' );
    
        /* got a hostname? */
        if ( !local && uri[0] == '/' && uri[2] != '/' ) {
          char* hostname_end = strchr( uri+1, '/' );
          if ( hostname_end != NULL ) {
              char hostname[ 257 ];
              if ( gethostname( hostname, 255 ) == 0 ) {
                hostname[ 256 ] = '\0';
                if ( memcmp( uri+1, hostname, hostname_end - ( uri+1 )) == 0 ) {
                    uri = hostname_end + 1;
                    local = SDL_TRUE;
                }
              }
          }
        }
        if ( local ) {
          file = uri;
          if ( uri[1] == '/' ) {
              file++;
          } else {
              file--;
          }
        }
        return file;
    }
    
    #if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
    static void X11_HandleGenericEvent(SDL_VideoData *videodata,XEvent event)
    {
        /* event is a union, so cookie == &event, but this is type safe. */
        XGenericEventCookie *cookie = &event.xcookie;
        if (XGetEventData(videodata->display, cookie)) {
            X11_HandleXinput2Event(videodata, cookie);
            XFreeEventData(videodata->display, cookie);
        }
    }
    #endif /* SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS */
    
    
    static void
    X11_DispatchFocusIn(SDL_WindowData *data)
    {
    #ifdef DEBUG_XEVENTS
        printf("window %p: Dispatching FocusIn\n", data);
    #endif
        SDL_SetKeyboardFocus(data->window);
    #ifdef X_HAVE_UTF8_STRING
        if (data->ic) {
            XSetICFocus(data->ic);
        }
    #endif
    }
    
    static void
    X11_DispatchFocusOut(SDL_WindowData *data)
    {
    #ifdef DEBUG_XEVENTS
        printf("window %p: Dispatching FocusOut\n", data);
    #endif
        SDL_SetKeyboardFocus(NULL);
    #ifdef X_HAVE_UTF8_STRING
        if (data->ic) {
            XUnsetICFocus(data->ic);
        }
    #endif
    }
    
    static void
    X11_DispatchMapNotify(SDL_WindowData *data)
    {
        SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
        SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
    }
    
    static void
    X11_DispatchUnmapNotify(SDL_WindowData *data)
    {
        SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
        SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    }
    
    static void
    X11_DispatchEvent(_THIS)
    {
        SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
        Display *display = videodata->display;
        SDL_WindowData *data;
        XEvent xevent;
        int i;
        XClientMessageEvent m;
    
        SDL_zero(xevent);           /* valgrind fix. --ryan. */
        XNextEvent(display, &xevent);
    
        /* filter events catchs XIM events and sends them to the correct
           handler */
        if (XFilterEvent(&xevent, None) == True) {
    #if 0
            printf("Filtered event type = %d display = %d window = %d\n",
                   xevent.type, xevent.xany.display, xevent.xany.window);
    #endif
            return;
        }
    
        /* Send a SDL_SYSWMEVENT if the application wants them */
        if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
            SDL_SysWMmsg wmmsg;
    
            SDL_VERSION(&wmmsg.version);
            wmmsg.subsystem = SDL_SYSWM_X11;
            wmmsg.msg.x11.event = xevent;
            SDL_SendSysWMEvent(&wmmsg);
        }
    
    #if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
        if(xevent.type == GenericEvent) {
            X11_HandleGenericEvent(videodata,xevent);
            return;
        }
    #endif
    
    #if 0
        printf("type = %d display = %d window = %d\n",
               xevent.type, xevent.xany.display, xevent.xany.window);
    #endif
    
        data = NULL;
        if (videodata && videodata->windowlist) {
            for (i = 0; i < videodata->numwindows; ++i) {
                if ((videodata->windowlist[i] != NULL) &&
                    (videodata->windowlist[i]->xwindow == xevent.xany.window)) {
                    data = videodata->windowlist[i];
                    break;
                }
            }
        }
        if (!data) {
            return;
        }
    
        switch (xevent.type) {
    
            /* Gaining mouse coverage? */
        case EnterNotify:{
    #ifdef DEBUG_XEVENTS
                printf("window %p: EnterNotify! (%d,%d,%d)\n", data,
                       xevent.xcrossing.x,
                       xevent.xcrossing.y,
                       xevent.xcrossing.mode);
                if (xevent.xcrossing.mode == NotifyGrab)
                    printf("Mode: NotifyGrab\n");
                if (xevent.xcrossing.mode == NotifyUngrab)
                    printf("Mode: NotifyUngrab\n");
    #endif
                SDL_SetMouseFocus(data->window);
    
                if (!SDL_GetMouse()->relative_mode) {
                    SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
                }
            }
            break;
            /* Losing mouse coverage? */
        case LeaveNotify:{
    #ifdef DEBUG_XEVENTS
                printf("window %p: LeaveNotify! (%d,%d,%d)\n", data,
                       xevent.xcrossing.x,
                       xevent.xcrossing.y,
                       xevent.xcrossing.mode);
                if (xevent.xcrossing.mode == NotifyGrab)
                    printf("Mode: NotifyGrab\n");
                if (xevent.xcrossing.mode == NotifyUngrab)
                    printf("Mode: NotifyUngrab\n");
    #endif
                if (!SDL_GetMouse()->relative_mode) {
                    SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
                }
    
                if (xevent.xcrossing.mode != NotifyGrab &&
                    xevent.xcrossing.mode != NotifyUngrab &&
                    xevent.xcrossing.detail != NotifyInferior) {
                    SDL_SetMouseFocus(NULL);
                }
            }
            break;
    
            /* Gaining input focus? */
        case FocusIn:{
                if (xevent.xfocus.detail == NotifyInferior) {
    #ifdef DEBUG_XEVENTS
                    printf("window %p: FocusIn (NotifierInferior, ignoring)\n", data);
    #endif
                    break;
                }
    #ifdef DEBUG_XEVENTS
                printf("window %p: FocusIn!\n", data);
    #endif
                if (data->pending_focus == PENDING_FOCUS_OUT &&
                    data->window == SDL_GetKeyboardFocus()) {
                    /* We want to reset the keyboard here, because we may have
                       missed keyboard messages after our previous FocusOut.
                     */
                    /* Actually, if we do this we clear the ALT key on Unity
                       because it briefly takes focus for their dashboard.
    
                       I think it's better to think the ALT key is held down
                       when it's not, then always lose the ALT modifier on Unity.
                     */
                    /* SDL_ResetKeyboard(); */
                }
                data->pending_focus = PENDING_FOCUS_IN;
                data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME;
            }
            break;
    
            /* Losing input focus? */
        case FocusOut:{
                if (xevent.xfocus.detail == NotifyInferior) {
                    /* We still have focus if a child gets focus */
    #ifdef DEBUG_XEVENTS
                    printf("window %p: FocusOut (NotifierInferior, ignoring)\n", data);
    #endif
                    break;
                }
    #ifdef DEBUG_XEVENTS
                printf("window %p: FocusOut!\n", data);
    #endif
                data->pending_focus = PENDING_FOCUS_OUT;
                data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_OUT_TIME;
            }
            break;
    
            /* Generated upon EnterWindow and FocusIn */
        case KeymapNotify:{
    #ifdef DEBUG_XEVENTS
                printf("window %p: KeymapNotify!\n", data);
    #endif
                /* FIXME:
                   X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
                 */
            }
            break;
    
            /* Has the keyboard layout changed? */
        case MappingNotify:{
    #ifdef DEBUG_XEVENTS
                printf("window %p: MappingNotify!\n", data);
    #endif
                X11_UpdateKeymap(_this);
            }
            break;
    
            /* Key press? */
        case KeyPress:{
                KeyCode keycode = xevent.xkey.keycode;
                KeySym keysym = NoSymbol;
                char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
                Status status = 0;
    
    #ifdef DEBUG_XEVENTS
                printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
    #endif
                SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
    #if 1
                if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
                    int min_keycode, max_keycode;
                    XDisplayKeycodes(display, &min_keycode, &max_keycode);
    #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
                    keysym = XkbKeycodeToKeysym(display, keycode, 0, 0);
    #else
                    keysym = XKeycodeToKeysym(display, keycode, 0);
    #endif
                    fprintf(stderr,
                            "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%lX (%s).\n",
                            keycode, keycode - min_keycode, keysym,
                            XKeysymToString(keysym));
                }
    #endif
                /* */
                SDL_zero(text);
    #ifdef X_HAVE_UTF8_STRING
                if (data->ic) {
                    Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
                                      &keysym, &status);
                }
    #else
                XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
    #endif
                if (*text) {
                    SDL_SendKeyboardText(text);
                }
            }
            break;
    
            /* Key release? */
        case KeyRelease:{
                KeyCode keycode = xevent.xkey.keycode;
    
    #ifdef DEBUG_XEVENTS
                printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
    #endif
                if (X11_KeyRepeat(display, &xevent)) {
                    /* We're about to get a repeated key down, ignore the key up */
                    break;
                }
                SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
            }
            break;
    
            /* Have we been iconified? */
        case UnmapNotify:{
    #ifdef DEBUG_XEVENTS
                printf("window %p: UnmapNotify!\n", data);
    #endif
                X11_DispatchUnmapNotify(data);
            }
            break;
    
            /* Have we been restored? */
        case MapNotify:{
    #ifdef DEBUG_XEVENTS
                printf("window %p: MapNotify!\n", data);
    #endif
                X11_DispatchMapNotify(data);
            }
            break;
    
            /* Have we been resized or moved? */
        case ConfigureNotify:{
    #ifdef DEBUG_XEVENTS
                printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data,
                       xevent.xconfigure.x, xevent.xconfigure.y,
                       xevent.xconfigure.width, xevent.xconfigure.height);
    #endif
                if (xevent.xconfigure.x != data->last_xconfigure.x ||
                    xevent.xconfigure.y != data->last_xconfigure.y) {
                    SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
                                        xevent.xconfigure.x, xevent.xconfigure.y);
                }
                if (xevent.xconfigure.width != data->last_xconfigure.width ||
                    xevent.xconfigure.height != data->last_xconfigure.height) {
                    SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED,
                                        xevent.xconfigure.width,
                                        xevent.xconfigure.height);
                }
                data->last_xconfigure = xevent.xconfigure;
            }
            break;
    
            /* Have we been requested to quit (or another client message?) */
        case ClientMessage:{
    
                int xdnd_version=0;
    
                if (xevent.xclient.message_type == videodata->XdndEnter) {
                    SDL_bool use_list = xevent.xclient.data.l[1] & 1;
                    data->xdnd_source = xevent.xclient.data.l[0];
                    xdnd_version = ( xevent.xclient.data.l[1] >> 24);
                    if (use_list) {
                        /* fetch conversion targets */
                        SDL_x11Prop p;
                        X11_ReadProperty(&p, display, data->xdnd_source, videodata->XdndTypeList);
                        /* pick one */
                        data->xdnd_req = X11_PickTarget(display, (Atom*)p.data, p.count);
                        XFree(p.data);
                    } else {
                        /* pick from list of three */
                        data->xdnd_req = X11_PickTargetFromAtoms(display, xevent.xclient.data.l[2], xevent.xclient.data.l[3], xevent.xclient.data.l[4]);
                    }
                }
                else if (xevent.xclient.message_type == videodata->XdndPosition) {
    
                    /* reply with status */
                    memset(&m, 0, sizeof(XClientMessageEvent));
                    m.type = ClientMessage;
                    m.display = xevent.xclient.display;
                    m.window = xevent.xclient.data.l[0];
                    m.message_type = videodata->XdndStatus;
                    m.format=32;
                    m.data.l[0] = data->xwindow;
                    m.data.l[1] = (data->xdnd_req != None);
                    m.data.l[2] = 0; /* specify an empty rectangle */
                    m.data.l[3] = 0;
                    m.data.l[4] = videodata->XdndActionCopy; /* we only accept copying anyway */
    
                    XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
                    XFlush(display);
                }
                else if(xevent.xclient.message_type == videodata->XdndDrop) {
                    if (data->xdnd_req == None) {
                        /* say again - not interested! */
                        memset(&m, 0, sizeof(XClientMessageEvent));
                        m.type = ClientMessage;
                        m.display = xevent.xclient.display;
                        m.window = xevent.xclient.data.l[0];
                        m.message_type = videodata->XdndFinished;
                        m.format=32;
                        m.data.l[0] = data->xwindow;
                        m.data.l[1] = 0;
                        m.data.l[2] = None; /* fail! */
                        XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
                    } else {
                        /* convert */
                        if(xdnd_version >= 1) {
                            XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, xevent.xclient.data.l[2]);
                        } else {
                            XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, CurrentTime);
                        }
                    }
                }
                else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
                    (xevent.xclient.format == 32) &&
                    (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
                    Window root = DefaultRootWindow(display);
    
    #ifdef DEBUG_XEVENTS
                    printf("window %p: _NET_WM_PING\n", data);
    #endif
                    xevent.xclient.window = root;
                    XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
                    break;
                }
    
                else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
                    (xevent.xclient.format == 32) &&
                    (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
    
    #ifdef DEBUG_XEVENTS
                    printf("window %p: WM_DELETE_WINDOW\n", data);
    #endif
                    SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
                    break;
                }
            }
            break;
    
            /* Do we need to refresh ourselves? */
        case Expose:{
    #ifdef DEBUG_XEVENTS
                printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
    #endif
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
            }
            break;
    
        case MotionNotify:{
                SDL_Mouse *mouse = SDL_GetMouse();
                if(!mouse->relative_mode) {
    #ifdef DEBUG_MOTION
                    printf("window %p: X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
    #endif
    
                    SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y);
                }
            }
            break;
    
        case ButtonPress:{
                int ticks = 0;
                if (X11_IsWheelEvent(display,&xevent,&ticks)) {
                    SDL_SendMouseWheel(data->window, 0, 0, ticks);
                } else {
                    SDL_SendMouseButton(data->window, 0, SDL_PRESSED, xevent.xbutton.button);
                }
            }
            break;
    
        case ButtonRelease:{
                SDL_SendMouseButton(data->window, 0, SDL_RELEASED, xevent.xbutton.button);
            }
            break;
    
        case PropertyNotify:{
    #ifdef DEBUG_XEVENTS
                unsigned char *propdata;
                int status, real_format;
                Atom real_type;
                unsigned long items_read, items_left, i;
    
                char *name = XGetAtomName(display, xevent.xproperty.atom);
                if (name) {
                    printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed");
                    XFree(name);
                }
    
                status = XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata);
                if (status == Success && items_read > 0) {
                    if (real_type == XA_INTEGER) {
                        int *values = (int *)propdata;
    
                        printf("{");
                        for (i = 0; i < items_read; i++) {
                            printf(" %d", values[i]);
                        }
                        printf(" }\n");
                    } else if (real_type == XA_CARDINAL) {
                        if (real_format == 32) {
                            Uint32 *values = (Uint32 *)propdata;
    
                            printf("{");
                            for (i = 0; i < items_read; i++) {
                                printf(" %d", values[i]);
                            }
                            printf(" }\n");
                        } else if (real_format == 16) {
                            Uint16 *values = (Uint16 *)propdata;
    
                            printf("{");
                            for (i = 0; i < items_read; i++) {
                                printf(" %d", values[i]);
                            }
                            printf(" }\n");
                        } else if (real_format == 8) {
                            Uint8 *values = (Uint8 *)propdata;
    
                            printf("{");
                            for (i = 0; i < items_read; i++) {
                                printf(" %d", values[i]);
                            }
                            printf(" }\n");
                        }
                    } else if (real_type == XA_STRING ||
                               real_type == videodata->UTF8_STRING) {
                        printf("{ \"%s\" }\n", propdata);
                    } else if (real_type == XA_ATOM) {
                        Atom *atoms = (Atom *)propdata;
    
                        printf("{");
                        for (i = 0; i < items_read; i++) {
                            char *name = XGetAtomName(display, atoms[i]);
                            if (name) {
                                printf(" %s", name);
                                XFree(name);
                            }
                        }
                        printf(" }\n");
                    } else {
                        char *name = XGetAtomName(display, real_type);
                        printf("Unknown type: %ld (%s)\n", real_type, name ? name : "UNKNOWN");
                        if (name) {
                            XFree(name);
                        }
                    }
                }
                if (status == Success) {
                    XFree(propdata);
                }
    #endif /* DEBUG_XEVENTS */
    
                if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
                    /* Get the new state from the window manager.
                       Compositing window managers can alter visibility of windows
                       without ever mapping / unmapping them, so we handle that here,
                       because they use the NETWM protocol to notify us of changes.
                     */
                    Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window);
                    if ((flags^data->window->flags) & SDL_WINDOW_HIDDEN) {
                        if (flags & SDL_WINDOW_HIDDEN) {
                            X11_DispatchUnmapNotify(data);
                        } else {
                            X11_DispatchMapNotify(data);
                        }
                    }
                }
            }
            break;
    
        /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
        case SelectionRequest: {
                XSelectionRequestEvent *req;
                XEvent sevent;
                int seln_format;
                unsigned long nbytes;
                unsigned long overflow;
                unsigned char *seln_data;
    
                req = &xevent.xselectionrequest;
    #ifdef DEBUG_XEVENTS
                printf("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", data,
                    req->requestor, req->target);
    #endif
    
                SDL_zero(sevent);
                sevent.xany.type = SelectionNotify;
                sevent.xselection.selection = req->selection;
                sevent.xselection.target = None;
                sevent.xselection.property = None;
                sevent.xselection.requestor = req->requestor;
                sevent.xselection.time = req->time;
                if (XGetWindowProperty(display, DefaultRootWindow(display),
                        XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
                        &sevent.xselection.target, &seln_format, &nbytes,
                        &overflow, &seln_data) == Success) {
                    Atom XA_TARGETS = XInternAtom(display, "TARGETS", 0);
                    if (sevent.xselection.target == req->target) {
                        XChangeProperty(display, req->requestor, req->property,
                            sevent.xselection.target, seln_format, PropModeReplace,
                            seln_data, nbytes);
                        sevent.xselection.property = req->property;
                    } else if (XA_TARGETS == req->target) {
                        Atom SupportedFormats[] = { sevent.xselection.target, XA_TARGETS };
                        XChangeProperty(display, req->requestor, req->property,
                            XA_ATOM, 32, PropModeReplace,
                            (unsigned char*)SupportedFormats,
                            sizeof(SupportedFormats)/sizeof(*SupportedFormats));
                        sevent.xselection.property = req->property;
                    }
                    XFree(seln_data);
                }
                XSendEvent(display, req->requestor, False, 0, &sevent);
                XSync(display, False);
            }
            break;
    
        case SelectionNotify: {
    #ifdef DEBUG_XEVENTS
                printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
                    xevent.xselection.requestor, xevent.xselection.target);
    #endif
                Atom target = xevent.xselection.target;
                if (target == data->xdnd_req) {
                    /* read data */
                    SDL_x11Prop p;
                    X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY);
    
                    if (p.format == 8) {
                        SDL_bool expect_lf = SDL_FALSE;
                        char *start = NULL;
                        char *scan = (char*)p.data;
                        char *fn;
                        char *uri;
                        int length = 0;
                        while (p.count--) {
                            if (!expect_lf) {
                                if (*scan == 0x0D) {
                                    expect_lf = SDL_TRUE;
                                }
                                if (start == NULL) {
                                    start = scan;
                                    length = 0;
                                }
                                length++;
                            } else {
                                if (*scan == 0x0A && length > 0) {
                                    uri = SDL_malloc(length--);
                                    SDL_memcpy(uri, start, length);
                                    uri[length] = '\0';
                                    fn = X11_URIToLocal(uri);
                                    if (fn) {
                                        SDL_SendDropFile(fn);
                                    }
                                    SDL_free(uri);
                                }
                                expect_lf = SDL_FALSE;
                                start = NULL;
                            }
                            scan++;
                        }
                    }
    
                    XFree(p.data);
    
                    /* send reply */
                    SDL_memset(&m, 0, sizeof(XClientMessageEvent));
                    m.type = ClientMessage;
                    m.display = display;
                    m.window = data->xdnd_source;
                    m.message_type = videodata->XdndFinished;
                    m.format = 32;
                    m.data.l[0] = data->xwindow;
                    m.data.l[1] = 1;
                    m.data.l[2] = videodata->XdndActionCopy;
                    XSendEvent(display, data->xdnd_source, False, NoEventMask, (XEvent*)&m);
    
                    XSync(display, False);
    
                } else {
                    videodata->selection_waiting = SDL_FALSE;
                }
            }
            break;
    
        default:{
    #ifdef DEBUG_XEVENTS
                printf("window %p: Unhandled event %d\n", data, xevent.type);
    #endif
            }
            break;
        }
    }
    
    static void
    X11_HandleFocusChanges(_THIS)
    {
        SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
        int i;
    
        if (videodata && videodata->windowlist) {
            for (i = 0; i < videodata->numwindows; ++i) {
                SDL_WindowData *data = videodata->windowlist[i];
                if (data && data->pending_focus != PENDING_FOCUS_NONE) {
                    Uint32 now = SDL_GetTicks();
                    if ( (int)(data->pending_focus_time-now) <= 0 ) {
                        if ( data->pending_focus == PENDING_FOCUS_IN ) {
                            X11_DispatchFocusIn(data);
                        } else {
                            X11_DispatchFocusOut(data);
                        }
                        data->pending_focus = PENDING_FOCUS_NONE;
                    }
                }
            }
        }
    }
    /* Ack!  XPending() actually performs a blocking read if no events available */
    static int
    X11_Pending(Display * display)
    {
        /* Flush the display connection and look to see if events are queued */
        XFlush(display);
        if (XEventsQueued(display, QueuedAlready)) {
            return (1);
        }
    
        /* More drastic measures are required -- see if X is ready to talk */
        {
            static struct timeval zero_time;        /* static == 0 */
            int x11_fd;
            fd_set fdset;
    
            x11_fd = ConnectionNumber(display);
            FD_ZERO(&fdset);
            FD_SET(x11_fd, &fdset);
            if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) {
                return (XPending(display));
            }
        }
    
        /* Oh well, nothing is ready .. */
        return (0);
    }
    
    
    /* !!! FIXME: this should be exposed in a header, or something. */
    int SDL_GetNumTouch(void);
    void SDL_dbus_screensaver_tickle(_THIS);
    
    void
    X11_PumpEvents(_THIS)
    {
        SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    
        /* Update activity every 30 seconds to prevent screensaver */
        if (_this->suspend_screensaver) {
            Uint32 now = SDL_GetTicks();
            if (!data->screensaver_activity ||
                (int) (now - data->screensaver_activity) >= 30000) {
                XResetScreenSaver(data->display);
    
                #if SDL_USE_LIBDBUS
                SDL_dbus_screensaver_tickle(_this);
                #endif
    
                data->screensaver_activity = now;
            }
        }
    
        /* Keep processing pending events */
        while (X11_Pending(data->display)) {
            X11_DispatchEvent(_this);
        }
    
        /* FIXME: Only need to do this when there are pending focus changes */
        X11_HandleFocusChanges(_this);
    }
    
    
    void
    X11_SuspendScreenSaver(_THIS)
    {
    #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
        SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
        int dummy;
        int major_version, minor_version;
    
        if (SDL_X11_HAVE_XSS) {
            /* XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
            if (!XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
                !XScreenSaverQueryVersion(data->display,
                                          &major_version, &minor_version) ||
                major_version < 1 || (major_version == 1 && minor_version < 1)) {
                return;
            }
    
            XScreenSaverSuspend(data->display, _this->suspend_screensaver);
            XResetScreenSaver(data->display);
        }
    #endif
    
    #if SDL_USE_LIBDBUS
        if (_this->suspend_screensaver) {
            SDL_dbus_screensaver_tickle(_this);
        }
    #endif
    }
    
    #endif /* SDL_VIDEO_DRIVER_X11 */
    
    /* vi: set ts=4 sw=4 expandtab: */