-/* Spaceball support for Linux.\r
- * Written by John Tsiombikas <nuclear@member.fsf.org>\r
- * Copied for Platform code by Evan Felix <karcaw at gmail.com>\r
- * Creation date: Thur Feb 2 2012\r
- *\r
- * This code supports 3Dconnexion's 6-dof space-whatever devices.\r
- * It can communicate with either the proprietary 3Dconnexion daemon (3dxsrv)\r
- * free spacenavd (http://spacenav.sourceforge.net), through the "standard"\r
- * magellan X-based protocol.\r
- */\r
-\r
-#include <GL/freeglut.h>\r
-#include "../Common/freeglut_internal.h"\r
-\r
-#include <X11/Xlib.h>\r
-\r
-extern int sball_initialized;\r
-\r
-enum {\r
- SPNAV_EVENT_ANY, /* used by spnav_remove_events() */\r
- SPNAV_EVENT_MOTION,\r
- SPNAV_EVENT_BUTTON /* includes both press and release */\r
-};\r
-\r
-struct spnav_event_motion {\r
- int type;\r
- int x, y, z;\r
- int rx, ry, rz;\r
- unsigned int period;\r
- int *data;\r
-};\r
-\r
-struct spnav_event_button {\r
- int type;\r
- int press;\r
- int bnum;\r
-};\r
-\r
-typedef union spnav_event {\r
- int type;\r
- struct spnav_event_motion motion;\r
- struct spnav_event_button button;\r
-} spnav_event;\r
-\r
-\r
-static int spnav_x11_open(Display *dpy, Window win);\r
-static int spnav_x11_window(Window win);\r
-static int spnav_x11_event(const XEvent *xev, spnav_event *event);\r
-static int spnav_close(void);\r
-static int spnav_fd(void);\r
-static int spnav_remove_events(int type);\r
-\r
-static SFG_Window *spnav_win;\r
-\r
-void fgPlatformInitializeSpaceball(void)\r
-{\r
- Window w;\r
-\r
- sball_initialized = 1;\r
- if(!fgStructure.CurrentWindow)\r
- {\r
- sball_initialized = -1;\r
- return;\r
- }\r
-\r
- w = fgStructure.CurrentWindow->Window.Handle;\r
- if(spnav_x11_open(fgDisplay.pDisplay.Display, w) == -1)\r
- {\r
- sball_initialized = -1;\r
- return;\r
- }\r
-}\r
-\r
-void fgPlatformSpaceballClose(void) \r
-{\r
- spnav_close();\r
-}\r
-\r
-int fgPlatformHasSpaceball(void) \r
-{\r
- /* XXX this function should somehow query the driver if there's a device\r
- * plugged in, as opposed to just checking if there's a driver to talk to.\r
- */\r
- return spnav_fd() == -1 ? 0 : 1;\r
-}\r
-\r
-int fgPlatformSpaceballNumButtons(void) {\r
- return 2;\r
-}\r
-\r
-void fgPlatformSpaceballSetWindow(SFG_Window *window) \r
-{\r
- if(spnav_win != window) {\r
- spnav_x11_window(window->Window.Handle);\r
- spnav_win = window;\r
- }\r
-}\r
-\r
-int fgIsSpaceballXEvent(const XEvent *xev)\r
-{\r
- spnav_event sev;\r
-\r
- if(spnav_win != fgStructure.CurrentWindow) {\r
- /* this will also initialize spaceball if needed (first call) */\r
- fgSpaceballSetWindow(fgStructure.CurrentWindow);\r
- }\r
-\r
- if(sball_initialized != 1) {\r
- return 0;\r
- }\r
-\r
- return spnav_x11_event(xev, &sev);\r
-}\r
-\r
-void fgSpaceballHandleXEvent(const XEvent *xev)\r
-{\r
- spnav_event sev;\r
-\r
- if(sball_initialized == 0) {\r
- fgInitialiseSpaceball();\r
- if(sball_initialized != 1) {\r
- return;\r
- }\r
- }\r
-\r
- if(spnav_x11_event(xev, &sev)) {\r
- switch(sev.type) {\r
- case SPNAV_EVENT_MOTION:\r
- if(sev.motion.x | sev.motion.y | sev.motion.z) {\r
- INVOKE_WCB(*spnav_win, SpaceMotion, (sev.motion.x, sev.motion.y, sev.motion.z));\r
- }\r
- if(sev.motion.rx | sev.motion.ry | sev.motion.rz) {\r
- INVOKE_WCB(*spnav_win, SpaceRotation, (sev.motion.rx, sev.motion.ry, sev.motion.rz));\r
- }\r
- spnav_remove_events(SPNAV_EVENT_MOTION);\r
- break;\r
-\r
- case SPNAV_EVENT_BUTTON:\r
- INVOKE_WCB(*spnav_win, SpaceButton, (sev.button.bnum, sev.button.press ? GLUT_DOWN : GLUT_UP));\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
- }\r
-}\r
-\r
-/*\r
-The following code is part of libspnav, part of the spacenav project (spacenav.sf.net)\r
-Copyright (C) 2007-2009 John Tsiombikas <nuclear@member.fsf.org>\r
-\r
-Redistribution and use in source and binary forms, with or without\r
-modification, are permitted provided that the following conditions are met:\r
-\r
-1. Redistributions of source code must retain the above copyright notice, this\r
- list of conditions and the following disclaimer.\r
-2. Redistributions in binary form must reproduce the above copyright notice,\r
- this list of conditions and the following disclaimer in the documentation\r
- and/or other materials provided with the distribution.\r
-3. The name of the author may not be used to endorse or promote products\r
- derived from this software without specific prior written permission.\r
-\r
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\r
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
-OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
-OF SUCH DAMAGE.\r
-*/\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-#ifdef HAVE_ERRNO_H\r
-#include <errno.h>\r
-#endif\r
-\r
-#include <X11/Xlib.h>\r
-#include <X11/Xutil.h>\r
-\r
-static Window get_daemon_window(Display *dpy);\r
-static int catch_badwin(Display *dpy, XErrorEvent *err);\r
-\r
-static Display *dpy;\r
-static Window app_win;\r
-static Atom motion_event, button_press_event, button_release_event, command_event;\r
-\r
-enum {\r
- CMD_APP_WINDOW = 27695,\r
- CMD_APP_SENS\r
-};\r
-\r
-#define IS_OPEN dpy\r
-\r
-struct event_node {\r
- spnav_event event;\r
- struct event_node *next;\r
-};\r
-\r
-static int spnav_x11_open(Display *display, Window win)\r
-{\r
- if(IS_OPEN) {\r
- return -1;\r
- }\r
-\r
- dpy = display;\r
-\r
- motion_event = XInternAtom(dpy, "MotionEvent", True);\r
- button_press_event = XInternAtom(dpy, "ButtonPressEvent", True);\r
- button_release_event = XInternAtom(dpy, "ButtonReleaseEvent", True);\r
- command_event = XInternAtom(dpy, "CommandEvent", True);\r
-\r
- if(!motion_event || !button_press_event || !button_release_event || !command_event) {\r
- dpy = 0;\r
- return -1; /* daemon not started */\r
- }\r
-\r
- if(spnav_x11_window(win) == -1) {\r
- dpy = 0;\r
- return -1; /* daemon not started */\r
- }\r
-\r
- app_win = win;\r
- return 0;\r
-}\r
-\r
-static int spnav_close(void)\r
-{\r
- if(dpy) {\r
- spnav_x11_window(DefaultRootWindow(dpy));\r
- app_win = 0;\r
- dpy = 0;\r
- return 0;\r
- }\r
- return -1;\r
-}\r
-\r
-static int spnav_x11_window(Window win)\r
-{\r
- int (*prev_xerr_handler)(Display*, XErrorEvent*);\r
- XEvent xev;\r
- Window daemon_win;\r
-\r
- if(!IS_OPEN) {\r
- return -1;\r
- }\r
-\r
- if(!(daemon_win = get_daemon_window(dpy))) {\r
- return -1;\r
- }\r
-\r
- prev_xerr_handler = XSetErrorHandler(catch_badwin);\r
-\r
- xev.type = ClientMessage;\r
- xev.xclient.send_event = False;\r
- xev.xclient.display = dpy;\r
- xev.xclient.window = win;\r
- xev.xclient.message_type = command_event;\r
- xev.xclient.format = 16;\r
- xev.xclient.data.s[0] = ((unsigned int)win & 0xffff0000) >> 16;\r
- xev.xclient.data.s[1] = (unsigned int)win & 0xffff;\r
- xev.xclient.data.s[2] = CMD_APP_WINDOW;\r
-\r
- XSendEvent(dpy, daemon_win, False, 0, &xev);\r
- XSync(dpy, False);\r
-\r
- XSetErrorHandler(prev_xerr_handler);\r
- return 0;\r
-}\r
-\r
-static int spnav_fd(void)\r
-{\r
- if(dpy) {\r
- return ConnectionNumber(dpy);\r
- }\r
- return -1;\r
-}\r
-\r
-/*static int spnav_wait_event(spnav_event *event)\r
-{\r
- if(dpy) {\r
- for(;;) {\r
- XEvent xev;\r
- XNextEvent(dpy, &xev);\r
-\r
- if(spnav_x11_event(&xev, event) > 0) {\r
- return event->type;\r
- }\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-static int spnav_poll_event(spnav_event *event)\r
-{\r
- if(dpy) {\r
- if(XPending(dpy)) {\r
- XEvent xev;\r
- XNextEvent(dpy, &xev);\r
-\r
- return spnav_x11_event(&xev, event);\r
- }\r
- }\r
- return 0;\r
-}*/\r
-\r
-static Bool match_events(Display *dpy, XEvent *xev, char *arg)\r
-{\r
- int evtype = *(int*)arg;\r
-\r
- if(xev->type != ClientMessage) {\r
- return False;\r
- }\r
-\r
- if(xev->xclient.message_type == motion_event) {\r
- return !evtype || evtype == SPNAV_EVENT_MOTION ? True : False;\r
- }\r
- if(xev->xclient.message_type == button_press_event ||\r
- xev->xclient.message_type == button_release_event) {\r
- return !evtype || evtype == SPNAV_EVENT_BUTTON ? True : False;\r
- }\r
- return False;\r
-}\r
-\r
-static int spnav_remove_events(int type)\r
-{\r
- int rm_count = 0;\r
-\r
- if(dpy) {\r
- XEvent xev;\r
-\r
- while(XCheckIfEvent(dpy, &xev, match_events, (char*)&type)) {\r
- rm_count++;\r
- }\r
- return rm_count;\r
- }\r
- return 0;\r
-}\r
-\r
-static int spnav_x11_event(const XEvent *xev, spnav_event *event)\r
-{\r
- int i;\r
- int xmsg_type;\r
-\r
- if(xev->type != ClientMessage) {\r
- return 0;\r
- }\r
-\r
- xmsg_type = xev->xclient.message_type;\r
-\r
- if(xmsg_type != motion_event && xmsg_type != button_press_event &&\r
- xmsg_type != button_release_event) {\r
- return 0;\r
- }\r
-\r
- if(xmsg_type == motion_event) {\r
- event->type = SPNAV_EVENT_MOTION;\r
- event->motion.data = &event->motion.x;\r
-\r
- for(i=0; i<6; i++) {\r
- event->motion.data[i] = xev->xclient.data.s[i + 2];\r
- }\r
- event->motion.period = xev->xclient.data.s[8];\r
- } else {\r
- event->type = SPNAV_EVENT_BUTTON;\r
- event->button.press = xmsg_type == button_press_event ? 1 : 0;\r
- event->button.bnum = xev->xclient.data.s[2];\r
- }\r
- return event->type;\r
-}\r
-\r
-\r
-static Window get_daemon_window(Display *dpy)\r
-{\r
- Window win, root_win;\r
- XTextProperty wname;\r
- Atom type;\r
- int fmt;\r
- unsigned long nitems, bytes_after;\r
- unsigned char *prop;\r
-\r
- root_win = DefaultRootWindow(dpy);\r
-\r
- XGetWindowProperty(dpy, root_win, command_event, 0, 1, False, AnyPropertyType, &type, &fmt, &nitems, &bytes_after, &prop);\r
- if(!prop) {\r
- return 0;\r
- }\r
-\r
- win = *(Window*)prop;\r
- XFree(prop);\r
-\r
- if(!XGetWMName(dpy, win, &wname) || strcmp("Magellan Window", (char*)wname.value) != 0) {\r
- return 0;\r
- }\r
-\r
- return win;\r
-}\r
-\r
-static int catch_badwin(Display *dpy, XErrorEvent *err)\r
-{\r
- char buf[256];\r
-\r
- if(err->error_code == BadWindow) {\r
- /* do nothing? */\r
- } else {\r
- XGetErrorText(dpy, err->error_code, buf, sizeof buf);\r
- fprintf(stderr, "Caught unexpected X error: %s\n", buf);\r
- }\r
- return 0;\r
-}\r
-\r
+/* Spaceball support for Linux.
+ * Written by John Tsiombikas <nuclear@member.fsf.org>
+ * Copied for Platform code by Evan Felix <karcaw at gmail.com>
+ * Creation date: Thur Feb 2 2012
+ *
+ * This code supports 3Dconnexion's 6-dof space-whatever devices.
+ * It can communicate with either the proprietary 3Dconnexion daemon (3dxsrv)
+ * free spacenavd (http://spacenav.sourceforge.net), through the "standard"
+ * magellan X-based protocol.
+ */
+
+#include <GL/freeglut.h>
+#include "../Common/freeglut_internal.h"
+
+#include <X11/Xlib.h>
+
+extern int sball_initialized;
+
+enum {
+ SPNAV_EVENT_ANY, /* used by spnav_remove_events() */
+ SPNAV_EVENT_MOTION,
+ SPNAV_EVENT_BUTTON /* includes both press and release */
+};
+
+struct spnav_event_motion {
+ int type;
+ int x, y, z;
+ int rx, ry, rz;
+ unsigned int period;
+ int *data;
+};
+
+struct spnav_event_button {
+ int type;
+ int press;
+ int bnum;
+};
+
+typedef union spnav_event {
+ int type;
+ struct spnav_event_motion motion;
+ struct spnav_event_button button;
+} spnav_event;
+
+
+static int spnav_x11_open(Display *dpy, Window win);
+static int spnav_x11_window(Window win);
+static int spnav_x11_event(const XEvent *xev, spnav_event *event);
+static int spnav_close(void);
+static int spnav_fd(void);
+static int spnav_remove_events(int type);
+
+static SFG_Window *spnav_win;
+
+void fgPlatformInitializeSpaceball(void)
+{
+ Window w;
+
+ sball_initialized = 1;
+ if(!fgStructure.CurrentWindow)
+ {
+ sball_initialized = -1;
+ return;
+ }
+
+ w = fgStructure.CurrentWindow->Window.Handle;
+ if(spnav_x11_open(fgDisplay.pDisplay.Display, w) == -1)
+ {
+ sball_initialized = -1;
+ return;
+ }
+}
+
+void fgPlatformSpaceballClose(void)
+{
+ spnav_close();
+}
+
+int fgPlatformHasSpaceball(void)
+{
+ /* XXX this function should somehow query the driver if there's a device
+ * plugged in, as opposed to just checking if there's a driver to talk to.
+ */
+ return spnav_fd() == -1 ? 0 : 1;
+}
+
+int fgPlatformSpaceballNumButtons(void) {
+ return 2;
+}
+
+void fgPlatformSpaceballSetWindow(SFG_Window *window)
+{
+ if(spnav_win != window) {
+ spnav_x11_window(window->Window.Handle);
+ spnav_win = window;
+ }
+}
+
+int fgIsSpaceballXEvent(const XEvent *xev)
+{
+ spnav_event sev;
+
+ if(spnav_win != fgStructure.CurrentWindow) {
+ /* this will also initialize spaceball if needed (first call) */
+ fgSpaceballSetWindow(fgStructure.CurrentWindow);
+ }
+
+ if(sball_initialized != 1) {
+ return 0;
+ }
+
+ return spnav_x11_event(xev, &sev);
+}
+
+void fgSpaceballHandleXEvent(const XEvent *xev)
+{
+ spnav_event sev;
+
+ if(sball_initialized == 0) {
+ fgInitialiseSpaceball();
+ if(sball_initialized != 1) {
+ return;
+ }
+ }
+
+ if(spnav_x11_event(xev, &sev)) {
+ switch(sev.type) {
+ case SPNAV_EVENT_MOTION:
+ if(sev.motion.x | sev.motion.y | sev.motion.z) {
+ INVOKE_WCB(*spnav_win, SpaceMotion, (sev.motion.x, sev.motion.y, sev.motion.z));
+ }
+ if(sev.motion.rx | sev.motion.ry | sev.motion.rz) {
+ INVOKE_WCB(*spnav_win, SpaceRotation, (sev.motion.rx, sev.motion.ry, sev.motion.rz));
+ }
+ spnav_remove_events(SPNAV_EVENT_MOTION);
+ break;
+
+ case SPNAV_EVENT_BUTTON:
+ INVOKE_WCB(*spnav_win, SpaceButton, (sev.button.bnum, sev.button.press ? GLUT_DOWN : GLUT_UP));
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/*
+The following code is part of libspnav, part of the spacenav project (spacenav.sf.net)
+Copyright (C) 2007-2009 John Tsiombikas <nuclear@member.fsf.org>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+static Window get_daemon_window(Display *dpy);
+static int catch_badwin(Display *dpy, XErrorEvent *err);
+
+static Display *dpy;
+static Window app_win;
+static Atom motion_event, button_press_event, button_release_event, command_event;
+
+enum {
+ CMD_APP_WINDOW = 27695,
+ CMD_APP_SENS
+};
+
+#define IS_OPEN dpy
+
+struct event_node {
+ spnav_event event;
+ struct event_node *next;
+};
+
+static int spnav_x11_open(Display *display, Window win)
+{
+ if(IS_OPEN) {
+ return -1;
+ }
+
+ dpy = display;
+
+ motion_event = XInternAtom(dpy, "MotionEvent", True);
+ button_press_event = XInternAtom(dpy, "ButtonPressEvent", True);
+ button_release_event = XInternAtom(dpy, "ButtonReleaseEvent", True);
+ command_event = XInternAtom(dpy, "CommandEvent", True);
+
+ if(!motion_event || !button_press_event || !button_release_event || !command_event) {
+ dpy = 0;
+ return -1; /* daemon not started */
+ }
+
+ if(spnav_x11_window(win) == -1) {
+ dpy = 0;
+ return -1; /* daemon not started */
+ }
+
+ app_win = win;
+ return 0;
+}
+
+static int spnav_close(void)
+{
+ if(dpy) {
+ spnav_x11_window(DefaultRootWindow(dpy));
+ app_win = 0;
+ dpy = 0;
+ return 0;
+ }
+ return -1;
+}
+
+static int spnav_x11_window(Window win)
+{
+ int (*prev_xerr_handler)(Display*, XErrorEvent*);
+ XEvent xev;
+ Window daemon_win;
+
+ if(!IS_OPEN) {
+ return -1;
+ }
+
+ if(!(daemon_win = get_daemon_window(dpy))) {
+ return -1;
+ }
+
+ prev_xerr_handler = XSetErrorHandler(catch_badwin);
+
+ xev.type = ClientMessage;
+ xev.xclient.send_event = False;
+ xev.xclient.display = dpy;
+ xev.xclient.window = win;
+ xev.xclient.message_type = command_event;
+ xev.xclient.format = 16;
+ xev.xclient.data.s[0] = ((unsigned int)win & 0xffff0000) >> 16;
+ xev.xclient.data.s[1] = (unsigned int)win & 0xffff;
+ xev.xclient.data.s[2] = CMD_APP_WINDOW;
+
+ XSendEvent(dpy, daemon_win, False, 0, &xev);
+ XSync(dpy, False);
+
+ XSetErrorHandler(prev_xerr_handler);
+ return 0;
+}
+
+static int spnav_fd(void)
+{
+ if(dpy) {
+ return ConnectionNumber(dpy);
+ }
+ return -1;
+}
+
+/*static int spnav_wait_event(spnav_event *event)
+{
+ if(dpy) {
+ for(;;) {
+ XEvent xev;
+ XNextEvent(dpy, &xev);
+
+ if(spnav_x11_event(&xev, event) > 0) {
+ return event->type;
+ }
+ }
+ }
+ return 0;
+}
+
+static int spnav_poll_event(spnav_event *event)
+{
+ if(dpy) {
+ if(XPending(dpy)) {
+ XEvent xev;
+ XNextEvent(dpy, &xev);
+
+ return spnav_x11_event(&xev, event);
+ }
+ }
+ return 0;
+}*/
+
+static Bool match_events(Display *dpy, XEvent *xev, char *arg)
+{
+ int evtype = *(int*)arg;
+
+ if(xev->type != ClientMessage) {
+ return False;
+ }
+
+ if(xev->xclient.message_type == motion_event) {
+ return !evtype || evtype == SPNAV_EVENT_MOTION ? True : False;
+ }
+ if(xev->xclient.message_type == button_press_event ||
+ xev->xclient.message_type == button_release_event) {
+ return !evtype || evtype == SPNAV_EVENT_BUTTON ? True : False;
+ }
+ return False;
+}
+
+static int spnav_remove_events(int type)
+{
+ int rm_count = 0;
+
+ if(dpy) {
+ XEvent xev;
+
+ while(XCheckIfEvent(dpy, &xev, match_events, (char*)&type)) {
+ rm_count++;
+ }
+ return rm_count;
+ }
+ return 0;
+}
+
+static int spnav_x11_event(const XEvent *xev, spnav_event *event)
+{
+ int i;
+ int xmsg_type;
+
+ if(xev->type != ClientMessage) {
+ return 0;
+ }
+
+ xmsg_type = xev->xclient.message_type;
+
+ if(xmsg_type != motion_event && xmsg_type != button_press_event &&
+ xmsg_type != button_release_event) {
+ return 0;
+ }
+
+ if(xmsg_type == motion_event) {
+ event->type = SPNAV_EVENT_MOTION;
+ event->motion.data = &event->motion.x;
+
+ for(i=0; i<6; i++) {
+ event->motion.data[i] = xev->xclient.data.s[i + 2];
+ }
+ event->motion.period = xev->xclient.data.s[8];
+ } else {
+ event->type = SPNAV_EVENT_BUTTON;
+ event->button.press = xmsg_type == button_press_event ? 1 : 0;
+ event->button.bnum = xev->xclient.data.s[2];
+ }
+ return event->type;
+}
+
+
+static Window get_daemon_window(Display *dpy)
+{
+ Window win, root_win;
+ XTextProperty wname;
+ Atom type;
+ int fmt;
+ unsigned long nitems, bytes_after;
+ unsigned char *prop;
+
+ root_win = DefaultRootWindow(dpy);
+
+ XGetWindowProperty(dpy, root_win, command_event, 0, 1, False, AnyPropertyType, &type, &fmt, &nitems, &bytes_after, &prop);
+ if(!prop) {
+ return 0;
+ }
+
+ win = *(Window*)prop;
+ XFree(prop);
+
+ if(!XGetWMName(dpy, win, &wname) || strcmp("Magellan Window", (char*)wname.value) != 0) {
+ return 0;
+ }
+
+ return win;
+}
+
+static int catch_badwin(Display *dpy, XErrorEvent *err)
+{
+ char buf[256];
+
+ if(err->error_code == BadWindow) {
+ /* do nothing? */
+ } else {
+ XGetErrorText(dpy, err->error_code, buf, sizeof buf);
+ fprintf(stderr, "Caught unexpected X error: %s\n", buf);
+ }
+ return 0;
+}
+