pcb 4.1.1
An interactive printed circuit board layout editor.

dbus-pcbmain.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 
00032 #ifdef HAVE_CONFIG_H
00033 #include "config.h"
00034 #endif
00035 
00036 #define DBUS_API_SUBJECT_TO_CHANGE
00037 #include <dbus/dbus.h>
00038 #include <stdio.h>
00039 
00040 #include "global.h"
00041 #include "dbus-pcbmain.h"
00042 
00043 typedef struct _IOWatchHandler IOWatchHandler;
00044 typedef struct _TimeoutHandler TimeoutHandler;
00045 
00046 struct _IOWatchHandler
00047 {
00048   DBusWatch *dbus_watch;
00049   hidval pcb_watch;
00050 };
00051 
00052 struct _TimeoutHandler
00053 {
00054   DBusTimeout *dbus_timeout;
00055   hidval pcb_timer;
00056   int interval;
00057 };
00058 
00059 
00060 static void
00061 block_hook_cb (hidval data)
00062 {
00063   DBusConnection *connection = (DBusConnection *) data.ptr;
00064   if (dbus_connection_get_dispatch_status (connection) !=
00065       DBUS_DISPATCH_DATA_REMAINS)
00066     return;
00067 
00068   // TODO: IS THIS NEEDED?
00069   // dbus_connection_ref (connection);
00070 
00071   /* Only dispatch once - we don't want to starve other mainloop users */
00072   dbus_connection_dispatch (connection);
00073 
00074   // dbus_connection_unref (connection);
00075   return;
00076 }
00077 
00078 static void
00079 io_watch_handler_dbus_freed (void *data)
00080 {
00081   IOWatchHandler *handler;
00082   handler = (IOWatchHandler *)data;
00083 
00084   // Remove the watch registered with the HID
00085   gui->unwatch_file (handler->pcb_watch);
00086   free (handler);
00087 }
00088 
00089 
00090 void
00091 io_watch_handler_cb (hidval pcb_watch,
00092                      int fd, unsigned int condition, hidval data)
00093 {
00094   IOWatchHandler *handler;
00095   unsigned int dbus_condition = 0;
00096 
00097   handler = (IOWatchHandler *) data.ptr;
00098 
00099   // TODO: IS THIS NEEDED?
00100   //if (connection)
00101   //  dbus_connection_ref (connection);
00102 
00103   if (condition & PCB_WATCH_READABLE)
00104     dbus_condition |= DBUS_WATCH_READABLE;
00105   if (condition & PCB_WATCH_WRITABLE)
00106     dbus_condition |= DBUS_WATCH_WRITABLE;
00107   if (condition & PCB_WATCH_ERROR)
00108     dbus_condition |= DBUS_WATCH_ERROR;
00109   if (condition & PCB_WATCH_HANGUP)
00110     dbus_condition |= DBUS_WATCH_HANGUP;
00111 
00112   /* We don't touch the handler after this, because DBus
00113    * may have disabled the watch and thus killed the handler
00114    */
00115   dbus_watch_handle (handler->dbus_watch, dbus_condition);
00116   handler = NULL;
00117 
00118   //if (connection)
00119   //  dbus_connection_unref (connection);
00120 
00121   return;
00122 }
00123 
00124 
00125 static void
00126 timeout_handler_dbus_freed (void *data)
00127 {
00128   TimeoutHandler *handler;
00129   handler = (TimeoutHandler *)data;
00130 
00131   // Remove the timeout registered with the HID
00132   gui->stop_timer (handler->pcb_timer);
00133   free (handler);
00134 }
00135 
00136 
00137 void
00138 timeout_handler_cb (hidval data)
00139 {
00140   TimeoutHandler *handler;
00141   handler = (TimeoutHandler *)data.ptr;
00142 
00143   // Re-add the timeout, as PCB will remove the current one
00144   // Do this before calling to dbus, incase DBus removes the timeout.
00145   // We can't touch handler after libdbus has been run for this reason.
00146   handler->pcb_timer =
00147     gui->add_timer (timeout_handler_cb, handler->interval, data);
00148 
00149   dbus_timeout_handle (handler->dbus_timeout);
00150 }
00151 
00152 
00153 static dbus_bool_t
00154 watch_add (DBusWatch * dbus_watch, void *data)
00155 {
00156   IOWatchHandler *handler;
00157   int fd;
00158   unsigned int pcb_condition;
00159   unsigned int dbus_flags;
00160   hidval temp;
00161 
00162   // We won't create a watch until it becomes enabled.
00163   if (!dbus_watch_get_enabled (dbus_watch))
00164     return TRUE;
00165 
00166   dbus_flags = dbus_watch_get_flags (dbus_watch);
00167 
00168   pcb_condition = PCB_WATCH_ERROR | PCB_WATCH_HANGUP;
00169   if (dbus_flags & DBUS_WATCH_READABLE)
00170     pcb_condition |= PCB_WATCH_READABLE;
00171   if (dbus_flags & DBUS_WATCH_WRITABLE)
00172     pcb_condition |= PCB_WATCH_READABLE;
00173 
00174 #if HAVE_DBUS_WATCH_GET_UNIX_FD
00175   fd = dbus_watch_get_unix_fd (dbus_watch);
00176 #else
00177   fd = dbus_watch_get_fd (dbus_watch);
00178 #endif
00179 
00180   handler = (IOWatchHandler *)malloc (sizeof (IOWatchHandler));
00181   temp.ptr = (void *)handler;
00182   handler->dbus_watch = dbus_watch;
00183   handler->pcb_watch =
00184     gui->watch_file (fd, pcb_condition, io_watch_handler_cb, temp);
00185 
00186   dbus_watch_set_data (dbus_watch, handler, io_watch_handler_dbus_freed);
00187   return TRUE;
00188 }
00189 
00190 static void
00191 watch_remove (DBusWatch * dbus_watch, void *data)
00192 {
00193   // Free the associated data. Its destroy callback removes the watch
00194   dbus_watch_set_data (dbus_watch, NULL, NULL);
00195 }
00196 
00197 static void
00198 watch_toggled (DBusWatch * dbus_watch, void *data)
00199 {
00200   /* Simply add/remove the watch completely */
00201   if (dbus_watch_get_enabled (dbus_watch))
00202     watch_add (dbus_watch, data);
00203   else
00204     watch_remove (dbus_watch, data);
00205 }
00206 
00207 
00208 static dbus_bool_t
00209 timeout_add (DBusTimeout * timeout, void *data)
00210 {
00211   TimeoutHandler *handler;
00212   hidval temp;
00213 
00214   // We won't create a timeout until it becomes enabled.
00215   if (!dbus_timeout_get_enabled (timeout))
00216     return TRUE;
00217 
00218   //FIXME: Need to store the interval, as PCB requires us
00219   //       to manually re-add the timer each time it expires.
00220   //       This is non-ideal, and hopefully can be changed?
00221 
00222   handler = (TimeoutHandler *)malloc (sizeof (TimeoutHandler));
00223   temp.ptr = (void *)handler;
00224   handler->dbus_timeout = timeout;
00225   handler->interval = dbus_timeout_get_interval (timeout);
00226   handler->pcb_timer =
00227     gui->add_timer (timeout_handler_cb, handler->interval, temp);
00228 
00229   dbus_timeout_set_data (timeout, handler, timeout_handler_dbus_freed);
00230   return TRUE;
00231 }
00232 
00233 static void
00234 timeout_remove (DBusTimeout * timeout, void *data)
00235 {
00236   // Free the associated data. Its destroy callback removes the timer
00237   dbus_timeout_set_data (timeout, NULL, NULL);
00238 }
00239 
00240 static void
00241 timeout_toggled (DBusTimeout * timeout, void *data)
00242 {
00243   /* Simply add/remove the timeout completely */
00244   if (dbus_timeout_get_enabled (timeout))
00245     timeout_add (timeout, data);
00246   else
00247     timeout_remove (timeout, data);
00248 }
00249 
00250 void
00251 dispatch_status_changed (DBusConnection * conn, DBusDispatchStatus new_status,
00252                          void *data)
00253 {
00254   // TODO: Can use this eventually to add one-shot idle work-functions to dispatch
00255   //       remaining IO. It could possibly replace the block_hook polling mechanism.
00256   //       (We could use a one-shot block_book to dispatch the work though.)
00257   //
00258   //       *** NO DISPATCHING TO BE DONE INSIDE THIS FUNCTION ***
00259 }
00260 
00261 // END INTERNALS
00262 
00263 
00270 void
00271 pcb_dbus_connection_setup_with_mainloop (DBusConnection * connection)
00272 {
00273   //ConnectionSetup *cs;
00274   hidval temp;
00275 
00276   /* FIXME we never free the slot, so its refcount just keeps growing,
00277    * which is kind of broken.
00278    */
00279   //dbus_connection_allocate_data_slot (&connection_slot);
00280   //if (connection_slot < 0)
00281   //  goto nomem;
00282 
00283 #if 0
00284   cs = connection_setup_new (connection);
00285 
00286   if (!dbus_connection_set_data (connection, connection_slot, cs,
00287                                  (DBusFreeFunction) connection_setup_free))
00288     goto nomem;
00289 #endif
00290 
00291   if (!dbus_connection_set_watch_functions (connection,
00292                                             watch_add,
00293                                             watch_remove,
00294                                             watch_toggled, NULL, NULL))
00295 //                                            cs, NULL))
00296     goto nomem;
00297 
00298   if (!dbus_connection_set_timeout_functions (connection,
00299                                               timeout_add,
00300                                               timeout_remove,
00301                                               timeout_toggled, NULL, NULL))
00302 //                                              cs, NULL))
00303     goto nomem;
00304 
00305   dbus_connection_set_dispatch_status_function (connection,
00306                                                 dispatch_status_changed,
00307                                                 NULL, NULL);
00308 //                                                cs, NULL);
00309 
00310   /* Register a new mainloop hook to mop up any unfinished IO. */
00311   temp.ptr = (void *)connection;
00312   gui->add_block_hook (block_hook_cb, temp);
00313 
00314   return;
00315 nomem:
00316   fprintf (stderr,
00317            "Not enough memory to set up DBusConnection for use with PCB\n");
00318 }
00319 
00320 void
00321 pcb_dbus_connection_finish_with_mainloop (DBusConnection * connection)
00322 {
00323   //ConnectionSetup *cs;
00324 
00325   //cs = dbus_connection_get_data (connection, connection_slot );
00326 
00327   // Replace the stored data with NULL, thus freeing the old data
00328   // DBus will call the function connection_setup_free() which we registered earlier
00329   //dbus_connection_set_data (connection, connection_slot, NULL, NULL );
00330 
00331   //dbus_connection_free_data_slot( &connection_slot );
00332 
00333   if (!dbus_connection_set_watch_functions (connection,
00334                                             NULL, NULL, NULL, NULL, NULL))
00335     goto nomem;
00336 
00337   if (!dbus_connection_set_timeout_functions (connection,
00338                                               NULL, NULL, NULL, NULL, NULL))
00339     goto nomem;
00340 
00341   dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL);
00342   return;
00343 nomem:
00344   fprintf (stderr,
00345            "Not enough memory when cleaning up DBusConnection mainloop integration\n");
00346 
00347 }