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