2008-04-07 08:37:52 +00:00
|
|
|
/*
|
|
|
|
spnavcfg - an interactive GUI configurator for the spacenavd daemon.
|
2009-01-30 03:11:59 +00:00
|
|
|
Copyright (C) 2007-2009 John Tsiombikas <nuclear@siggraph.org>
|
2008-04-07 08:37:52 +00:00
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2008-04-09 04:27:12 +00:00
|
|
|
#include <string.h>
|
2008-04-07 08:37:52 +00:00
|
|
|
#include <signal.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <gtk/gtk.h>
|
2008-04-09 04:27:12 +00:00
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xutil.h>
|
2008-04-07 08:37:52 +00:00
|
|
|
#include "cfgfile.h"
|
|
|
|
#include "cmd.h"
|
|
|
|
|
|
|
|
#define CFGFILE "/etc/spnavrc"
|
|
|
|
|
2008-04-09 04:27:12 +00:00
|
|
|
int get_daemon_pid(void); /* back.c */
|
|
|
|
|
2008-04-07 08:37:52 +00:00
|
|
|
static void update_cfg(void);
|
|
|
|
static void layout(void);
|
|
|
|
static void chk_handler(GtkToggleButton *bn, void *data);
|
|
|
|
static void slider_handler(GtkRange *rng, void *data);
|
2008-04-09 04:27:12 +00:00
|
|
|
static void bn_handler(GtkButton *bn, void *data);
|
2008-04-07 08:37:52 +00:00
|
|
|
|
|
|
|
static void add_child(GtkWidget *parent, GtkWidget *child);
|
|
|
|
static GtkWidget *create_vbox(GtkWidget *parent);
|
|
|
|
|
|
|
|
static GtkWidget *win;
|
|
|
|
|
|
|
|
static struct cfg cfg;
|
|
|
|
static int pipe_fd;
|
|
|
|
|
|
|
|
void frontend(int pfd)
|
|
|
|
{
|
|
|
|
int argc = 0;
|
|
|
|
int ruid = getuid();
|
|
|
|
#ifdef __linux__
|
|
|
|
int setresuid(uid_t ruid, uid_t euid, uid_t suid);
|
|
|
|
setresuid(ruid, ruid, ruid);
|
|
|
|
#else
|
|
|
|
seteuid(ruid);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
pipe_fd = pfd;
|
|
|
|
|
|
|
|
gtk_init(&argc, 0);
|
|
|
|
|
|
|
|
read_cfg(CFGFILE, &cfg);
|
|
|
|
|
|
|
|
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
gtk_window_set_title(GTK_WINDOW(win), "spacenavd configuration");
|
|
|
|
g_signal_connect(G_OBJECT(win), "delete_event", G_CALLBACK(gtk_main_quit), 0);
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(win), 4);
|
|
|
|
|
|
|
|
layout();
|
|
|
|
|
|
|
|
gtk_widget_show_all(win);
|
|
|
|
|
|
|
|
gtk_main();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update_cfg(void)
|
|
|
|
{
|
|
|
|
int cmd = CMD_CFG;
|
|
|
|
write(pipe_fd, &cmd, 1);
|
|
|
|
write(pipe_fd, &cfg, sizeof cfg);
|
|
|
|
}
|
|
|
|
|
2008-04-09 04:27:12 +00:00
|
|
|
static int query_x11(void)
|
|
|
|
{
|
|
|
|
Display *dpy;
|
|
|
|
Window win, root_win;
|
|
|
|
XTextProperty wname;
|
|
|
|
Atom type, command_event;
|
|
|
|
int fmt;
|
|
|
|
unsigned long nitems, bytes_after;
|
|
|
|
unsigned char *prop;
|
|
|
|
|
|
|
|
if(!(dpy = XOpenDisplay(0))) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
root_win = DefaultRootWindow(dpy);
|
|
|
|
|
|
|
|
if((command_event = XInternAtom(dpy, "CommandEvent", True)) == None) {
|
|
|
|
XCloseDisplay(dpy);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
XGetWindowProperty(dpy, root_win, command_event, 0, 1, False, AnyPropertyType,
|
|
|
|
&type, &fmt, &nitems, &bytes_after, &prop);
|
|
|
|
if(!prop) {
|
|
|
|
XCloseDisplay(dpy);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
win = *(Window*)prop;
|
|
|
|
XFree(prop);
|
|
|
|
|
|
|
|
if(!XGetWMName(dpy, win, &wname) || strcmp("Magellan Window", (char*)wname.value) != 0) {
|
|
|
|
XCloseDisplay(dpy);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
XCloseDisplay(dpy);
|
|
|
|
|
|
|
|
/* found a magellan window, still it might belong to the 3dxsrv driver */
|
|
|
|
if(get_daemon_pid() == -1) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this could still mean that the daemon crashed and left behind the pidfile... */
|
|
|
|
return 1; /* ... but wtf */
|
|
|
|
}
|
|
|
|
|
2008-04-07 08:37:52 +00:00
|
|
|
static void layout(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
GtkWidget *w;
|
2008-05-12 06:03:19 +00:00
|
|
|
GtkWidget *vbox, *vbox2, *bbox, *tbl, *frm;
|
2008-04-07 08:37:52 +00:00
|
|
|
|
|
|
|
vbox = create_vbox(win);
|
|
|
|
|
|
|
|
frm = gtk_frame_new("invert axis");
|
|
|
|
add_child(vbox, frm);
|
|
|
|
|
|
|
|
tbl = gtk_table_new(3, 4, FALSE);
|
|
|
|
add_child(frm, tbl);
|
|
|
|
|
2008-04-09 04:27:12 +00:00
|
|
|
gtk_table_set_row_spacings(GTK_TABLE(tbl), 2);
|
|
|
|
gtk_table_set_col_spacings(GTK_TABLE(tbl), 2);
|
|
|
|
|
2008-04-07 08:37:52 +00:00
|
|
|
gtk_table_attach_defaults(GTK_TABLE(tbl), gtk_label_new("X"), 1, 2, 0, 1);
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(tbl), gtk_label_new("Y"), 2, 3, 0, 1);
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(tbl), gtk_label_new("Z"), 3, 4, 0, 1);
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(tbl), gtk_label_new("translation"), 0, 1, 1, 2);
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(tbl), gtk_label_new("rotation"), 0, 1, 2, 3);
|
|
|
|
|
|
|
|
for(i=0; i<6; i++) {
|
|
|
|
int x = i % 3 + 1;
|
|
|
|
int y = i / 3 + 1;
|
|
|
|
w = gtk_check_button_new();
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(tbl), w, x, x + 1, y, y + 1);
|
|
|
|
g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(chk_handler), (void*)i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*hbox = create_hbox(vbox);*/
|
|
|
|
frm = gtk_frame_new("sensitivity");
|
|
|
|
add_child(vbox, frm);
|
|
|
|
|
|
|
|
w = gtk_hscale_new_with_range(0.0, 4.0, 0.1);
|
|
|
|
gtk_range_set_update_policy(GTK_RANGE(w), GTK_UPDATE_DELAYED);
|
|
|
|
gtk_range_set_value(GTK_RANGE(w), cfg.sensitivity);
|
|
|
|
gtk_scale_set_value_pos(GTK_SCALE(w), GTK_POS_RIGHT);
|
|
|
|
g_signal_connect(G_OBJECT(w), "value_changed", G_CALLBACK(slider_handler), 0);
|
|
|
|
add_child(frm, w);
|
|
|
|
|
2008-04-09 04:27:12 +00:00
|
|
|
frm = gtk_frame_new("X11 magellan API");
|
|
|
|
add_child(vbox, frm);
|
|
|
|
|
|
|
|
bbox = gtk_hbutton_box_new();
|
|
|
|
add_child(frm, bbox);
|
|
|
|
|
|
|
|
w = gtk_button_new_with_label("start");
|
|
|
|
g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(bn_handler), (void*)0);
|
|
|
|
add_child(bbox, w);
|
|
|
|
|
|
|
|
w = gtk_button_new_with_label("stop");
|
|
|
|
g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(bn_handler), (void*)1);
|
|
|
|
add_child(bbox, w);
|
|
|
|
|
|
|
|
w = gtk_button_new_with_label("check");
|
|
|
|
g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(bn_handler), (void*)2);
|
|
|
|
add_child(bbox, w);
|
|
|
|
|
|
|
|
/*
|
|
|
|
w = gtk_check_button_new_with_label("enable X11 magellan API");
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), query_x11());
|
|
|
|
g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(chk_handler), (void*)10);
|
|
|
|
add_child(frm, w);
|
|
|
|
*/
|
|
|
|
|
|
|
|
frm = gtk_frame_new("misc");
|
|
|
|
add_child(vbox, frm);
|
|
|
|
|
2008-05-12 06:03:19 +00:00
|
|
|
vbox2 = create_vbox(frm);
|
|
|
|
|
|
|
|
w = gtk_check_button_new_with_label("enable LED");
|
|
|
|
g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(chk_handler), (void*)10);
|
|
|
|
add_child(vbox2, w);
|
|
|
|
|
2008-04-09 04:27:12 +00:00
|
|
|
bbox = gtk_hbutton_box_new();
|
2008-05-12 06:03:19 +00:00
|
|
|
add_child(vbox2, bbox);
|
2008-04-09 04:27:12 +00:00
|
|
|
|
|
|
|
w = gtk_button_new_with_label("ping daemon");
|
|
|
|
g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(bn_handler), (void*)3);
|
|
|
|
add_child(bbox, w);
|
|
|
|
|
2008-04-07 08:37:52 +00:00
|
|
|
bbox = gtk_hbutton_box_new();
|
|
|
|
add_child(vbox, bbox);
|
|
|
|
|
|
|
|
/*w = gtk_button_new_from_stock(GTK_STOCK_APPLY);
|
|
|
|
g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(bn_handler), 0);
|
|
|
|
add_child(bbox, w);*/
|
|
|
|
|
|
|
|
w = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
|
|
|
|
g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(gtk_main_quit), 0);
|
|
|
|
add_child(bbox, w);
|
|
|
|
}
|
|
|
|
|
2008-04-09 04:27:12 +00:00
|
|
|
static void chk_handler(GtkToggleButton *bn, void *data)
|
|
|
|
{
|
|
|
|
int which = (int)data;
|
|
|
|
int state = gtk_toggle_button_get_active(bn);
|
|
|
|
|
|
|
|
if(which < 6) {
|
|
|
|
cfg.invert[which] = state;
|
|
|
|
update_cfg();
|
|
|
|
}
|
2008-05-12 06:03:19 +00:00
|
|
|
|
|
|
|
if(which == 10) {
|
|
|
|
cfg.led = state;
|
|
|
|
update_cfg();
|
|
|
|
}
|
2008-04-09 04:27:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void slider_handler(GtkRange *rng, void *data)
|
|
|
|
{
|
|
|
|
cfg.sensitivity = gtk_range_get_value(rng);
|
|
|
|
update_cfg();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bn_handler(GtkButton *bn, void *data)
|
2008-04-07 08:37:52 +00:00
|
|
|
{
|
|
|
|
GtkWidget *dlg;
|
2008-04-09 04:27:12 +00:00
|
|
|
int id = (int)data;
|
|
|
|
int tmp;
|
|
|
|
|
|
|
|
switch(id) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
tmp = id ? CMD_STOPX : CMD_STARTX;
|
|
|
|
write(pipe_fd, &tmp, 1);
|
|
|
|
break;
|
2008-04-07 08:37:52 +00:00
|
|
|
|
2008-04-09 04:27:12 +00:00
|
|
|
case 2:
|
2008-04-07 08:37:52 +00:00
|
|
|
dlg = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
|
2008-04-09 04:27:12 +00:00
|
|
|
GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "The X11 Magellan (3dxsrv-compatible) API is %s.",
|
|
|
|
query_x11() ? "enabled" : "disabled");
|
|
|
|
gtk_widget_show_all(dlg);
|
2008-04-07 08:37:52 +00:00
|
|
|
g_signal_connect_swapped(dlg, "response", G_CALLBACK(gtk_widget_destroy), dlg);
|
|
|
|
break;
|
|
|
|
|
2008-04-09 04:27:12 +00:00
|
|
|
case 3:
|
|
|
|
tmp = CMD_PING;
|
|
|
|
write(pipe_fd, &tmp, 1);
|
|
|
|
read(pipe_fd, &tmp, 1);
|
|
|
|
|
|
|
|
if(tmp) { /* daemon alive */
|
|
|
|
dlg = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "The spacenavd driver is running fine.");
|
|
|
|
gtk_widget_show_all(dlg);
|
|
|
|
g_signal_connect_swapped(dlg, "response", G_CALLBACK(gtk_widget_destroy), dlg);
|
|
|
|
} else { /* daemon dead */
|
|
|
|
dlg = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
|
2008-04-07 08:37:52 +00:00
|
|
|
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "The driver isn't running at the moment.\n"
|
|
|
|
"You can still modify the configuration through this panel though.");
|
2008-04-09 04:27:12 +00:00
|
|
|
gtk_widget_show_all(dlg);
|
|
|
|
g_signal_connect_swapped(dlg, "response", G_CALLBACK(gtk_widget_destroy), dlg);
|
|
|
|
}
|
2008-04-07 08:37:52 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_child(GtkWidget *parent, GtkWidget *child)
|
|
|
|
{
|
|
|
|
if(GTK_IS_BOX(parent)) {
|
|
|
|
gtk_box_pack_start(GTK_BOX(parent), child, TRUE, TRUE, 3);
|
|
|
|
} else if(GTK_CONTAINER(parent)) {
|
|
|
|
gtk_container_add(GTK_CONTAINER(parent), child);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "failed to add child\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget *create_vbox(GtkWidget *parent)
|
|
|
|
{
|
|
|
|
GtkWidget *box = gtk_vbox_new(FALSE, 5);
|
|
|
|
add_child(parent, box);
|
|
|
|
return box;
|
|
|
|
}
|