Fix distribution of gnet-pcbfwd.scm in the dist tarball
[geda-pcb/gde.git] / src / dbus-pcbmain.c
blob83b2e973045ed4660b4b0c92dc0b4a712930d6ab
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-pcbmain.c PCB HID main loop integration
4 * Adapted from dbus-gmain.c from dbus-glib bindings:
5 * Copyright (C) 2002, 2003 CodeFactory AB
6 * Copyright (C) 2005 Red Hat, Inc.
8 * Licensed under the Academic Free License version 2.1
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
31 #define DBUS_API_SUBJECT_TO_CHANGE
32 #include <dbus/dbus.h>
33 #include <stdio.h>
35 #include "global.h"
36 #include "dbus-pcbmain.h"
38 typedef struct _IOWatchHandler IOWatchHandler;
39 typedef struct _TimeoutHandler TimeoutHandler;
41 struct _IOWatchHandler
43 DBusWatch *dbus_watch;
44 hidval pcb_watch;
47 struct _TimeoutHandler
49 DBusTimeout *dbus_timeout;
50 hidval pcb_timer;
51 int interval;
55 static void
56 block_hook_cb (hidval data)
58 DBusConnection *connection = (DBusConnection *) data.ptr;
59 if (dbus_connection_get_dispatch_status (connection) !=
60 DBUS_DISPATCH_DATA_REMAINS)
61 return;
63 // TODO: IS THIS NEEDED?
64 // dbus_connection_ref (connection);
66 /* Only dispatch once - we don't want to starve other mainloop users */
67 dbus_connection_dispatch (connection);
69 // dbus_connection_unref (connection);
70 return;
73 static void
74 io_watch_handler_dbus_freed (void *data)
76 IOWatchHandler *handler;
77 handler = data;
79 // Remove the watch registered with the HID
80 gui->unwatch_file (handler->pcb_watch);
81 free (handler);
85 void
86 io_watch_handler_cb (hidval pcb_watch,
87 int fd, unsigned int condition, hidval data)
89 IOWatchHandler *handler;
90 unsigned int dbus_condition = 0;
92 handler = (IOWatchHandler *) data.ptr;
94 // TODO: IS THIS NEEDED?
95 //if (connection)
96 // dbus_connection_ref (connection);
98 if (condition & PCB_WATCH_READABLE)
99 dbus_condition |= DBUS_WATCH_READABLE;
100 if (condition & PCB_WATCH_WRITABLE)
101 dbus_condition |= DBUS_WATCH_WRITABLE;
102 if (condition & PCB_WATCH_ERROR)
103 dbus_condition |= DBUS_WATCH_ERROR;
104 if (condition & PCB_WATCH_HANGUP)
105 dbus_condition |= DBUS_WATCH_HANGUP;
107 /* We don't touch the handler after this, because DBus
108 * may have disabled the watch and thus killed the handler
110 dbus_watch_handle (handler->dbus_watch, dbus_condition);
111 handler = NULL;
113 //if (connection)
114 // dbus_connection_unref (connection);
116 return;
120 static void
121 timeout_handler_dbus_freed (void *data)
123 TimeoutHandler *handler;
124 handler = data;
126 // Remove the timeout registered with the HID
127 gui->stop_timer (handler->pcb_timer);
128 free (handler);
132 void
133 timeout_handler_cb (hidval data)
135 TimeoutHandler *handler;
136 handler = data.ptr;
138 // Re-add the timeout, as PCB will remove the current one
139 // Do this before calling to dbus, incase DBus removes the timeout.
140 // We can't touch handler after libdbus has been run for this reason.
141 handler->pcb_timer =
142 gui->add_timer (timeout_handler_cb, handler->interval, data);
144 dbus_timeout_handle (handler->dbus_timeout);
148 static dbus_bool_t
149 watch_add (DBusWatch * dbus_watch, void *data)
151 IOWatchHandler *handler;
152 int fd;
153 unsigned int pcb_condition;
154 unsigned int dbus_flags;
156 // We won't create a watch until it becomes enabled.
157 if (!dbus_watch_get_enabled (dbus_watch))
158 return TRUE;
160 dbus_flags = dbus_watch_get_flags (dbus_watch);
162 pcb_condition = PCB_WATCH_ERROR | PCB_WATCH_HANGUP;
163 if (dbus_flags & DBUS_WATCH_READABLE)
164 pcb_condition |= PCB_WATCH_READABLE;
165 if (dbus_flags & DBUS_WATCH_WRITABLE)
166 pcb_condition |= PCB_WATCH_READABLE;
168 #if HAVE_DBUS_WATCH_GET_UNIX_FD
169 fd = dbus_watch_get_unix_fd (dbus_watch);
170 #else
171 fd = dbus_watch_get_fd (dbus_watch);
172 #endif
174 handler = malloc (sizeof (IOWatchHandler));
175 handler->dbus_watch = dbus_watch;
176 handler->pcb_watch =
177 gui->watch_file (fd, pcb_condition, io_watch_handler_cb,
178 (hidval) (void *) handler);
180 dbus_watch_set_data (dbus_watch, handler, io_watch_handler_dbus_freed);
181 return TRUE;
184 static void
185 watch_remove (DBusWatch * dbus_watch, void *data)
187 // Free the associated data. Its destroy callback removes the watch
188 dbus_watch_set_data (dbus_watch, NULL, NULL);
191 static void
192 watch_toggled (DBusWatch * dbus_watch, void *data)
194 /* Simply add/remove the watch completely */
195 if (dbus_watch_get_enabled (dbus_watch))
196 watch_add (dbus_watch, data);
197 else
198 watch_remove (dbus_watch, data);
202 static dbus_bool_t
203 timeout_add (DBusTimeout * timeout, void *data)
205 TimeoutHandler *handler;
207 // We won't create a timeout until it becomes enabled.
208 if (!dbus_timeout_get_enabled (timeout))
209 return TRUE;
211 //FIXME: Need to store the interval, as PCB requires us
212 // to manually re-add the timer each time it expires.
213 // This is non-ideal, and hopefully can be changed?
215 handler = malloc (sizeof (TimeoutHandler));
216 handler->dbus_timeout = timeout;
217 handler->interval = dbus_timeout_get_interval (timeout);
218 handler->pcb_timer =
219 gui->add_timer (timeout_handler_cb, handler->interval,
220 (hidval) (void *) handler);
222 dbus_timeout_set_data (timeout, handler, timeout_handler_dbus_freed);
223 return TRUE;
226 static void
227 timeout_remove (DBusTimeout * timeout, void *data)
229 // Free the associated data. Its destroy callback removes the timer
230 dbus_timeout_set_data (timeout, NULL, NULL);
233 static void
234 timeout_toggled (DBusTimeout * timeout, void *data)
236 /* Simply add/remove the timeout completely */
237 if (dbus_timeout_get_enabled (timeout))
238 timeout_add (timeout, data);
239 else
240 timeout_remove (timeout, data);
243 void
244 dispatch_status_changed (DBusConnection * conn, DBusDispatchStatus new_status,
245 void *data)
247 // TODO: Can use this eventually to add one-shot idle work-functions to dispatch
248 // remaining IO. It could possibly replace the block_hook polling mechanism.
249 // (We could use a one-shot block_book to dispatch the work though.)
251 // *** NO DISPATCHING TO BE DONE INSIDE THIS FUNCTION ***
254 // END INTERNALS
258 * Sets the watch and timeout functions of a #DBusConnection
259 * to integrate the connection with the GUI HID's main loop.
261 * @param connection the connection
263 void
264 pcb_dbus_connection_setup_with_mainloop (DBusConnection * connection)
266 //ConnectionSetup *cs;
268 /* FIXME we never free the slot, so its refcount just keeps growing,
269 * which is kind of broken.
271 //dbus_connection_allocate_data_slot (&connection_slot);
272 //if (connection_slot < 0)
273 // goto nomem;
275 #if 0
276 cs = connection_setup_new (connection);
278 if (!dbus_connection_set_data (connection, connection_slot, cs,
279 (DBusFreeFunction) connection_setup_free))
280 goto nomem;
281 #endif
283 if (!dbus_connection_set_watch_functions (connection,
284 watch_add,
285 watch_remove,
286 watch_toggled, NULL, NULL))
287 // cs, NULL))
288 goto nomem;
290 if (!dbus_connection_set_timeout_functions (connection,
291 timeout_add,
292 timeout_remove,
293 timeout_toggled, NULL, NULL))
294 // cs, NULL))
295 goto nomem;
297 dbus_connection_set_dispatch_status_function (connection,
298 dispatch_status_changed,
299 NULL, NULL);
300 // cs, NULL);
302 /* Register a new mainloop hook to mop up any unfinished IO. */
303 gui->add_block_hook (block_hook_cb, (hidval) (void *) connection);
305 return;
306 nomem:
307 fprintf (stderr,
308 "Not enough memory to set up DBusConnection for use with PCB\n");
311 void
312 pcb_dbus_connection_finish_with_mainloop (DBusConnection * connection)
314 //ConnectionSetup *cs;
316 //cs = dbus_connection_get_data (connection, connection_slot );
318 // Replace the stored data with NULL, thus freeing the old data
319 // DBus will call the function connection_setup_free() which we registered earlier
320 //dbus_connection_set_data (connection, connection_slot, NULL, NULL );
322 //dbus_connection_free_data_slot( &connection_slot );
324 if (!dbus_connection_set_watch_functions (connection,
325 NULL, NULL, NULL, NULL, NULL))
326 goto nomem;
328 if (!dbus_connection_set_timeout_functions (connection,
329 NULL, NULL, NULL, NULL, NULL))
330 goto nomem;
332 dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL);
333 return;
334 nomem:
335 fprintf (stderr,
336 "Not enough memory when cleaning up DBusConnection mainloop integration\n");