pcb 4.1.1
An interactive printed circuit board layout editor.
|
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 }