(no commit message)
[geda-pcb/pcjc2.git] / src / dbus-pcbmain.c
blob07e68c0d68984e3394eb61b34d37cc51a283e302
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 = (IOWatchHandler *)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 = (TimeoutHandler *)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 = (TimeoutHandler *)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;
155 hidval temp;
157 // We won't create a watch until it becomes enabled.
158 if (!dbus_watch_get_enabled (dbus_watch))
159 return TRUE;
161 dbus_flags = dbus_watch_get_flags (dbus_watch);
163 pcb_condition = PCB_WATCH_ERROR | PCB_WATCH_HANGUP;
164 if (dbus_flags & DBUS_WATCH_READABLE)
165 pcb_condition |= PCB_WATCH_READABLE;
166 if (dbus_flags & DBUS_WATCH_WRITABLE)
167 pcb_condition |= PCB_WATCH_READABLE;
169 #if HAVE_DBUS_WATCH_GET_UNIX_FD
170 fd = dbus_watch_get_unix_fd (dbus_watch);
171 #else
172 fd = dbus_watch_get_fd (dbus_watch);
173 #endif
175 handler = (IOWatchHandler *)malloc (sizeof (IOWatchHandler));
176 temp.ptr = (void *)handler;
177 handler->dbus_watch = dbus_watch;
178 handler->pcb_watch =
179 gui->watch_file (fd, pcb_condition, io_watch_handler_cb, temp);
181 dbus_watch_set_data (dbus_watch, handler, io_watch_handler_dbus_freed);
182 return TRUE;
185 static void
186 watch_remove (DBusWatch * dbus_watch, void *data)
188 // Free the associated data. Its destroy callback removes the watch
189 dbus_watch_set_data (dbus_watch, NULL, NULL);
192 static void
193 watch_toggled (DBusWatch * dbus_watch, void *data)
195 /* Simply add/remove the watch completely */
196 if (dbus_watch_get_enabled (dbus_watch))
197 watch_add (dbus_watch, data);
198 else
199 watch_remove (dbus_watch, data);
203 static dbus_bool_t
204 timeout_add (DBusTimeout * timeout, void *data)
206 TimeoutHandler *handler;
207 hidval temp;
209 // We won't create a timeout until it becomes enabled.
210 if (!dbus_timeout_get_enabled (timeout))
211 return TRUE;
213 //FIXME: Need to store the interval, as PCB requires us
214 // to manually re-add the timer each time it expires.
215 // This is non-ideal, and hopefully can be changed?
217 handler = (TimeoutHandler *)malloc (sizeof (TimeoutHandler));
218 temp.ptr = (void *)handler;
219 handler->dbus_timeout = timeout;
220 handler->interval = dbus_timeout_get_interval (timeout);
221 handler->pcb_timer =
222 gui->add_timer (timeout_handler_cb, handler->interval, temp);
224 dbus_timeout_set_data (timeout, handler, timeout_handler_dbus_freed);
225 return TRUE;
228 static void
229 timeout_remove (DBusTimeout * timeout, void *data)
231 // Free the associated data. Its destroy callback removes the timer
232 dbus_timeout_set_data (timeout, NULL, NULL);
235 static void
236 timeout_toggled (DBusTimeout * timeout, void *data)
238 /* Simply add/remove the timeout completely */
239 if (dbus_timeout_get_enabled (timeout))
240 timeout_add (timeout, data);
241 else
242 timeout_remove (timeout, data);
245 void
246 dispatch_status_changed (DBusConnection * conn, DBusDispatchStatus new_status,
247 void *data)
249 // TODO: Can use this eventually to add one-shot idle work-functions to dispatch
250 // remaining IO. It could possibly replace the block_hook polling mechanism.
251 // (We could use a one-shot block_book to dispatch the work though.)
253 // *** NO DISPATCHING TO BE DONE INSIDE THIS FUNCTION ***
256 // END INTERNALS
260 * Sets the watch and timeout functions of a #DBusConnection
261 * to integrate the connection with the GUI HID's main loop.
263 * @param connection the connection
265 void
266 pcb_dbus_connection_setup_with_mainloop (DBusConnection * connection)
268 //ConnectionSetup *cs;
269 hidval temp;
271 /* FIXME we never free the slot, so its refcount just keeps growing,
272 * which is kind of broken.
274 //dbus_connection_allocate_data_slot (&connection_slot);
275 //if (connection_slot < 0)
276 // goto nomem;
278 #if 0
279 cs = connection_setup_new (connection);
281 if (!dbus_connection_set_data (connection, connection_slot, cs,
282 (DBusFreeFunction) connection_setup_free))
283 goto nomem;
284 #endif
286 if (!dbus_connection_set_watch_functions (connection,
287 watch_add,
288 watch_remove,
289 watch_toggled, NULL, NULL))
290 // cs, NULL))
291 goto nomem;
293 if (!dbus_connection_set_timeout_functions (connection,
294 timeout_add,
295 timeout_remove,
296 timeout_toggled, NULL, NULL))
297 // cs, NULL))
298 goto nomem;
300 dbus_connection_set_dispatch_status_function (connection,
301 dispatch_status_changed,
302 NULL, NULL);
303 // cs, NULL);
305 /* Register a new mainloop hook to mop up any unfinished IO. */
306 temp.ptr = (void *)connection;
307 gui->add_block_hook (block_hook_cb, temp);
309 return;
310 nomem:
311 fprintf (stderr,
312 "Not enough memory to set up DBusConnection for use with PCB\n");
315 void
316 pcb_dbus_connection_finish_with_mainloop (DBusConnection * connection)
318 //ConnectionSetup *cs;
320 //cs = dbus_connection_get_data (connection, connection_slot );
322 // Replace the stored data with NULL, thus freeing the old data
323 // DBus will call the function connection_setup_free() which we registered earlier
324 //dbus_connection_set_data (connection, connection_slot, NULL, NULL );
326 //dbus_connection_free_data_slot( &connection_slot );
328 if (!dbus_connection_set_watch_functions (connection,
329 NULL, NULL, NULL, NULL, NULL))
330 goto nomem;
332 if (!dbus_connection_set_timeout_functions (connection,
333 NULL, NULL, NULL, NULL, NULL))
334 goto nomem;
336 dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL);
337 return;
338 nomem:
339 fprintf (stderr,
340 "Not enough memory when cleaning up DBusConnection mainloop integration\n");