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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * This file is based on dbus-gmain.c from dbus-glib with functions renamed
24 * and unnecessary code removed.
28 #include <dbus/dbus.h>
33 #define _(x) dgettext (GETTEXT_PACKAGE, x)
37 * @defgroup DBusGLibInternals GLib bindings implementation details
38 * @ingroup DBusInternals
39 * @brief Implementation details of GLib bindings
46 * A GSource subclass for dispatching DBusConnection messages.
47 * We need this on top of the IO handlers, because sometimes
48 * there are messages to dispatch queued up but no IO pending.
52 GSource source; /**< the parent GSource */
53 DBusConnection *connection; /**< the connection to dispatch */
56 static gboolean message_queue_prepare (GSource *source,
58 static gboolean message_queue_check (GSource *source);
59 static gboolean message_queue_dispatch (GSource *source,
63 static const GSourceFuncs message_queue_funcs = {
64 message_queue_prepare,
66 message_queue_dispatch,
71 message_queue_prepare (GSource *source,
74 DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
78 return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);
82 message_queue_check (GSource *source)
88 message_queue_dispatch (GSource *source,
92 DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
94 dbus_connection_ref (connection);
96 /* Only dispatch once - we don't want to starve other GSource */
97 dbus_connection_dispatch (connection);
99 dbus_connection_unref (connection);
106 GMainContext *context; /**< the main context */
107 GSList *ios; /**< all IOHandler */
108 GSList *timeouts; /**< all TimeoutHandler */
109 DBusConnection *connection; /**< NULL if this is really for a server not a connection */
110 GSource *message_queue_source; /**< DBusGMessageQueue */
125 DBusTimeout *timeout;
128 dbus_int32_t _dbus_gmain_connection_slot = -1;
129 static dbus_int32_t server_slot = -1;
131 static ConnectionSetup*
132 connection_setup_new (GMainContext *context,
133 DBusConnection *connection)
137 cs = g_new0 (ConnectionSetup, 1);
139 g_assert (context != NULL);
141 cs->context = context;
142 g_main_context_ref (cs->context);
146 cs->connection = connection;
148 cs->message_queue_source = g_source_new ((GSourceFuncs *) &message_queue_funcs,
149 sizeof (DBusGMessageQueue));
150 ((DBusGMessageQueue*)cs->message_queue_source)->connection = connection;
151 g_source_attach (cs->message_queue_source, cs->context);
158 io_handler_source_finalized (gpointer data)
165 dbus_watch_set_data (handler->watch, NULL, NULL);
171 io_handler_destroy_source (void *data)
179 GSource *source = handler->source;
180 handler->source = NULL;
181 handler->cs->ios = g_slist_remove (handler->cs->ios, handler);
182 g_source_destroy (source);
183 g_source_unref (source);
188 io_handler_watch_freed (void *data)
194 handler->watch = NULL;
196 io_handler_destroy_source (handler);
200 io_handler_dispatch (GIOChannel *source,
201 GIOCondition condition,
205 guint dbus_condition = 0;
206 DBusConnection *connection;
210 connection = handler->cs->connection;
213 dbus_connection_ref (connection);
215 if (condition & G_IO_IN)
216 dbus_condition |= DBUS_WATCH_READABLE;
217 if (condition & G_IO_OUT)
218 dbus_condition |= DBUS_WATCH_WRITABLE;
219 if (condition & G_IO_ERR)
220 dbus_condition |= DBUS_WATCH_ERROR;
221 if (condition & G_IO_HUP)
222 dbus_condition |= DBUS_WATCH_HANGUP;
224 /* Note that we don't touch the handler after this, because
225 * dbus may have disabled the watch and thus killed the
228 dbus_watch_handle (handler->watch, dbus_condition);
233 dbus_connection_unref (connection);
238 /* Attach the connection setup to the given watch, removing any
239 * previously-attached connection setup.
242 connection_setup_add_watch (ConnectionSetup *cs,
246 GIOCondition condition;
250 if (!dbus_watch_get_enabled (watch))
253 flags = dbus_watch_get_flags (watch);
255 condition = G_IO_ERR | G_IO_HUP;
256 if (flags & DBUS_WATCH_READABLE)
257 condition |= G_IO_IN;
258 if (flags & DBUS_WATCH_WRITABLE)
259 condition |= G_IO_OUT;
261 handler = g_new0 (IOHandler, 1);
263 handler->watch = watch;
265 channel = g_io_channel_unix_new (dbus_watch_get_unix_fd (watch));
267 handler->source = g_io_create_watch (channel, condition);
268 g_source_set_callback (handler->source, (GSourceFunc) io_handler_dispatch, handler,
269 io_handler_source_finalized);
270 g_source_attach (handler->source, cs->context);
272 cs->ios = g_slist_prepend (cs->ios, handler);
274 dbus_watch_set_data (watch, handler, io_handler_watch_freed);
275 g_io_channel_unref (channel);
279 connection_setup_remove_watch (ConnectionSetup *cs,
284 handler = dbus_watch_get_data (watch);
286 if (handler == NULL || handler->cs != cs)
289 io_handler_destroy_source (handler);
293 timeout_handler_source_finalized (gpointer data)
295 TimeoutHandler *handler;
299 if (handler->timeout)
300 dbus_timeout_set_data (handler->timeout, NULL, NULL);
306 timeout_handler_destroy_source (void *data)
308 TimeoutHandler *handler;
314 GSource *source = handler->source;
315 handler->source = NULL;
316 handler->cs->timeouts = g_slist_remove (handler->cs->timeouts, handler);
317 g_source_destroy (source);
318 g_source_unref (source);
323 timeout_handler_timeout_freed (void *data)
325 TimeoutHandler *handler;
329 handler->timeout = NULL;
331 timeout_handler_destroy_source (handler);
335 timeout_handler_dispatch (gpointer data)
337 TimeoutHandler *handler;
341 dbus_timeout_handle (handler->timeout);
347 connection_setup_add_timeout (ConnectionSetup *cs,
348 DBusTimeout *timeout)
350 TimeoutHandler *handler;
352 if (!dbus_timeout_get_enabled (timeout))
355 handler = g_new0 (TimeoutHandler, 1);
357 handler->timeout = timeout;
359 handler->source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
360 g_source_set_callback (handler->source, timeout_handler_dispatch, handler,
361 timeout_handler_source_finalized);
362 g_source_attach (handler->source, handler->cs->context);
364 cs->timeouts = g_slist_prepend (cs->timeouts, handler);
366 dbus_timeout_set_data (timeout, handler, timeout_handler_timeout_freed);
370 connection_setup_remove_timeout (ConnectionSetup *cs,
371 DBusTimeout *timeout)
373 TimeoutHandler *handler;
375 handler = dbus_timeout_get_data (timeout);
380 timeout_handler_destroy_source (handler);
384 connection_setup_free (ConnectionSetup *cs)
387 io_handler_destroy_source (cs->ios->data);
390 timeout_handler_destroy_source (cs->timeouts->data);
392 if (cs->message_queue_source)
396 source = cs->message_queue_source;
397 cs->message_queue_source = NULL;
399 g_source_destroy (source);
400 g_source_unref (source);
403 g_main_context_unref (cs->context);
408 add_watch (DBusWatch *watch,
415 connection_setup_add_watch (cs, watch);
421 remove_watch (DBusWatch *watch,
428 connection_setup_remove_watch (cs, watch);
432 watch_toggled (DBusWatch *watch,
435 /* Because we just exit on OOM, enable/disable is
436 * no different from add/remove
438 if (dbus_watch_get_enabled (watch))
439 add_watch (watch, data);
441 remove_watch (watch, data);
445 add_timeout (DBusTimeout *timeout,
452 if (!dbus_timeout_get_enabled (timeout))
455 connection_setup_add_timeout (cs, timeout);
461 remove_timeout (DBusTimeout *timeout,
468 connection_setup_remove_timeout (cs, timeout);
472 timeout_toggled (DBusTimeout *timeout,
475 /* Because we just exit on OOM, enable/disable is
476 * no different from add/remove
478 if (dbus_timeout_get_enabled (timeout))
479 add_timeout (timeout, data);
481 remove_timeout (timeout, data);
485 wakeup_main (void *data)
487 ConnectionSetup *cs = data;
489 g_main_context_wakeup (cs->context);
493 /* Move to a new context */
494 static ConnectionSetup*
495 connection_setup_new_from_old (GMainContext *context,
496 ConnectionSetup *old)
500 g_assert (old->context != context);
502 cs = connection_setup_new (context, old->connection);
504 while (old->ios != NULL)
506 IOHandler *handler = old->ios->data;
508 connection_setup_add_watch (cs, handler->watch);
509 /* The old handler will be removed from old->ios as a side-effect */
512 while (old->timeouts != NULL)
514 TimeoutHandler *handler = old->timeouts->data;
516 connection_setup_add_timeout (cs, handler->timeout);
522 /** @} */ /* End of GLib bindings internals */
524 /** @addtogroup DBusGLib
529 * atspi_dbus_connection_setup_with_g_main:
530 * @connection: the connection
531 * @context: the #GMainContext or #NULL for default context
533 * Sets the watch and timeout functions of a #DBusConnection
534 * to integrate the connection with the GLib main loop.
535 * Pass in #NULL for the #GMainContext unless you're
536 * doing something specialized.
538 * If called twice for the same context, does nothing the second
539 * time. If called once with context A and once with context B,
540 * context B replaces context A as the context monitoring the
544 atspi_dbus_connection_setup_with_g_main (DBusConnection *connection,
545 GMainContext *context)
547 ConnectionSetup *old_setup;
550 /* FIXME we never free the slot, so its refcount just keeps growing,
551 * which is kind of broken.
553 dbus_connection_allocate_data_slot (&_dbus_gmain_connection_slot);
554 if (_dbus_gmain_connection_slot < 0)
558 context = g_main_context_default ();
562 old_setup = dbus_connection_get_data (connection, _dbus_gmain_connection_slot);
563 if (old_setup != NULL)
565 if (old_setup->context == context)
566 return; /* nothing to do */
568 cs = connection_setup_new_from_old (context, old_setup);
570 /* Nuke the old setup */
571 dbus_connection_set_data (connection, _dbus_gmain_connection_slot, NULL, NULL);
577 cs = connection_setup_new (context, connection);
579 if (!dbus_connection_set_data (connection, _dbus_gmain_connection_slot, cs,
580 (DBusFreeFunction)connection_setup_free))
583 if (!dbus_connection_set_watch_functions (connection,
590 if (!dbus_connection_set_timeout_functions (connection,
597 dbus_connection_set_wakeup_main_function (connection,
604 g_error ("Not enough memory to set up DBusConnection for use with GLib");
608 * atspi_dbus_server_setup_with_g_main:
609 * @server: the server
610 * @context: the #GMainContext or #NULL for default
612 * Sets the watch and timeout functions of a #DBusServer
613 * to integrate the server with the GLib main loop.
614 * In most cases the context argument should be #NULL.
616 * If called twice for the same context, does nothing the second
617 * time. If called once with context A and once with context B,
618 * context B replaces context A as the context monitoring the
622 atspi_dbus_server_setup_with_g_main (DBusServer *server,
623 GMainContext *context)
625 ConnectionSetup *old_setup;
628 /* FIXME we never free the slot, so its refcount just keeps growing,
629 * which is kind of broken.
631 dbus_server_allocate_data_slot (&server_slot);
636 context = g_main_context_default ();
640 old_setup = dbus_server_get_data (server, server_slot);
641 if (old_setup != NULL)
643 if (old_setup->context == context)
644 return; /* nothing to do */
646 cs = connection_setup_new_from_old (context, old_setup);
648 /* Nuke the old setup */
649 if (!dbus_server_set_data (server, server_slot, NULL, NULL))
656 cs = connection_setup_new (context, NULL);
658 if (!dbus_server_set_data (server, server_slot, cs,
659 (DBusFreeFunction)connection_setup_free))
662 if (!dbus_server_set_watch_functions (server,
669 if (!dbus_server_set_timeout_functions (server,
679 g_error ("Not enough memory to set up DBusServer for use with GLib");