Splitting the X11-specific "freeglut_spaceball.c" code into its own file
authorJohn F. Fay <johnffay@nettally.com>
Sun, 5 Feb 2012 04:04:28 +0000 (04:04 +0000)
committerJohn F. Fay <johnffay@nettally.com>
Sun, 5 Feb 2012 04:04:28 +0000 (04:04 +0000)
git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@1057 7f0cb862-5218-0410-a997-914c9d46530a

src/Common/freeglut_spaceball.c
src/mswin/freeglut_spaceball_mswin.c
src/x11/freeglut_spaceball_x11.c

index 4901e79..6f8feba 100644 (file)
 \r
 /* -- PRIVATE FUNCTIONS --------------------------------------------------- */\r
 \r
-#if TARGET_HOST_POSIX_X11\r
-#include <X11/Xlib.h>\r
+extern void fgPlatformInitializeSpaceball(void);\r
+extern void fgPlatformSpaceballClose(void);\r
+extern int fgPlatformHasSpaceball(void);\r
+extern int fgPlatformSpaceballNumButtons(void);\r
+extern void fgPlatformSpaceballSetWindow(SFG_Window *window);\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
-#endif\r
-\r
-/* Flag telling whether we have a spaceball:\r
- *   0 - haven't tried initializing\r
- *   1 - have successfully initialized\r
- *  -1 - have tried to initialize but not succeeded\r
- */\r
-static int sball_initialized = 0;\r
 \r
+int sball_initialized = 0;\r
 \r
 void fgInitialiseSpaceball(void)\r
 {\r
@@ -66,34 +27,14 @@ void fgInitialiseSpaceball(void)
         return;\r
     }\r
 \r
-#if TARGET_HOST_POSIX_X11\r
-    {\r
-        Window w;\r
-\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
-#endif\r
+    fgPlatformInitializeSpaceball();\r
 \r
     sball_initialized = 1;\r
 }\r
 \r
 void fgSpaceballClose(void)\r
 {\r
-#if TARGET_HOST_POSIX_X11\r
-    spnav_close();\r
-#endif\r
-}\r
+       fgPlatformSpaceballClose();}\r
 \r
 int fgHasSpaceball(void)\r
 {\r
@@ -105,14 +46,7 @@ int fgHasSpaceball(void)
         }\r
     }\r
 \r
-#if TARGET_HOST_POSIX_X11\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
-#else\r
-    return 0;\r
-#endif\r
+    return fgPlatformHasSpaceball();\r
 }\r
 \r
 int fgSpaceballNumButtons(void)\r
@@ -125,11 +59,7 @@ int fgSpaceballNumButtons(void)
         }\r
     }\r
 \r
-#if TARGET_HOST_POSIX_X11\r
-    return 2;  /* TODO implement this properly */\r
-#else\r
-    return 0;\r
-#endif\r
+    return fgPlatformSpaceballNumButtons();\r
 }\r
 \r
 void fgSpaceballSetWindow(SFG_Window *window)\r
@@ -141,331 +71,6 @@ void fgSpaceballSetWindow(SFG_Window *window)
         }\r
     }\r
 \r
-#if TARGET_HOST_POSIX_X11\r
-    if(spnav_win != window) {\r
-        spnav_x11_window(window->Window.Handle);\r
-        spnav_win = window;\r
-    }\r
-#endif\r
-}\r
-\r
-\r
-#if TARGET_HOST_POSIX_X11\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
+    fgPlatformSpaceballSetWindow(window);\r
 }\r
 \r
-#endif  /* TARGET_HOST_POSIX_X11 */\r
index e69de29..72a8d8c 100644 (file)
@@ -0,0 +1,58 @@
+/*\r
+ * freeglut_spaceball_mswin.c\r
+ *\r
+ * Spaceball support for Windows\r
+ *\r
+ * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.\r
+ * Written by Evan Felix <karcaw at gmail.com>\r
+ * Creation date: Sat Feb 4, 2012\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a\r
+ * copy of this software and associated documentation files (the "Software"),\r
+ * to deal in the Software without restriction, including without limitation\r
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
+ * and/or sell copies of the Software, and to permit persons to whom the\r
+ * Software is furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included\r
+ * in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
+ * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ */\r
+/*\r
+ * This code is a very complicated way of doing nothing.  \r
+ * But is needed for mswindows platform builds.\r
+ */\r
+\r
+#include <GL/freeglut.h>\r
+#include "../Common/freeglut_internal.h"\r
+\r
+void fgPlatformInitializeSpaceball(void)\r
+{\r
+       return;\r
+}\r
+\r
+void fgPlatformSpaceballClose(void)\r
+{\r
+       return;\r
+}\r
+\r
+int fgPlatformHasSpaceball(void)\r
+{\r
+       return 0;\r
+}\r
+\r
+int fgPlatformSpaceballNumButtons(void)\r
+{\r
+       return 0;\r
+}\r
+\r
+void fgPlatformSpaceballSetWindow(SFG_Window *window)\r
+{\r
+       return;\r
+}\r
index e69de29..0e29b3f 100644 (file)
@@ -0,0 +1,415 @@
+/* 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 "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