Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

dbus-gmain.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */ 00002 /* dbus-gmain.c GLib main loop integration 00003 * 00004 * Copyright (C) 2002, 2003 CodeFactory AB 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include <dbus/dbus-glib.h> 00026 #include <dbus/dbus-glib-lowlevel.h> 00027 #include "dbus-gtest.h" 00028 #include "dbus-gutils.h" 00029 00030 #include <libintl.h> 00031 #define _(x) dgettext (GETTEXT_PACKAGE, x) 00032 #define N_(x) x 00033 00056 typedef struct DBusGSource DBusGSource; 00057 00061 struct DBusGSource 00062 { 00063 GSource source; 00065 GList *watch_fds; 00067 GMainContext *context; 00069 void *connection_or_server; 00070 }; 00071 00076 typedef struct 00077 { 00078 int refcount; 00080 GPollFD poll_fd; 00081 DBusWatch *watch; 00083 unsigned int removed : 1; 00084 } WatchFD; 00085 00086 static WatchFD * 00087 watch_fd_new (void) 00088 { 00089 WatchFD *watch_fd; 00090 00091 watch_fd = g_new0 (WatchFD, 1); 00092 watch_fd->refcount = 1; 00093 00094 return watch_fd; 00095 } 00096 00097 static WatchFD * 00098 watch_fd_ref (WatchFD *watch_fd) 00099 { 00100 watch_fd->refcount += 1; 00101 00102 return watch_fd; 00103 } 00104 00105 static void 00106 watch_fd_unref (WatchFD *watch_fd) 00107 { 00108 watch_fd->refcount -= 1; 00109 00110 if (watch_fd->refcount == 0) 00111 { 00112 g_assert (watch_fd->removed); 00113 00114 g_free (watch_fd); 00115 } 00116 } 00117 00118 static dbus_int32_t connection_slot = -1; 00119 static dbus_int32_t server_slot = -1; 00120 00121 static gboolean gsource_connection_prepare (GSource *source, 00122 gint *timeout); 00123 static gboolean gsource_connection_check (GSource *source); 00124 static gboolean gsource_connection_dispatch (GSource *source, 00125 GSourceFunc callback, 00126 gpointer user_data); 00127 static gboolean gsource_server_prepare (GSource *source, 00128 gint *timeout); 00129 static gboolean gsource_server_check (GSource *source); 00130 static gboolean gsource_server_dispatch (GSource *source, 00131 GSourceFunc callback, 00132 gpointer user_data); 00133 00134 static GSourceFuncs dbus_connection_funcs = { 00135 gsource_connection_prepare, 00136 gsource_connection_check, 00137 gsource_connection_dispatch, 00138 NULL 00139 }; 00140 00141 static GSourceFuncs dbus_server_funcs = { 00142 gsource_server_prepare, 00143 gsource_server_check, 00144 gsource_server_dispatch, 00145 NULL 00146 }; 00147 00148 static gboolean 00149 gsource_connection_prepare (GSource *source, 00150 gint *timeout) 00151 { 00152 DBusConnection *connection = ((DBusGSource *)source)->connection_or_server; 00153 00154 *timeout = -1; 00155 00156 return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS); 00157 } 00158 00159 static gboolean 00160 gsource_server_prepare (GSource *source, 00161 gint *timeout) 00162 { 00163 *timeout = -1; 00164 00165 return FALSE; 00166 } 00167 00168 static gboolean 00169 dbus_gsource_check (GSource *source) 00170 { 00171 DBusGSource *dbus_source = (DBusGSource *)source; 00172 GList *list; 00173 00174 list = dbus_source->watch_fds; 00175 00176 while (list) 00177 { 00178 WatchFD *watch_fd = list->data; 00179 00180 if (watch_fd->poll_fd.revents != 0) 00181 return TRUE; 00182 00183 list = list->next; 00184 } 00185 00186 return FALSE; 00187 } 00188 00189 static gboolean 00190 gsource_connection_check (GSource *source) 00191 { 00192 return dbus_gsource_check (source); 00193 } 00194 00195 static gboolean 00196 gsource_server_check (GSource *source) 00197 { 00198 return dbus_gsource_check (source); 00199 } 00200 00201 static gboolean 00202 dbus_gsource_dispatch (GSource *source, 00203 GSourceFunc callback, 00204 gpointer user_data, 00205 dbus_bool_t is_server) 00206 { 00207 DBusGSource *dbus_source = (DBusGSource *)source; 00208 GList *copy, *list; 00209 00210 /* Make a copy of the list and ref all WatchFDs */ 00211 copy = g_list_copy (dbus_source->watch_fds); 00212 g_list_foreach (copy, (GFunc)watch_fd_ref, NULL); 00213 00214 list = copy; 00215 while (list) 00216 { 00217 WatchFD *watch_fd = list->data; 00218 00219 if (!watch_fd->removed && watch_fd->poll_fd.revents != 0) 00220 { 00221 guint condition = 0; 00222 00223 if (watch_fd->poll_fd.revents & G_IO_IN) 00224 condition |= DBUS_WATCH_READABLE; 00225 if (watch_fd->poll_fd.revents & G_IO_OUT) 00226 condition |= DBUS_WATCH_WRITABLE; 00227 if (watch_fd->poll_fd.revents & G_IO_ERR) 00228 condition |= DBUS_WATCH_ERROR; 00229 if (watch_fd->poll_fd.revents & G_IO_HUP) 00230 condition |= DBUS_WATCH_HANGUP; 00231 00232 dbus_watch_handle (watch_fd->watch, condition); 00233 } 00234 00235 list = list->next; 00236 } 00237 00238 g_list_foreach (copy, (GFunc)watch_fd_unref, NULL); 00239 g_list_free (copy); 00240 00241 return TRUE; 00242 } 00243 00244 static gboolean 00245 gsource_connection_dispatch (GSource *source, 00246 GSourceFunc callback, 00247 gpointer user_data) 00248 { 00249 DBusGSource *dbus_source = (DBusGSource *)source; 00250 DBusConnection *connection = dbus_source->connection_or_server; 00251 00252 dbus_connection_ref (connection); 00253 00254 dbus_gsource_dispatch (source, callback, user_data, 00255 FALSE); 00256 00257 /* Dispatch messages */ 00258 while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS) 00259 ; 00260 00261 dbus_connection_unref (connection); 00262 00263 return TRUE; 00264 } 00265 00266 static gboolean 00267 gsource_server_dispatch (GSource *source, 00268 GSourceFunc callback, 00269 gpointer user_data) 00270 { 00271 DBusGSource *dbus_source = (DBusGSource *)source; 00272 DBusServer *server = dbus_source->connection_or_server; 00273 00274 dbus_server_ref (server); 00275 00276 dbus_gsource_dispatch (source, callback, user_data, 00277 TRUE); 00278 00279 dbus_server_unref (server); 00280 00281 return TRUE; 00282 } 00283 00284 static dbus_bool_t 00285 add_watch (DBusWatch *watch, 00286 gpointer data) 00287 { 00288 WatchFD *watch_fd; 00289 DBusGSource *dbus_source; 00290 guint flags; 00291 00292 if (!dbus_watch_get_enabled (watch)) 00293 return TRUE; 00294 00295 dbus_source = data; 00296 00297 watch_fd = watch_fd_new (); 00298 watch_fd->poll_fd.fd = dbus_watch_get_fd (watch); 00299 watch_fd->poll_fd.events = 0; 00300 flags = dbus_watch_get_flags (watch); 00301 dbus_watch_set_data (watch, watch_fd, (DBusFreeFunction)watch_fd_unref); 00302 00303 if (flags & DBUS_WATCH_READABLE) 00304 watch_fd->poll_fd.events |= G_IO_IN; 00305 if (flags & DBUS_WATCH_WRITABLE) 00306 watch_fd->poll_fd.events |= G_IO_OUT; 00307 watch_fd->poll_fd.events |= G_IO_ERR | G_IO_HUP; 00308 00309 watch_fd->watch = watch; 00310 00311 g_source_add_poll ((GSource *)dbus_source, &watch_fd->poll_fd); 00312 00313 dbus_source->watch_fds = g_list_prepend (dbus_source->watch_fds, watch_fd); 00314 00315 return TRUE; 00316 } 00317 00318 static void 00319 remove_watch (DBusWatch *watch, 00320 gpointer data) 00321 { 00322 DBusGSource *dbus_source = data; 00323 WatchFD *watch_fd; 00324 00325 watch_fd = dbus_watch_get_data (watch); 00326 if (watch_fd == NULL) 00327 return; /* probably a not-enabled watch that was added */ 00328 00329 watch_fd->removed = TRUE; 00330 watch_fd->watch = NULL; 00331 00332 dbus_source->watch_fds = g_list_remove (dbus_source->watch_fds, watch_fd); 00333 00334 g_source_remove_poll ((GSource *)dbus_source, &watch_fd->poll_fd); 00335 00336 dbus_watch_set_data (watch, NULL, NULL); /* needed due to watch_toggled 00337 * breaking add/remove symmetry 00338 */ 00339 } 00340 00341 static void 00342 watch_toggled (DBusWatch *watch, 00343 void *data) 00344 { 00345 /* Because we just exit on OOM, enable/disable is 00346 * no different from add/remove 00347 */ 00348 if (dbus_watch_get_enabled (watch)) 00349 add_watch (watch, data); 00350 else 00351 remove_watch (watch, data); 00352 } 00353 00354 static gboolean 00355 timeout_handler (gpointer data) 00356 { 00357 DBusTimeout *timeout = data; 00358 00359 dbus_timeout_handle (timeout); 00360 00361 return TRUE; 00362 } 00363 00364 static dbus_bool_t 00365 add_timeout (DBusTimeout *timeout, 00366 void *data) 00367 { 00368 DBusGSource *dbus_source = data; 00369 GSource *source; 00370 00371 if (!dbus_timeout_get_enabled (timeout)) 00372 return TRUE; 00373 00374 source = g_timeout_source_new (dbus_timeout_get_interval (timeout)); 00375 g_source_set_callback (source, timeout_handler, timeout, NULL); 00376 g_source_attach (source, dbus_source->context); 00377 00378 dbus_timeout_set_data (timeout, GUINT_TO_POINTER (g_source_get_id (source)), 00379 NULL); 00380 00381 return TRUE; 00382 } 00383 00384 static void 00385 remove_timeout (DBusTimeout *timeout, 00386 void *data) 00387 { 00388 guint timeout_tag; 00389 00390 timeout_tag = GPOINTER_TO_UINT (dbus_timeout_get_data (timeout)); 00391 00392 if (timeout_tag != 0) /* if 0, probably timeout was disabled */ 00393 g_source_remove (timeout_tag); 00394 } 00395 00396 static void 00397 timeout_toggled (DBusTimeout *timeout, 00398 void *data) 00399 { 00400 /* Because we just exit on OOM, enable/disable is 00401 * no different from add/remove 00402 */ 00403 if (dbus_timeout_get_enabled (timeout)) 00404 add_timeout (timeout, data); 00405 else 00406 remove_timeout (timeout, data); 00407 } 00408 00409 00410 static void 00411 free_source (GSource *source) 00412 { 00413 g_source_destroy (source); 00414 } 00415 00416 static void 00417 wakeup_main (void *data) 00418 { 00419 DBusGSource *dbus_source = data; 00420 00421 g_main_context_wakeup (dbus_source->context); 00422 } 00423 00424 /* End of GLib bindings internals */ 00426 00431 static GSource* 00432 create_source (void *connection_or_server, 00433 GSourceFuncs *funcs, 00434 GMainContext *context) 00435 { 00436 GSource *source; 00437 DBusGSource *dbus_source; 00438 00439 source = g_source_new (funcs, sizeof (DBusGSource)); 00440 00441 dbus_source = (DBusGSource *)source; 00442 dbus_source->connection_or_server = connection_or_server; 00443 dbus_source->context = context; 00444 00445 return source; 00446 } 00447 00462 void 00463 dbus_connection_setup_with_g_main (DBusConnection *connection, 00464 GMainContext *context) 00465 { 00466 GSource *source; 00467 00468 /* FIXME we never free the slot, so its refcount just keeps growing, 00469 * which is kind of broken. 00470 */ 00471 dbus_connection_allocate_data_slot (&connection_slot); 00472 if (connection_slot < 0) 00473 goto nomem; 00474 00475 /* So we can test for equality below */ 00476 if (context == NULL) 00477 context = g_main_context_default (); 00478 00479 source = dbus_connection_get_data (connection, connection_slot); 00480 if (source != NULL) 00481 { 00482 if (source->context == context) 00483 return; /* nothing to do */ 00484 00485 /* Remove the previous source and move to a new context */ 00486 dbus_connection_set_data (connection, connection_slot, NULL, NULL); 00487 source = NULL; 00488 } 00489 00490 source = create_source (connection, &dbus_connection_funcs, context); 00491 00492 if (!dbus_connection_set_watch_functions (connection, 00493 add_watch, 00494 remove_watch, 00495 watch_toggled, 00496 source, NULL)) 00497 goto nomem; 00498 00499 if (!dbus_connection_set_timeout_functions (connection, 00500 add_timeout, 00501 remove_timeout, 00502 timeout_toggled, 00503 source, NULL)) 00504 goto nomem; 00505 00506 dbus_connection_set_wakeup_main_function (connection, 00507 wakeup_main, 00508 source, NULL); 00509 00510 g_source_attach (source, context); 00511 00512 if (!dbus_connection_set_data (connection, connection_slot, source, 00513 (DBusFreeFunction)free_source)) 00514 goto nomem; 00515 00516 return; 00517 00518 nomem: 00519 g_error ("Not enough memory to set up DBusConnection for use with GLib"); 00520 } 00521 00535 void 00536 dbus_server_setup_with_g_main (DBusServer *server, 00537 GMainContext *context) 00538 { 00539 GSource *source; 00540 00541 dbus_server_allocate_data_slot (&server_slot); 00542 if (server_slot < 0) 00543 goto nomem; 00544 00545 /* So we can test for equality below */ 00546 if (context == NULL) 00547 context = g_main_context_default (); 00548 00549 source = dbus_server_get_data (server, server_slot); 00550 if (source != NULL) 00551 { 00552 if (source->context == context) 00553 return; /* nothing to do */ 00554 00555 /* Remove the previous source and move to a new context */ 00556 dbus_server_set_data (server, server_slot, NULL, NULL); 00557 source = NULL; 00558 } 00559 00560 source = create_source (server, &dbus_server_funcs, context); 00561 00562 dbus_server_set_watch_functions (server, 00563 add_watch, 00564 remove_watch, 00565 watch_toggled, 00566 source, NULL); 00567 00568 dbus_server_set_timeout_functions (server, 00569 add_timeout, 00570 remove_timeout, 00571 timeout_toggled, 00572 NULL, NULL); 00573 00574 g_source_attach (source, context); 00575 00576 if (!dbus_server_set_data (server, server_slot, source, 00577 (DBusFreeFunction)free_source)) 00578 goto nomem; 00579 00580 return; 00581 00582 nomem: 00583 g_error ("Not enough memory to set up DBusServer for use with GLib"); 00584 } 00585 00597 DBusGConnection* 00598 dbus_g_bus_get (DBusBusType type, 00599 GError **error) 00600 { 00601 DBusConnection *connection; 00602 DBusError derror; 00603 00604 g_return_val_if_fail (error == NULL || *error == NULL, NULL); 00605 00606 dbus_error_init (&derror); 00607 00608 connection = dbus_bus_get (type, &derror); 00609 if (connection == NULL) 00610 { 00611 dbus_set_g_error (error, &derror); 00612 dbus_error_free (&derror); 00613 } 00614 else 00615 { 00616 /* does nothing if it's already been done */ 00617 dbus_connection_setup_with_g_main (connection, NULL); 00618 } 00619 00620 return DBUS_G_CONNECTION_FROM_CONNECTION (connection); 00621 } 00622 00629 GQuark 00630 dbus_g_error_quark (void) 00631 { 00632 static GQuark quark = 0; 00633 if (quark == 0) 00634 quark = g_quark_from_static_string ("g-exec-error-quark"); 00635 return quark; 00636 } 00637 00638 00647 void 00648 dbus_set_g_error (GError **gerror, 00649 DBusError *derror) 00650 { 00651 g_return_if_fail (derror != NULL); 00652 g_return_if_fail (dbus_error_is_set (derror)); 00653 00654 g_set_error (gerror, DBUS_GERROR, 00655 DBUS_GERROR_FAILED, 00656 _("D-BUS error %s: %s"), 00657 derror->name, derror->message); 00658 } 00659 00665 GType 00666 dbus_connection_get_g_type (void) 00667 { 00668 static GType our_type = 0; 00669 00670 if (our_type == 0) 00671 our_type = g_boxed_type_register_static ("DBusConnection", 00672 (GBoxedCopyFunc) dbus_connection_ref, 00673 (GBoxedFreeFunc) dbus_connection_unref); 00674 00675 return our_type; 00676 } 00677 00683 GType 00684 dbus_message_get_g_type (void) 00685 { 00686 static GType our_type = 0; 00687 00688 if (our_type == 0) 00689 our_type = g_boxed_type_register_static ("DBusMessage", 00690 (GBoxedCopyFunc) dbus_message_ref, 00691 (GBoxedFreeFunc) dbus_message_unref); 00692 00693 return our_type; 00694 } 00695 00696 static DBusGConnection* 00697 dbus_g_connection_ref (DBusGConnection *gconnection) 00698 { 00699 DBusConnection *c; 00700 00701 c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection); 00702 dbus_connection_ref (c); 00703 return gconnection; 00704 } 00705 00706 static void 00707 dbus_g_connection_unref (DBusGConnection *gconnection) 00708 { 00709 DBusConnection *c; 00710 00711 c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection); 00712 dbus_connection_unref (c); 00713 } 00714 00715 00716 static DBusGMessage* 00717 dbus_g_message_ref (DBusGMessage *gmessage) 00718 { 00719 DBusMessage *c; 00720 00721 c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage); 00722 dbus_message_ref (c); 00723 return gmessage; 00724 } 00725 00726 static void 00727 dbus_g_message_unref (DBusGMessage *gmessage) 00728 { 00729 DBusMessage *c; 00730 00731 c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage); 00732 dbus_message_unref (c); 00733 } 00734 00740 GType 00741 dbus_g_connection_get_g_type (void) 00742 { 00743 static GType our_type = 0; 00744 00745 if (our_type == 0) 00746 our_type = g_boxed_type_register_static ("DBusGConnection", 00747 (GBoxedCopyFunc) dbus_g_connection_ref, 00748 (GBoxedFreeFunc) dbus_g_connection_unref); 00749 00750 return our_type; 00751 } 00752 00758 GType 00759 dbus_g_message_get_g_type (void) 00760 { 00761 static GType our_type = 0; 00762 00763 if (our_type == 0) 00764 our_type = g_boxed_type_register_static ("DBusGMessage", 00765 (GBoxedCopyFunc) dbus_g_message_ref, 00766 (GBoxedFreeFunc) dbus_g_message_unref); 00767 00768 return our_type; 00769 } 00770 00777 DBusConnection* 00778 dbus_g_connection_get_connection (DBusGConnection *gconnection) 00779 { 00780 return DBUS_CONNECTION_FROM_G_CONNECTION (gconnection); 00781 } 00782 00789 DBusMessage* 00790 dbus_g_message_get_message (DBusGMessage *gmessage) 00791 { 00792 return DBUS_MESSAGE_FROM_G_MESSAGE (gmessage); 00793 } 00794 /* end of public API */ 00796 00797 #ifdef DBUS_BUILD_TESTS 00798 00804 gboolean 00805 _dbus_gmain_test (const char *test_data_dir) 00806 { 00807 00808 return TRUE; 00809 } 00810 00811 #endif /* DBUS_BUILD_TESTS */

Generated on Mon Jun 27 07:48:21 2005 for D-BUS by doxygen 1.3.7