aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorN.N. <david_merrill@users.sourceforge.net>2006-06-20 17:20:32 +0000
committerN.N. <david_merrill@users.sourceforge.net>2006-06-20 17:20:32 +0000
commitbd8d77dd8a6fbbc2a8925a2210917bfe0e2d6849 (patch)
treed1e7ec9d2cf141fc6b28d9cf6b800b9242a78608
This commit was generated by cvs2svn to compensate for changes in r5269,svn2git-root
which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/input_noticer/; revision=5270
-rw-r--r--INSTALL.TXT27
-rw-r--r--Makefile33
-rw-r--r--README.TXT51
-rw-r--r--input_noticer.c371
-rw-r--r--input_noticer.h58
-rw-r--r--noticer_test.pd12
-rw-r--r--test_noticer.c147
-rw-r--r--test_noticer_compile.sh1
8 files changed, 700 insertions, 0 deletions
diff --git a/INSTALL.TXT b/INSTALL.TXT
new file mode 100644
index 0000000..f7eefed
--- /dev/null
+++ b/INSTALL.TXT
@@ -0,0 +1,27 @@
+input_noticer install instructions
+David Merrill <dmerrill@media.mit.edu>
+
+In order to make this code compile, I had to install the following libraries
+onto my system:
+
+ libhal-dev
+ libglib2.0-dev
+ libdbus-glib-1-dev
+
+In a debian-based system, they can be installed with apt-get, as in:
+ sudo apt-get install libhal-dev
+
+To see if you have the right libraries installed in order to compile, you can
+try compiling the test_noticer.c file, by running the test_noticer_compile.sh
+shell script, as follows:
+
+source test_noticer_compile.sh
+
+Then, run test_noticer, and when it's running you should see messages when
+you plug, or un-plug a joystick.
+
+Once you've got your libraries sorted out, to compile and install, you should
+first modify the Makefile to suit your system. Then you can type:
+
+make
+make install_noticer
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..12401f6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,33 @@
+CC=gcc
+
+pd_linux: input_noticer.pd_linux
+
+clean: ; rm -f *.pd_linux *.o *~
+
+# installs all compiled externals.
+# you'll want to change this to match where your externals live
+install: ; sudo cp *.pd_linux /usr/lib/pd/extra
+
+# installs the input_noticer
+# you'll want to change this to match where your externals live
+install_noticer: ; cp input_noticer.pd_linux /usr/lib/pd/extra
+
+# ----------------------- LINUX i386 -----------------------
+
+.SUFFIXES: .pd_linux
+
+LINUXLDFLAGS = `pkg-config --libs glib-2.0 hal dbus-glib-1` -lpthread -lgthread-2.0 -lglib-2.0
+# LINUXLDFLAGS = `pkg-config --libs glib-2.0 hal dbus-glib-1 gthread-2.0`
+
+LINUXCFLAGS = -DUNIX -DPD -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch \
+ `pkg-config --cflags --libs glib-2.0 hal dbus-glib-1 gthread-2.0`
+
+LINUXINCLUDE = -I/usr/local/lib/pd/include -I/usr/lib/pd/src -I/usr/local/include
+
+.c.pd_linux:
+ $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm $(LINUXLDFLAGS)
+ strip --strip-unneeded $*.pd_linux
+ rm $*.o
diff --git a/README.TXT b/README.TXT
new file mode 100644
index 0000000..b92bb67
--- /dev/null
+++ b/README.TXT
@@ -0,0 +1,51 @@
+title: input_noticer
+
+author: David Merrill <dmerrill@media.mit.edu>
+
+desc: Using dbus and the hardware abstraction layer (HAL) in linux,
+this external allows pd to find all linux device files for a given device type.
+This scanning behavior can happen when the external is set up (via a [bang]),
+and will happen automatically when a new device is added to the system. An
+example linux device file would be:
+
+/dev/input/event5
+
+The pd user specifies device type as a string - i.e. "SideWinder Dual Strike", and
+this external outputs lists containing an index, and the linux device file where
+each device of the given type was found. For example
+
+{0, /dev/input/event5}
+{1, /dev/input/event6}
+
+These lists can be routed in PD with the [route] object - see the help file for
+[route] for more details.
+
+In order to make this code compile, I had to install the following libraries
+onto my system:
+
+ libhal-dev
+ libglib2.0-dev
+ libdbus-glib-1-dev
+
+In a debian-based system, they can be installed with apt-get, as in:
+ sudo apt-get install libhal-dev
+
+To see if you have the right libraries installed in order to compile, you can
+try compiling the test_noticer.c file, by running the test_noticer_compile.sh
+shell script, as follows:
+
+source test_noticer_compile.sh
+
+Then, run test_noticer, and when it's running you should see messages when
+you plug, or un-plug a joystick.
+
+Thanks to Dan Willmans, Seth Nickell, and David Zeuthen for their
+invaluable help with the whole dbus/hal part. Also, thanks to Hans-Christoph
+Steiner for his help with (and creation of) the joystick external.
+
+For good examples and reference on dbus/hal, please see:
+NetworkManager.c: http://cvs.gnome.org/viewcvs/NetworkManager/src/NetworkManager.c?rev=1.100&view=markup
+libhal.h: http://webcvs.freedesktop.org/hal/hal/libhal/libhal.h?rev=1.32&view=markup
+
+Parts of this code were pulled from those examples.
+
diff --git a/input_noticer.c b/input_noticer.c
new file mode 100644
index 0000000..ef2c91a
--- /dev/null
+++ b/input_noticer.c
@@ -0,0 +1,371 @@
+/*
+ * input_noticer - input noticer external for pure-data
+ *
+ * David Merrill <dmerrill@media.mit.edu>
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <libhal.h>
+#include <stdio.h>
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <stdlib.h>
+#include <string.h>
+#include "input_noticer.h"
+
+static char *version = "$Revision: 1.1.1.1 $";
+#define MAX_INPUT_DEVICES 32
+
+/*------------------------------------------------------------------------------
+ * CLASS DEF
+ */
+
+typedef struct callback_info {
+ void (*device_added)(char *device_file);
+ void (*device_removed)(char *device_file);
+} callback_info;
+
+static t_class *input_noticer_class;
+
+typedef struct _input_noticer {
+ t_object x_obj;
+ GMainContext *gmc;
+ GMainLoop *gml;
+ callback_info *cbi;
+ LibHalContext *lhc;
+ DBusConnection *connection;
+ char *capability;
+ char *product_substring;
+ int device_idx;
+ t_outlet *notify_out;
+ char *last_notification_sent;
+ GThread *gthread;
+ int started;
+} t_input_noticer;
+
+int udi_matches_device(LibHalContext *ctx, const char *udi);
+static void output_list(t_input_noticer *x, t_symbol *s, int argc, t_atom *argv);
+
+/*------------------------------------------------------------------------------
+ * IMPLEMENTATION
+ */
+
+static void output_inputpath(t_input_noticer *x, int idx, char *path)
+{
+ t_atom t[2];
+
+ // set up the output array
+ SETFLOAT(&(t[0]),idx);
+ SETSYMBOL(&(t[1]),gensym(path));
+
+ // output a list
+ outlet_list(x->notify_out, &s_list, 2, t);
+}
+
+int scmp(const void *sp1, const void *sp2 )
+{
+ return( strcmp(*(char **)sp1, *(char **)sp2) );
+}
+
+void scan_for_devices(LibHalContext *ctx) {
+ char ** input_devices;
+ int num_input_devices;
+ int i,j;
+ int this_device_idx;
+ DBusError dbus_error;
+ char *linux_device_file = NULL;
+ char *found_devices[MAX_INPUT_DEVICES];
+ t_input_noticer *x = libhal_ctx_get_user_data(ctx);
+
+ /// can't do anything here if we don't have a pointer back to our struct
+ if (x == NULL) return;
+
+ // not really using this, but why not initialize... :)
+ dbus_error_init (&dbus_error);
+
+ // grab an array of all devices that match the capability we're looking for
+ input_devices = libhal_find_device_by_capability (ctx, "input", &num_input_devices, &dbus_error);
+ if (dbus_error_is_set (&dbus_error))
+ {
+ post("could not find existing networking devices: %s\n", dbus_error.message);
+ dbus_error_free (&dbus_error);
+ return;
+ }
+
+ if (input_devices)
+ {
+ // we found at least one
+ this_device_idx = 0;
+ for (i = 0; i < num_input_devices; i++)
+ {
+ if (udi_matches_device(ctx, input_devices[i]))
+ {
+ post("found a %s",x->product_substring);
+
+ // get the linux.device_file
+ linux_device_file = libhal_device_get_property_string(ctx, input_devices[i],"linux.device_file", NULL);
+
+ // store the linux device file
+ found_devices[this_device_idx] = linux_device_file;
+
+ this_device_idx++;
+ }
+
+ }
+ // sort the devices alphabetically, so they will stay in the same order
+ qsort (found_devices, this_device_idx, sizeof (char *), scmp);
+ for (i = 0; i < this_device_idx; i++)
+ {
+ output_inputpath(x, i, found_devices[i]);
+ libhal_free_string(found_devices[i]);
+ }
+ libhal_free_string_array(input_devices);
+ } else {
+ post("no input devices found!");
+ }
+}
+
+// this function checks the UDI returned from libhal against the device product string
+// that we are looking
+int udi_matches_device(LibHalContext *ctx, const char *udi) {
+ t_input_noticer *x = libhal_ctx_get_user_data(ctx);
+ int i;
+ char *capability = malloc (strlen("input") + strlen(x->capability) + 2);
+ char *temp1;
+
+ sprintf(capability,"input.%s",x->capability);
+ temp1 = libhal_device_get_property_string (ctx, udi, "info.product", NULL);
+ if (libhal_device_property_exists(ctx, udi, "info.capabilities", NULL))
+ {
+ char **capabilities = libhal_device_get_property_strlist(ctx, udi, "info.capabilities", NULL);
+ for (i=0; capabilities[i] != NULL; i++)
+ {
+ //post("looking for %s, now checking capability #%d, %s",capability,i,capabilities[i]);
+ if (!strcmp (capabilities[i], capability))
+ {
+ char *temp = libhal_device_get_property_string (ctx, udi, "info.product", NULL);
+ if (temp != NULL && strstr(temp, x->product_substring)) // if product string matches up
+ {
+ libhal_free_string_array(capabilities);
+ libhal_free_string (temp);
+ free(capability);
+ return 1;
+ } else {
+ // product string does not match up
+ }
+
+ libhal_free_string (temp);
+ }
+ }
+ libhal_free_string_array(capabilities);
+ } else {
+ // no capabilities found
+ }
+ free(capability);
+ return 0;
+}
+
+// this callback gets called whenever HAL notices a new device being added
+void hal_device_added(LibHalContext *ctx, const char *udi) {
+ t_input_noticer *x = libhal_ctx_get_user_data(ctx);
+
+ if (x != NULL && x->started) {
+ if (udi_matches_device(ctx,udi)) {
+ scan_for_devices(ctx);
+ } else {
+ // post("nope");
+ }
+ }
+}
+
+void hal_device_removed(LibHalContext *ctx, const char *udi) {
+ // post("device removed, udi = %s\n", udi);
+}
+
+// I haven't seen this one get called... <Dm>
+void hal_device_new_capability(LibHalContext *ctx, const char *udi, const char *capability) {
+ // post("new device capability, udi = %s\n", udi);
+}
+
+void input_noticer_stop(t_input_noticer* x) {
+ DEBUG(post("input_noticer_stop"););
+
+ /* Signal the HAL listener to stop */
+ g_main_loop_quit(x->gml);
+
+ /* Wait until it has actually stopped */
+ g_thread_join(x->gthread);
+}
+
+static int input_noticer_close(t_input_noticer *x) {
+ DEBUG(post("input_noticer_close"););
+
+ input_noticer_stop(x);
+
+ if (x->product_substring) free(x->product_substring);
+ if (x->capability) free(x->capability);
+
+ return 1;
+}
+
+static int input_noticer_open(t_input_noticer *x, t_symbol *s) {
+ DEBUG(post("input_noticer_open");)
+
+ // close it down, if running already
+ input_noticer_close(x);
+
+ return 1;
+}
+
+void input_noticer_start(t_input_noticer* x) {
+ post("input_noticer: started");
+
+ x->started = 1;
+
+ // do first scan here (NOT in input_noticer_new, can't generate output from there)
+ scan_for_devices(x->lhc);
+}
+
+gpointer input_noticer_thread_main(gpointer user_data) {
+ t_input_noticer *x = (t_input_noticer *) user_data;
+
+ /* Run the main loop. We stay here until g_main_quit() is called */
+ g_main_loop_run(x->gml);
+
+ return user_data;
+}
+
+/* teardown functions */
+static void input_noticer_free(t_input_noticer* x) {
+ DEBUG(post("input_noticer_free");)
+}
+
+// removes double-quotes from a string, and returns a copy of it, otherwise unharmed
+static char *remove_quotes(char *input_str)
+{
+ char *rv, *tp;
+ unsigned int i;
+
+ post ("removing quotes from %s", input_str);
+
+ if (input_str != NULL)
+ {
+ rv = malloc ((strlen(input_str) + 1) * sizeof(char));
+ tp = rv;
+ for (i=0; i < strlen(input_str); i++) {
+ if (input_str[i] != '"') {
+ *tp = input_str[i];
+ tp++;
+ }
+ }
+ *tp = '\0';
+ } else {
+ return NULL;
+ }
+
+ post ("returning %s", rv);
+ return rv;
+}
+
+/* setup functions */
+static void *input_noticer_new(t_symbol *capability, t_symbol *product_substring) {
+ int i;
+ t_input_noticer *x = (t_input_noticer *)pd_new(input_noticer_class);
+
+ post("[input_noticer] %s, written by David Merrill <dmerrill@media.mit.edu>",version);
+
+ /* init vars */
+ x->gmc = NULL;
+ x->cbi = NULL;
+ x->lhc = NULL;
+ x->connection = NULL;
+ x->notify_out = NULL;
+ x->last_notification_sent = NULL;
+ x->started = 0;
+ x->capability = remove_quotes((char *)capability->s_name);
+ x->product_substring = remove_quotes((char *)product_substring->s_name);
+
+ // create outlet for notifying
+ x->notify_out = outlet_new(&x->x_obj, 0); // list outlet
+
+ // Setup glib and dbus for threading
+ g_type_init();
+ if (!g_thread_supported ())
+ g_thread_init (NULL);
+ dbus_g_thread_init();
+
+ // create a context for the callback functions
+ x->gmc = g_main_context_new();
+ x->gml = g_main_loop_new(x->gmc, FALSE);
+
+ // create a libhal context
+ if ((x->lhc = libhal_ctx_new()) == NULL) {
+ // complain here (exit)
+ DEBUG(post("input_noticer_open: error, could not create a libhal context!");)
+ }
+
+ // get the dbus connection
+ x->connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (x->connection == NULL) {
+ // complain here (exit)
+ DEBUG(post("input_noticer_open: error, could not get the DBUS connection!");)
+ }
+
+ // attaches the main loop to dbus, so that the main loop
+ // gets dbus events
+ dbus_connection_setup_with_g_main(x->connection,x->gmc);
+
+ // tells libhal to use our dbus connection, in order to receive
+ // events from hal
+ libhal_ctx_set_dbus_connection(x->lhc,x->connection);
+
+ if (!libhal_ctx_init (x->lhc, NULL)) {
+ DEBUG(post("input_noticer_open: error, could not init libhal!");)
+ }
+
+ // handing my custom data structure to libhal context, so that the callback functions
+ // can get to it
+ libhal_ctx_set_user_data(x->lhc, x);
+
+ libhal_ctx_set_device_added(x->lhc, hal_device_added);
+ libhal_ctx_set_device_removed(x->lhc, hal_device_removed);
+ libhal_ctx_set_device_new_capability(x->lhc, hal_device_new_capability);
+
+ /* Create the thread that listens for HAL events */
+ x->gthread = g_thread_create(input_noticer_thread_main, x, TRUE, NULL);
+
+ return (void *)x;
+}
+
+void input_noticer_setup(void) {
+ // DEBUG(post("input_noticer_setup");)
+
+ // define how the object gets instantiated
+ // example: [input_noticer joystick "SideWinder Dual Strike"]
+ input_noticer_class = class_new(
+ gensym("input_noticer"),
+ (t_newmethod)input_noticer_new,
+ (t_method)input_noticer_free,
+ sizeof(t_input_noticer),
+ CLASS_DEFAULT,
+ A_DEFSYMBOL,
+ A_DEFSYMBOL,
+ 0);
+
+ class_addbang(input_noticer_class, input_noticer_start);
+}
diff --git a/input_noticer.h b/input_noticer.h
new file mode 100644
index 0000000..5bedd24
--- /dev/null
+++ b/input_noticer.h
@@ -0,0 +1,58 @@
+#ifndef INPUT_NOTICER_H_
+#define INPUT_NOTICER_H_
+
+/*
+ * input_noticer - input noticer external for pure-data
+ *
+ * David Merrill <dmerrill@media.mit.edu>
+ *
+ * Description: Using dbus and the hardware abstraction layer (HAL) in linux,
+ * this external allows pd to find all linux device files for a given device type.
+ * This scanning behavior can happen when the external is set up (via a [bang]),
+ * and will happen automatically when a new device is added to the system. An
+ * example linux device file would be:
+ *
+ * /dev/input/event5
+ *
+ * The pd user specifies device type as a string - i.e. "SideWinder Dual Strike", and
+ * this external outputs lists containing an index, and the linux device file where
+ * each device of the given type was found. For example
+ *
+ * {0, /dev/input/event5}
+ * {1, /dev/input/event6}
+ *
+ * These lists can be routed in PD with the [route] object - see the help file for
+ * more details.
+ *
+ * Thanks to Dan Willmans, Seth Nickell, and David Zeuthen for their
+ * invaluable help with the whole dbus/hal part. Also, thanks to Hans-Christoph
+ * Steiner for his help with (and creation of) the joystick external.
+ *
+ * For good examples and reference on dbus/hal, please see:
+ * NetworkManager.c: http://cvs.gnome.org/viewcvs/NetworkManager/src/NetworkManager.c?rev=1.100&view=markup
+ * libhal.h: http://webcvs.freedesktop.org/hal/hal/libhal/libhal.h?rev=1.32&view=markup
+ *
+ * Parts of this code were pulled from those examples.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <m_pd.h>
+
+//#define DEBUG(x)
+#define DEBUG(x) x
+
+#endif /*INPUT_NOTICER_H_*/
diff --git a/noticer_test.pd b/noticer_test.pd
new file mode 100644
index 0000000..e001bc5
--- /dev/null
+++ b/noticer_test.pd
@@ -0,0 +1,12 @@
+#N canvas 0 0 450 300 10;
+#X obj 108 188 print A;
+#X obj 49 45 input_noticer joystick SideWinder;
+#X obj 133 137 route 0 1;
+#X obj 197 186 print C;
+#X obj 149 215 print B;
+#X obj 50 22 loadbang;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X connect 2 1 4 0;
+#X connect 2 2 3 0;
+#X connect 5 0 1 0;
diff --git a/test_noticer.c b/test_noticer.c
new file mode 100644
index 0000000..b963ae3
--- /dev/null
+++ b/test_noticer.c
@@ -0,0 +1,147 @@
+#include <libhal.h>
+#include <stdio.h>
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <stdlib.h>
+
+typedef struct callback_info {
+ void (*device_added)(char *device_file);
+ void (*device_removed)(char *device_file);
+} callback_info;
+
+// callback fns
+
+// this one actually never gets called in my experience <DJM>
+void hal_device_added(LibHalContext *ctx, const char *udi) {
+ int i, found_joystick;
+ char *linux_device_file = NULL;
+
+ printf("device added, udi = %s\n", udi);
+
+ // find out if this device advertises capabilities
+ if (libhal_device_property_exists(ctx, udi, "info.capabilities", NULL)) {
+ //printf("***** it's a joystick! *****\n");
+
+ // get the capabilities strlist
+ char **capabilities = libhal_device_get_property_strlist(ctx, udi, "info.capabilities", NULL);
+
+ // find out if it's a joystick
+ found_joystick = 0;
+ for (i=0; capabilities[i] != NULL; i++) {
+ if (!strcmp (capabilities[i], "input.joystick")) {
+ char **linux_device_file_strlist;
+ found_joystick = 1;
+
+ // printf("found a joystick!\n");
+
+ // pull out the relevant information (note - in Device Manager, this is reported incorrectly as a strlist,
+ // whereas it actually returns a string - so we make the correct call here
+ linux_device_file = libhal_device_get_property_string(ctx, udi, "linux.device_file", NULL);
+
+ if (linux_device_file != NULL) {
+ // linux_device_file = linux_device_file_strlist[0];
+ printf("found the joystick at: %s\n", linux_device_file);
+
+ } else {
+ // we didn't find the device file, better luck next time
+
+ }
+ }
+ // printf("got the following: %s\n", capabilities[i]);
+ }
+ }
+}
+
+void hal_device_removed(LibHalContext *ctx, const char *udi) {
+ printf("device removed, udi = %s\n", udi);
+}
+
+void hal_device_new_capability(LibHalContext *ctx, const char *udi, const char *capability) {
+ char *device;
+ callback_info *cbi = (callback_info *)libhal_ctx_get_user_data(ctx);
+
+ printf("device has a new capability, udi = %s, cap = %s\n", udi, capability);
+
+ if (capability && ((strcmp (capability, "input") == 0))) {
+ //
+ if (libhal_device_property_exists(ctx, udi, "input.device", NULL)) {
+ device = libhal_device_get_property_string(ctx, udi, "input.device",NULL);
+
+ // this is the callback into my PD C code
+ // (*(cbi->device_added))(device);
+ printf("new capability, testing: %s\n",device);
+ }
+ }
+}
+
+
+
+gpointer hal_thread_main(gpointer user_data) {
+ callback_info *cbi = (callback_info *)(user_data);
+ GMainContext *gmc;
+ GMainLoop *gml;
+ LibHalContext *lhc;
+ DBusConnection *connection;
+
+ gmc = g_main_context_new();
+ gml = g_main_loop_new(gmc,FALSE);
+
+ if ((lhc = libhal_ctx_new()) == NULL) {
+ // complain here (exit)
+ }
+
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (connection == NULL) {
+
+ }
+
+ // attaches the main loop to dbus, so tha the main loop
+ // gets dbus events
+ dbus_connection_setup_with_g_main(connection,gmc);
+
+ // tells libhal to use our dbus connection, in order to receive
+ // events from hal
+ libhal_ctx_set_dbus_connection(lhc,connection);
+
+ if (!libhal_ctx_init (lhc, NULL)) {
+ // die
+ }
+
+ // handing my custom data structure to libhal context
+ libhal_ctx_set_user_data(lhc, cbi);
+
+ libhal_ctx_set_device_added(lhc, hal_device_added);
+ libhal_ctx_set_device_removed(lhc, hal_device_removed);
+ libhal_ctx_set_device_new_capability(lhc, hal_device_new_capability);
+
+ // Get stuck here forever, and ever, and ever....
+ g_main_loop_run(gml);
+}
+
+GThread *hal_thread(callback_info *cbi) {
+ GThread *rv;
+
+ // eventually, we will pass in some user data here (the first NULL)
+ // this could be a fn pointer, or a structure with a few fn pointers,
+ // etc, so that
+ rv = g_thread_create(hal_thread_main, cbi, TRUE, NULL);
+ return(rv);
+}
+
+int main(int argc, char **argv) {
+ GThread *gth;
+ callback_info * cbi = malloc (sizeof (callback_info));
+
+ // Setup glib
+ g_type_init();
+ if (!g_thread_supported ())
+ g_thread_init (NULL);
+
+ dbus_g_thread_init();
+
+ gth = hal_thread(cbi);
+ while (1) {
+ sleep(1);
+ }
+}
+
diff --git a/test_noticer_compile.sh b/test_noticer_compile.sh
new file mode 100644
index 0000000..7adc18a
--- /dev/null
+++ b/test_noticer_compile.sh
@@ -0,0 +1 @@
+gcc `pkg-config --cflags --libs glib-2.0 hal dbus-glib-1 gthread-2.0` -o test_noticer test_noticer.c