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)
38 * A GSource subclass for dispatching DBusConnection messages.
39 * We need this on top of the IO handlers, because sometimes
40 * there are messages to dispatch queued up but no IO pending.
44 GSource source; /**< the parent GSource */
45 DBusConnection *connection; /**< the connection to dispatch */
48 static gboolean message_queue_prepare (GSource *source,
50 static gboolean message_queue_check (GSource *source);
51 static gboolean message_queue_dispatch (GSource *source,
55 static const GSourceFuncs message_queue_funcs = {
56 message_queue_prepare,
58 message_queue_dispatch,
63 message_queue_prepare (GSource *source,
66 DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
70 return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);
74 message_queue_check (GSource *source)
80 message_queue_dispatch (GSource *source,
84 DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
86 dbus_connection_ref (connection);
88 /* Only dispatch once - we don't want to starve other GSource */
89 dbus_connection_dispatch (connection);
91 dbus_connection_unref (connection);
98 GMainContext *context; /**< the main context */
99 GSList *ios; /**< all IOHandler */
100 GSList *timeouts; /**< all TimeoutHandler */
101 DBusConnection *connection; /**< NULL if this is really for a server not a connection */
102 GSource *message_queue_source; /**< DBusGMessageQueue */
117 DBusTimeout *timeout;
120 dbus_int32_t _dbus_gmain_connection_slot = -1;
121 static dbus_int32_t server_slot = -1;
123 static ConnectionSetup*
124 connection_setup_new (GMainContext *context,
125 DBusConnection *connection)
129 cs = g_new0 (ConnectionSetup, 1);
131 g_assert (context != NULL);
133 cs->context = context;
134 g_main_context_ref (cs->context);
138 cs->connection = connection;
140 cs->message_queue_source = g_source_new ((GSourceFuncs *) &message_queue_funcs,
141 sizeof (DBusGMessageQueue));
142 ((DBusGMessageQueue*)cs->message_queue_source)->connection = connection;
143 g_source_attach (cs->message_queue_source, cs->context);
150 io_handler_source_finalized (gpointer data)
157 dbus_watch_set_data (handler->watch, NULL, NULL);
163 io_handler_destroy_source (void *data)
171 GSource *source = handler->source;
172 handler->source = NULL;
173 handler->cs->ios = g_slist_remove (handler->cs->ios, handler);
174 g_source_destroy (source);
175 g_source_unref (source);
180 io_handler_watch_freed (void *data)
186 handler->watch = NULL;
188 io_handler_destroy_source (handler);
192 io_handler_dispatch (GIOChannel *source,
193 GIOCondition condition,
197 guint dbus_condition = 0;
198 DBusConnection *connection;
202 connection = handler->cs->connection;
205 dbus_connection_ref (connection);
207 if (condition & G_IO_IN)
208 dbus_condition |= DBUS_WATCH_READABLE;
209 if (condition & G_IO_OUT)
210 dbus_condition |= DBUS_WATCH_WRITABLE;
211 if (condition & G_IO_ERR)
212 dbus_condition |= DBUS_WATCH_ERROR;
213 if (condition & G_IO_HUP)
214 dbus_condition |= DBUS_WATCH_HANGUP;
216 /* Note that we don't touch the handler after this, because
217 * dbus may have disabled the watch and thus killed the
220 dbus_watch_handle (handler->watch, dbus_condition);
224 dbus_connection_unref (connection);
229 /* Attach the connection setup to the given watch, removing any
230 * previously-attached connection setup.
233 connection_setup_add_watch (ConnectionSetup *cs,
237 GIOCondition condition;
241 if (!dbus_watch_get_enabled (watch))
244 flags = dbus_watch_get_flags (watch);
246 condition = G_IO_ERR | G_IO_HUP;
247 if (flags & DBUS_WATCH_READABLE)
248 condition |= G_IO_IN;
249 if (flags & DBUS_WATCH_WRITABLE)
250 condition |= G_IO_OUT;
252 handler = g_new0 (IOHandler, 1);
254 handler->watch = watch;
256 channel = g_io_channel_unix_new (dbus_watch_get_unix_fd (watch));
258 handler->source = g_io_create_watch (channel, condition);
259 g_source_set_callback (handler->source, (GSourceFunc) io_handler_dispatch, handler,
260 io_handler_source_finalized);
261 g_source_attach (handler->source, cs->context);
263 cs->ios = g_slist_prepend (cs->ios, handler);
265 dbus_watch_set_data (watch, handler, io_handler_watch_freed);
266 g_io_channel_unref (channel);
270 connection_setup_remove_watch (ConnectionSetup *cs,
275 handler = dbus_watch_get_data (watch);
277 if (handler == NULL || handler->cs != cs)
280 io_handler_destroy_source (handler);
284 timeout_handler_source_finalized (gpointer data)
286 TimeoutHandler *handler;
290 if (handler->timeout)
291 dbus_timeout_set_data (handler->timeout, NULL, NULL);
297 timeout_handler_destroy_source (void *data)
299 TimeoutHandler *handler;
305 GSource *source = handler->source;
306 handler->source = NULL;
307 handler->cs->timeouts = g_slist_remove (handler->cs->timeouts, handler);
308 g_source_destroy (source);
309 g_source_unref (source);
314 timeout_handler_timeout_freed (void *data)
316 TimeoutHandler *handler;
320 handler->timeout = NULL;
322 timeout_handler_destroy_source (handler);
326 timeout_handler_dispatch (gpointer data)
328 TimeoutHandler *handler;
332 dbus_timeout_handle (handler->timeout);
338 connection_setup_add_timeout (ConnectionSetup *cs,
339 DBusTimeout *timeout)
341 TimeoutHandler *handler;
343 if (!dbus_timeout_get_enabled (timeout))
346 handler = g_new0 (TimeoutHandler, 1);
348 handler->timeout = timeout;
350 handler->source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
351 g_source_set_callback (handler->source, timeout_handler_dispatch, handler,
352 timeout_handler_source_finalized);
353 g_source_attach (handler->source, handler->cs->context);
355 cs->timeouts = g_slist_prepend (cs->timeouts, handler);
357 dbus_timeout_set_data (timeout, handler, timeout_handler_timeout_freed);
361 connection_setup_remove_timeout (ConnectionSetup *cs,
362 DBusTimeout *timeout)
364 TimeoutHandler *handler;
366 handler = dbus_timeout_get_data (timeout);
371 timeout_handler_destroy_source (handler);
375 connection_setup_free (ConnectionSetup *cs)
378 io_handler_destroy_source (cs->ios->data);
381 timeout_handler_destroy_source (cs->timeouts->data);
383 if (cs->message_queue_source)
387 source = cs->message_queue_source;
388 cs->message_queue_source = NULL;
390 g_source_destroy (source);
391 g_source_unref (source);
394 g_main_context_unref (cs->context);
399 add_watch (DBusWatch *watch,
406 connection_setup_add_watch (cs, watch);
412 remove_watch (DBusWatch *watch,
419 connection_setup_remove_watch (cs, watch);
423 watch_toggled (DBusWatch *watch,
426 /* Because we just exit on OOM, enable/disable is
427 * no different from add/remove
429 if (dbus_watch_get_enabled (watch))
430 add_watch (watch, data);
432 remove_watch (watch, data);
436 add_timeout (DBusTimeout *timeout,
443 if (!dbus_timeout_get_enabled (timeout))
446 connection_setup_add_timeout (cs, timeout);
452 remove_timeout (DBusTimeout *timeout,
459 connection_setup_remove_timeout (cs, timeout);
463 timeout_toggled (DBusTimeout *timeout,
466 /* Because we just exit on OOM, enable/disable is
467 * no different from add/remove
469 if (dbus_timeout_get_enabled (timeout))
470 add_timeout (timeout, data);
472 remove_timeout (timeout, data);
476 wakeup_main (void *data)
478 ConnectionSetup *cs = data;
480 g_main_context_wakeup (cs->context);
484 /* Move to a new context */
485 static ConnectionSetup*
486 connection_setup_new_from_old (GMainContext *context,
487 ConnectionSetup *old)
491 g_assert (old->context != context);
493 cs = connection_setup_new (context, old->connection);
495 while (old->ios != NULL)
497 IOHandler *handler = old->ios->data;
499 connection_setup_add_watch (cs, handler->watch);
500 /* The old handler will be removed from old->ios as a side-effect */
503 while (old->timeouts != NULL)
505 TimeoutHandler *handler = old->timeouts->data;
507 connection_setup_add_timeout (cs, handler->timeout);
513 /** @} */ /* End of GLib bindings internals */
516 * atspi_dbus_connection_setup_with_g_main: (skip)
517 * @connection: the connection
518 * @context: the #GMainContext or #NULL for default context
520 * Sets the watch and timeout functions of a #DBusConnection
521 * to integrate the connection with the GLib main loop.
522 * Pass in #NULL for the #GMainContext unless you're
523 * doing something specialized.
525 * If called twice for the same context, does nothing the second
526 * time. If called once with context A and once with context B,
527 * context B replaces context A as the context monitoring the
531 atspi_dbus_connection_setup_with_g_main (DBusConnection *connection,
532 GMainContext *context)
534 ConnectionSetup *old_setup;
537 /* FIXME we never free the slot, so its refcount just keeps growing,
538 * which is kind of broken.
540 dbus_connection_allocate_data_slot (&_dbus_gmain_connection_slot);
541 if (_dbus_gmain_connection_slot < 0)
545 context = g_main_context_default ();
549 old_setup = dbus_connection_get_data (connection, _dbus_gmain_connection_slot);
550 if (old_setup != NULL)
552 if (old_setup->context == context)
553 return; /* nothing to do */
555 cs = connection_setup_new_from_old (context, old_setup);
557 /* Nuke the old setup */
558 dbus_connection_set_data (connection, _dbus_gmain_connection_slot, NULL, NULL);
563 cs = connection_setup_new (context, connection);
565 if (!dbus_connection_set_data (connection, _dbus_gmain_connection_slot, cs,
566 (DBusFreeFunction)connection_setup_free))
569 if (!dbus_connection_set_watch_functions (connection,
576 if (!dbus_connection_set_timeout_functions (connection,
583 dbus_connection_set_wakeup_main_function (connection,
590 g_error ("Not enough memory to set up DBusConnection for use with GLib");
594 * atspi_dbus_server_setup_with_g_main: (skip)
595 * @server: the server
596 * @context: the #GMainContext or #NULL for default
598 * Sets the watch and timeout functions of a #DBusServer
599 * to integrate the server with the GLib main loop.
600 * In most cases the context argument should be #NULL.
602 * If called twice for the same context, does nothing the second
603 * time. If called once with context A and once with context B,
604 * context B replaces context A as the context monitoring the
608 atspi_dbus_server_setup_with_g_main (DBusServer *server,
609 GMainContext *context)
611 ConnectionSetup *old_setup;
614 /* FIXME we never free the slot, so its refcount just keeps growing,
615 * which is kind of broken.
617 dbus_server_allocate_data_slot (&server_slot);
622 context = g_main_context_default ();
626 old_setup = dbus_server_get_data (server, server_slot);
627 if (old_setup != NULL)
629 if (old_setup->context == context)
630 return; /* nothing to do */
632 cs = connection_setup_new_from_old (context, old_setup);
634 /* Nuke the old setup */
635 if (!dbus_server_set_data (server, server_slot, NULL, NULL))
641 cs = connection_setup_new (context, NULL);
643 if (!dbus_server_set_data (server, server_slot, cs,
644 (DBusFreeFunction)connection_setup_free))
647 if (!dbus_server_set_watch_functions (server,
654 if (!dbus_server_set_timeout_functions (server,
664 g_error ("Not enough memory to set up DBusServer for use with GLib");