1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gmain.c GLib main loop integration
4 * Copyright (C) 2002, 2003 CodeFactory AB
5 * Copyright (C) 2005 Red Hat, Inc.
7 * Licensed under the Academic Free License version 2.1
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <dbus/dbus-glib.h>
27 #include <dbus/dbus-glib-lowlevel.h>
28 #include "dbus-gtest.h"
29 #include "dbus-gutils.h"
32 #define _(x) dgettext (GETTEXT_PACKAGE, x)
36 * @defgroup DBusGLib GLib bindings
37 * @brief API for using D-BUS with GLib
39 * libdbus proper is a low-level API, these GLib bindings wrap libdbus
40 * with a much higher-level approach. The higher level approach is
41 * possible because GLib defines a main loop, an object/type system,
42 * and an out-of-memory handling policy (it exits the program).
43 * See http://www.gtk.org for GLib information.
45 * To manipulate remote objects, use #DBusGProxy.
49 * @defgroup DBusGLibInternals GLib bindings implementation details
50 * @ingroup DBusInternals
51 * @brief Implementation details of GLib bindings
56 /** @typedef DBusGSource
57 * A GSource representing a #DBusConnection or #DBusServer
59 typedef struct DBusGSource DBusGSource;
62 * A GSource subclass for a DBusConnection.
66 GSource source; /**< the parent GSource */
68 GList *watch_fds; /**< descriptors we're watching */
70 GMainContext *context; /**< the GMainContext to use, NULL for default */
72 void *connection_or_server; /**< DBusConnection or DBusServer */
76 * Auxillary struct for pairing up a #DBusWatch and associated
81 int refcount; /**< reference count */
83 GPollFD poll_fd; /**< the #GPollFD to use with g_source_add_poll() */
84 DBusWatch *watch; /**< the corresponding DBusWatch*/
86 unsigned int removed : 1; /**< true if this #WatchFD has been removed */
94 watch_fd = g_new0 (WatchFD, 1);
95 watch_fd->refcount = 1;
101 watch_fd_ref (WatchFD *watch_fd)
103 g_assert (watch_fd->refcount > 0);
105 watch_fd->refcount += 1;
111 watch_fd_unref (WatchFD *watch_fd)
113 g_assert (watch_fd->refcount > 0);
115 watch_fd->refcount -= 1;
117 if (watch_fd->refcount == 0)
119 g_assert (watch_fd->removed);
125 static dbus_int32_t connection_slot = -1;
126 static dbus_int32_t server_slot = -1;
128 static gboolean gsource_connection_prepare (GSource *source,
130 static gboolean gsource_connection_check (GSource *source);
131 static gboolean gsource_connection_dispatch (GSource *source,
132 GSourceFunc callback,
134 static void gsource_connection_finalize (GSource *source);
135 static gboolean gsource_server_prepare (GSource *source,
137 static gboolean gsource_server_check (GSource *source);
138 static gboolean gsource_server_dispatch (GSource *source,
139 GSourceFunc callback,
141 static void gsource_server_finalize (GSource *source);
143 static GSourceFuncs dbus_connection_funcs = {
144 gsource_connection_prepare,
145 gsource_connection_check,
146 gsource_connection_dispatch,
147 gsource_connection_finalize
150 static GSourceFuncs dbus_server_funcs = {
151 gsource_server_prepare,
152 gsource_server_check,
153 gsource_server_dispatch,
154 gsource_server_finalize
158 gsource_connection_prepare (GSource *source,
161 DBusConnection *connection = ((DBusGSource *)source)->connection_or_server;
165 return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);
169 gsource_server_prepare (GSource *source,
178 dbus_gsource_check (GSource *source)
180 DBusGSource *dbus_source = (DBusGSource *)source;
183 list = dbus_source->watch_fds;
187 WatchFD *watch_fd = list->data;
189 if (watch_fd->poll_fd.revents != 0)
199 gsource_connection_check (GSource *source)
201 return dbus_gsource_check (source);
205 gsource_server_check (GSource *source)
207 return dbus_gsource_check (source);
211 dbus_gsource_dispatch (GSource *source,
212 GSourceFunc callback,
214 dbus_bool_t is_server)
216 DBusGSource *dbus_source = (DBusGSource *)source;
219 /* Make a copy of the list and ref all WatchFDs */
220 copy = g_list_copy (dbus_source->watch_fds);
221 g_list_foreach (copy, (GFunc)watch_fd_ref, NULL);
226 WatchFD *watch_fd = list->data;
228 if (!watch_fd->removed && watch_fd->poll_fd.revents != 0)
232 if (watch_fd->poll_fd.revents & G_IO_IN)
233 condition |= DBUS_WATCH_READABLE;
234 if (watch_fd->poll_fd.revents & G_IO_OUT)
235 condition |= DBUS_WATCH_WRITABLE;
236 if (watch_fd->poll_fd.revents & G_IO_ERR)
237 condition |= DBUS_WATCH_ERROR;
238 if (watch_fd->poll_fd.revents & G_IO_HUP)
239 condition |= DBUS_WATCH_HANGUP;
241 dbus_watch_handle (watch_fd->watch, condition);
247 g_list_foreach (copy, (GFunc)watch_fd_unref, NULL);
254 gsource_connection_dispatch (GSource *source,
255 GSourceFunc callback,
258 DBusGSource *dbus_source = (DBusGSource *)source;
259 DBusConnection *connection = dbus_source->connection_or_server;
261 dbus_connection_ref (connection);
263 dbus_gsource_dispatch (source, callback, user_data,
266 /* Dispatch messages */
267 while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS)
270 dbus_connection_unref (connection);
276 gsource_server_dispatch (GSource *source,
277 GSourceFunc callback,
280 DBusGSource *dbus_source = (DBusGSource *)source;
281 DBusServer *server = dbus_source->connection_or_server;
283 dbus_server_ref (server);
285 dbus_gsource_dispatch (source, callback, user_data,
288 dbus_server_unref (server);
294 add_watch (DBusWatch *watch,
298 DBusGSource *dbus_source;
301 if (!dbus_watch_get_enabled (watch))
304 g_assert (dbus_watch_get_data (watch) == NULL);
308 watch_fd = watch_fd_new ();
309 watch_fd->poll_fd.fd = dbus_watch_get_fd (watch);
310 watch_fd->poll_fd.events = 0;
311 flags = dbus_watch_get_flags (watch);
312 dbus_watch_set_data (watch, watch_fd, (DBusFreeFunction)watch_fd_unref);
314 if (flags & DBUS_WATCH_READABLE)
315 watch_fd->poll_fd.events |= G_IO_IN;
316 if (flags & DBUS_WATCH_WRITABLE)
317 watch_fd->poll_fd.events |= G_IO_OUT;
318 watch_fd->poll_fd.events |= G_IO_ERR | G_IO_HUP;
320 watch_fd->watch = watch;
322 g_source_add_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
324 dbus_source->watch_fds = g_list_prepend (dbus_source->watch_fds, watch_fd);
325 g_assert (!watch_fd->removed);
331 source_remove_watch_fd (DBusGSource *dbus_source,
334 g_assert (g_list_find (dbus_source->watch_fds, watch_fd) != NULL);
335 g_assert (!watch_fd->removed);
337 watch_fd_ref (watch_fd);
339 watch_fd->removed = TRUE;
340 dbus_source->watch_fds = g_list_remove (dbus_source->watch_fds, watch_fd);
342 g_source_remove_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
344 g_assert (watch_fd->watch != NULL);
345 dbus_watch_set_data (watch_fd->watch, NULL, NULL); /* needed due to watch_toggled
346 * breaking add/remove symmetry
349 watch_fd->watch = NULL;
351 watch_fd_unref (watch_fd);
355 remove_watch (DBusWatch *watch,
358 DBusGSource *dbus_source = data;
361 watch_fd = dbus_watch_get_data (watch);
362 if (watch_fd == NULL)
363 return; /* probably a not-enabled watch that was added,
364 * or the source has been finalized
367 g_assert (watch_fd->watch == watch);
369 source_remove_watch_fd (dbus_source, watch_fd);
373 watch_toggled (DBusWatch *watch,
376 /* Because we just exit on OOM, enable/disable is
377 * no different from add/remove
379 if (dbus_watch_get_enabled (watch))
380 add_watch (watch, data);
382 remove_watch (watch, data);
386 timeout_handler (gpointer data)
388 DBusTimeout *timeout = data;
390 dbus_timeout_handle (timeout);
396 add_timeout (DBusTimeout *timeout,
400 GMainContext *context;
404 if (!dbus_timeout_get_enabled (timeout))
407 source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
408 g_source_set_callback (source, timeout_handler, timeout, NULL);
409 g_source_attach (source, context);
411 dbus_timeout_set_data (timeout, GUINT_TO_POINTER (g_source_get_id (source)),
418 remove_timeout (DBusTimeout *timeout,
423 timeout_tag = GPOINTER_TO_UINT (dbus_timeout_get_data (timeout));
425 if (timeout_tag != 0) /* if 0, probably timeout was disabled */
426 g_source_remove (timeout_tag);
430 timeout_toggled (DBusTimeout *timeout,
433 /* Because we just exit on OOM, enable/disable is
434 * no different from add/remove
436 if (dbus_timeout_get_enabled (timeout))
437 add_timeout (timeout, data);
439 remove_timeout (timeout, data);
444 free_source (GSource *source)
446 g_source_destroy (source);
450 wakeup_main (void *data)
452 DBusGSource *dbus_source = data;
454 g_main_context_wakeup (dbus_source->context);
458 remove_all_watch_fd (DBusGSource *dbus_source)
460 while (dbus_source->watch_fds)
462 WatchFD *watch_fd = dbus_source->watch_fds->data;
464 g_assert (!watch_fd->removed); /* should not be in the list if removed */
465 source_remove_watch_fd (dbus_source, watch_fd);
470 gsource_connection_finalize (GSource *source)
472 DBusGSource *dbus_source = (DBusGSource *)source;
474 remove_all_watch_fd (dbus_source);
478 gsource_server_finalize (GSource *source)
480 DBusGSource *dbus_source = (DBusGSource *)source;
482 remove_all_watch_fd (dbus_source);
485 /** @} */ /* End of GLib bindings internals */
487 /** @addtogroup DBusGLib
492 create_source (void *connection_or_server,
494 GMainContext *context)
497 DBusGSource *dbus_source;
499 source = g_source_new (funcs, sizeof (DBusGSource));
501 dbus_source = (DBusGSource *)source;
502 dbus_source->connection_or_server = connection_or_server;
503 dbus_source->context = context;
509 * Sets the watch and timeout functions of a #DBusConnection
510 * to integrate the connection with the GLib main loop.
511 * Pass in #NULL for the #GMainContext unless you're
512 * doing something specialized.
514 * If called twice for the same context, does nothing the second
515 * time. If called once with context A and once with context B,
516 * context B replaces context A as the context monitoring the
519 * @param connection the connection
520 * @param context the #GMainContext or #NULL for default context
523 dbus_connection_setup_with_g_main (DBusConnection *connection,
524 GMainContext *context)
528 /* FIXME we never free the slot, so its refcount just keeps growing,
529 * which is kind of broken.
531 dbus_connection_allocate_data_slot (&connection_slot);
532 if (connection_slot < 0)
535 /* So we can test for equality below */
537 context = g_main_context_default ();
539 source = dbus_connection_get_data (connection, connection_slot);
542 if (source->context == context)
543 return; /* nothing to do */
545 /* Remove the previous source and move to a new context */
546 dbus_connection_set_data (connection, connection_slot, NULL, NULL);
550 source = create_source (connection, &dbus_connection_funcs, context);
552 if (!dbus_connection_set_watch_functions (connection,
559 if (!dbus_connection_set_timeout_functions (connection,
566 dbus_connection_set_wakeup_main_function (connection,
570 g_source_attach (source, context);
572 if (!dbus_connection_set_data (connection, connection_slot, source,
573 (DBusFreeFunction)free_source))
579 g_error ("Not enough memory to set up DBusConnection for use with GLib");
583 * Sets the watch and timeout functions of a #DBusServer
584 * to integrate the server with the GLib main loop.
585 * In most cases the context argument should be #NULL.
587 * If called twice for the same context, does nothing the second
588 * time. If called once with context A and once with context B,
589 * context B replaces context A as the context monitoring the
592 * @param server the server
593 * @param context the #GMainContext or #NULL for default
596 dbus_server_setup_with_g_main (DBusServer *server,
597 GMainContext *context)
601 dbus_server_allocate_data_slot (&server_slot);
605 /* So we can test for equality below */
607 context = g_main_context_default ();
609 source = dbus_server_get_data (server, server_slot);
612 if (source->context == context)
613 return; /* nothing to do */
615 /* Remove the previous source and move to a new context */
616 dbus_server_set_data (server, server_slot, NULL, NULL);
620 source = create_source (server, &dbus_server_funcs, context);
622 dbus_server_set_watch_functions (server,
628 dbus_server_set_timeout_functions (server,
634 g_source_attach (source, context);
636 if (!dbus_server_set_data (server, server_slot, source,
637 (DBusFreeFunction)free_source))
643 g_error ("Not enough memory to set up DBusServer for use with GLib");
647 * Returns a connection to the given bus. The connection is a global variable
648 * shared with other callers of this function.
650 * (Internally, calls dbus_bus_get() then calls
651 * dbus_connection_setup_with_g_main() on the result.)
653 * @param type bus type
654 * @param error address where an error can be returned.
655 * @returns a DBusConnection
658 dbus_g_bus_get (DBusBusType type,
661 DBusConnection *connection;
664 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
666 dbus_error_init (&derror);
668 connection = dbus_bus_get (type, &derror);
669 if (connection == NULL)
671 dbus_set_g_error (error, &derror);
672 dbus_error_free (&derror);
676 /* does nothing if it's already been done */
677 dbus_connection_setup_with_g_main (connection, NULL);
679 return DBUS_G_CONNECTION_FROM_CONNECTION (connection);
683 * The implementation of DBUS_GERROR error domain. See documentation
684 * for GError in GLib reference manual.
686 * @returns the error domain quark for use with GError
689 dbus_g_error_quark (void)
691 static GQuark quark = 0;
693 quark = g_quark_from_static_string ("g-exec-error-quark");
699 * Set a GError return location from a DBusError.
701 * @todo expand the DBUS_GERROR enum and take advantage of it here
703 * @param gerror location to store a GError, or #NULL
704 * @param derror the DBusError
707 dbus_set_g_error (GError **gerror,
710 g_return_if_fail (derror != NULL);
711 g_return_if_fail (dbus_error_is_set (derror));
713 g_set_error (gerror, DBUS_GERROR,
715 _("D-BUS error %s: %s"),
716 derror->name, derror->message);
720 * Get the GLib type ID for a DBusConnection boxed type.
725 dbus_connection_get_g_type (void)
727 static GType our_type = 0;
730 our_type = g_boxed_type_register_static ("DBusConnection",
731 (GBoxedCopyFunc) dbus_connection_ref,
732 (GBoxedFreeFunc) dbus_connection_unref);
738 * Get the GLib type ID for a DBusMessage boxed type.
743 dbus_message_get_g_type (void)
745 static GType our_type = 0;
748 our_type = g_boxed_type_register_static ("DBusMessage",
749 (GBoxedCopyFunc) dbus_message_ref,
750 (GBoxedFreeFunc) dbus_message_unref);
755 static DBusGConnection*
756 dbus_g_connection_ref (DBusGConnection *gconnection)
760 c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
761 dbus_connection_ref (c);
766 dbus_g_connection_unref (DBusGConnection *gconnection)
770 c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
771 dbus_connection_unref (c);
776 dbus_g_message_ref (DBusGMessage *gmessage)
780 c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
781 dbus_message_ref (c);
786 dbus_g_message_unref (DBusGMessage *gmessage)
790 c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
791 dbus_message_unref (c);
795 * Get the GLib type ID for a DBusGConnection boxed type.
800 dbus_g_connection_get_g_type (void)
802 static GType our_type = 0;
805 our_type = g_boxed_type_register_static ("DBusGConnection",
806 (GBoxedCopyFunc) dbus_g_connection_ref,
807 (GBoxedFreeFunc) dbus_g_connection_unref);
813 * Get the GLib type ID for a DBusGMessage boxed type.
818 dbus_g_message_get_g_type (void)
820 static GType our_type = 0;
823 our_type = g_boxed_type_register_static ("DBusGMessage",
824 (GBoxedCopyFunc) dbus_g_message_ref,
825 (GBoxedFreeFunc) dbus_g_message_unref);
831 * Get the DBusConnection corresponding to this DBusGConnection.
832 * The return value does not have its refcount incremented.
834 * @returns DBusConnection
837 dbus_g_connection_get_connection (DBusGConnection *gconnection)
839 return DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
843 * Get the DBusMessage corresponding to this DBusGMessage.
844 * The return value does not have its refcount incremented.
846 * @returns DBusMessage
849 dbus_g_message_get_message (DBusGMessage *gmessage)
851 return DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
854 /** @} */ /* end of public API */
856 #ifdef DBUS_BUILD_TESTS
859 * @ingroup DBusGLibInternals
860 * Unit test for GLib main loop integration
861 * @returns #TRUE on success.
864 _dbus_gmain_test (const char *test_data_dir)
870 #endif /* DBUS_BUILD_TESTS */