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);
232 dbus_connection_unref (connection);
237 /* Attach the connection setup to the given watch, removing any
238 * previously-attached connection setup.
241 connection_setup_add_watch (ConnectionSetup *cs,
245 GIOCondition condition;
249 if (!dbus_watch_get_enabled (watch))
252 flags = dbus_watch_get_flags (watch);
254 condition = G_IO_ERR | G_IO_HUP;
255 if (flags & DBUS_WATCH_READABLE)
256 condition |= G_IO_IN;
257 if (flags & DBUS_WATCH_WRITABLE)
258 condition |= G_IO_OUT;
260 handler = g_new0 (IOHandler, 1);
262 handler->watch = watch;
264 channel = g_io_channel_unix_new (dbus_watch_get_unix_fd (watch));
266 handler->source = g_io_create_watch (channel, condition);
267 g_source_set_callback (handler->source, (GSourceFunc) io_handler_dispatch, handler,
268 io_handler_source_finalized);
269 g_source_attach (handler->source, cs->context);
271 cs->ios = g_slist_prepend (cs->ios, handler);
273 dbus_watch_set_data (watch, handler, io_handler_watch_freed);
274 g_io_channel_unref (channel);
278 connection_setup_remove_watch (ConnectionSetup *cs,
283 handler = dbus_watch_get_data (watch);
285 if (handler == NULL || handler->cs != cs)
288 io_handler_destroy_source (handler);
292 timeout_handler_source_finalized (gpointer data)
294 TimeoutHandler *handler;
298 if (handler->timeout)
299 dbus_timeout_set_data (handler->timeout, NULL, NULL);
305 timeout_handler_destroy_source (void *data)
307 TimeoutHandler *handler;
313 GSource *source = handler->source;
314 handler->source = NULL;
315 handler->cs->timeouts = g_slist_remove (handler->cs->timeouts, handler);
316 g_source_destroy (source);
317 g_source_unref (source);
322 timeout_handler_timeout_freed (void *data)
324 TimeoutHandler *handler;
328 handler->timeout = NULL;
330 timeout_handler_destroy_source (handler);
334 timeout_handler_dispatch (gpointer data)
336 TimeoutHandler *handler;
340 dbus_timeout_handle (handler->timeout);
346 connection_setup_add_timeout (ConnectionSetup *cs,
347 DBusTimeout *timeout)
349 TimeoutHandler *handler;
351 if (!dbus_timeout_get_enabled (timeout))
354 handler = g_new0 (TimeoutHandler, 1);
356 handler->timeout = timeout;
358 handler->source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
359 g_source_set_callback (handler->source, timeout_handler_dispatch, handler,
360 timeout_handler_source_finalized);
361 g_source_attach (handler->source, handler->cs->context);
363 cs->timeouts = g_slist_prepend (cs->timeouts, handler);
365 dbus_timeout_set_data (timeout, handler, timeout_handler_timeout_freed);
369 connection_setup_remove_timeout (ConnectionSetup *cs,
370 DBusTimeout *timeout)
372 TimeoutHandler *handler;
374 handler = dbus_timeout_get_data (timeout);
379 timeout_handler_destroy_source (handler);
383 connection_setup_free (ConnectionSetup *cs)
386 io_handler_destroy_source (cs->ios->data);
389 timeout_handler_destroy_source (cs->timeouts->data);
391 if (cs->message_queue_source)
395 source = cs->message_queue_source;
396 cs->message_queue_source = NULL;
398 g_source_destroy (source);
399 g_source_unref (source);
402 g_main_context_unref (cs->context);
407 add_watch (DBusWatch *watch,
414 connection_setup_add_watch (cs, watch);
420 remove_watch (DBusWatch *watch,
427 connection_setup_remove_watch (cs, watch);
431 watch_toggled (DBusWatch *watch,
434 /* Because we just exit on OOM, enable/disable is
435 * no different from add/remove
437 if (dbus_watch_get_enabled (watch))
438 add_watch (watch, data);
440 remove_watch (watch, data);
444 add_timeout (DBusTimeout *timeout,
451 if (!dbus_timeout_get_enabled (timeout))
454 connection_setup_add_timeout (cs, timeout);
460 remove_timeout (DBusTimeout *timeout,
467 connection_setup_remove_timeout (cs, timeout);
471 timeout_toggled (DBusTimeout *timeout,
474 /* Because we just exit on OOM, enable/disable is
475 * no different from add/remove
477 if (dbus_timeout_get_enabled (timeout))
478 add_timeout (timeout, data);
480 remove_timeout (timeout, data);
484 wakeup_main (void *data)
486 ConnectionSetup *cs = data;
488 g_main_context_wakeup (cs->context);
492 /* Move to a new context */
493 static ConnectionSetup*
494 connection_setup_new_from_old (GMainContext *context,
495 ConnectionSetup *old)
499 g_assert (old->context != context);
501 cs = connection_setup_new (context, old->connection);
503 while (old->ios != NULL)
505 IOHandler *handler = old->ios->data;
507 connection_setup_add_watch (cs, handler->watch);
508 /* The old handler will be removed from old->ios as a side-effect */
511 while (old->timeouts != NULL)
513 TimeoutHandler *handler = old->timeouts->data;
515 connection_setup_add_timeout (cs, handler->timeout);
521 /** @} */ /* End of GLib bindings internals */
523 /** @addtogroup DBusGLib
528 * atspi_dbus_connection_setup_with_g_main:
529 * @connection: the connection
530 * @context: the #GMainContext or #NULL for default context
532 * Sets the watch and timeout functions of a #DBusConnection
533 * to integrate the connection with the GLib main loop.
534 * Pass in #NULL for the #GMainContext unless you're
535 * doing something specialized.
537 * If called twice for the same context, does nothing the second
538 * time. If called once with context A and once with context B,
539 * context B replaces context A as the context monitoring the
543 atspi_dbus_connection_setup_with_g_main (DBusConnection *connection,
544 GMainContext *context)
546 ConnectionSetup *old_setup;
549 /* FIXME we never free the slot, so its refcount just keeps growing,
550 * which is kind of broken.
552 dbus_connection_allocate_data_slot (&_dbus_gmain_connection_slot);
553 if (_dbus_gmain_connection_slot < 0)
557 context = g_main_context_default ();
561 old_setup = dbus_connection_get_data (connection, _dbus_gmain_connection_slot);
562 if (old_setup != NULL)
564 if (old_setup->context == context)
565 return; /* nothing to do */
567 cs = connection_setup_new_from_old (context, old_setup);
569 /* Nuke the old setup */
570 dbus_connection_set_data (connection, _dbus_gmain_connection_slot, NULL, NULL);
575 cs = connection_setup_new (context, connection);
577 if (!dbus_connection_set_data (connection, _dbus_gmain_connection_slot, cs,
578 (DBusFreeFunction)connection_setup_free))
581 if (!dbus_connection_set_watch_functions (connection,
588 if (!dbus_connection_set_timeout_functions (connection,
595 dbus_connection_set_wakeup_main_function (connection,
602 g_error ("Not enough memory to set up DBusConnection for use with GLib");
606 * atspi_dbus_server_setup_with_g_main:
607 * @server: the server
608 * @context: the #GMainContext or #NULL for default
610 * Sets the watch and timeout functions of a #DBusServer
611 * to integrate the server with the GLib main loop.
612 * In most cases the context argument should be #NULL.
614 * If called twice for the same context, does nothing the second
615 * time. If called once with context A and once with context B,
616 * context B replaces context A as the context monitoring the
620 atspi_dbus_server_setup_with_g_main (DBusServer *server,
621 GMainContext *context)
623 ConnectionSetup *old_setup;
626 /* FIXME we never free the slot, so its refcount just keeps growing,
627 * which is kind of broken.
629 dbus_server_allocate_data_slot (&server_slot);
634 context = g_main_context_default ();
638 old_setup = dbus_server_get_data (server, server_slot);
639 if (old_setup != NULL)
641 if (old_setup->context == context)
642 return; /* nothing to do */
644 cs = connection_setup_new_from_old (context, old_setup);
646 /* Nuke the old setup */
647 if (!dbus_server_set_data (server, server_slot, NULL, NULL))
653 cs = connection_setup_new (context, NULL);
655 if (!dbus_server_set_data (server, server_slot, cs,
656 (DBusFreeFunction)connection_setup_free))
659 if (!dbus_server_set_watch_functions (server,
666 if (!dbus_server_set_timeout_functions (server,
676 g_error ("Not enough memory to set up DBusServer for use with GLib");