packaging: exclude on non X11 configuration
[platform/core/uifw/at-spi2-core.git] / atspi / atspi-gmain.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gmain.c GLib main loop integration
3  *
4  * Copyright (C) 2002, 2003 CodeFactory AB
5  * Copyright (C) 2005 Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 2.1
8  * 
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.
13  *
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.
18  * 
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
22  *
23  * This file is based on dbus-gmain.c from dbus-glib with functions renamed
24  * and unnecessary code removed.
25  */
26
27 #include <config.h>
28 #include <dbus/dbus.h>
29 #include "glib.h"
30 #include <string.h>
31
32 #include <libintl.h>
33 #define _(x) dgettext (GETTEXT_PACKAGE, x)
34 #define N_(x) x
35
36 /**
37  * @defgroup DBusGLibInternals GLib bindings implementation details
38  * @ingroup  DBusInternals
39  * @brief Implementation details of GLib bindings
40  *
41  * @{
42  */
43
44 /**
45  * DBusGMessageQueue:
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.
49  */
50 typedef struct
51 {
52   GSource source; /**< the parent GSource */
53   DBusConnection *connection; /**< the connection to dispatch */
54 } DBusGMessageQueue;
55
56 static gboolean message_queue_prepare  (GSource     *source,
57                                         gint        *timeout);
58 static gboolean message_queue_check    (GSource     *source);
59 static gboolean message_queue_dispatch (GSource     *source,
60                                         GSourceFunc  callback,
61                                         gpointer     user_data);
62
63 static const GSourceFuncs message_queue_funcs = {
64   message_queue_prepare,
65   message_queue_check,
66   message_queue_dispatch,
67   NULL
68 };
69
70 static gboolean
71 message_queue_prepare (GSource *source,
72                        gint    *timeout)
73 {
74   DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
75   
76   *timeout = -1;
77
78   return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);  
79 }
80
81 static gboolean
82 message_queue_check (GSource *source)
83 {
84   return FALSE;
85 }
86
87 static gboolean
88 message_queue_dispatch (GSource     *source,
89                         GSourceFunc  callback,
90                         gpointer     user_data)
91 {
92   DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
93
94   dbus_connection_ref (connection);
95
96   /* Only dispatch once - we don't want to starve other GSource */
97   dbus_connection_dispatch (connection);
98   
99   dbus_connection_unref (connection);
100
101   return TRUE;
102 }
103
104 typedef struct
105 {
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 */
111 } ConnectionSetup;
112
113
114 typedef struct
115 {
116   ConnectionSetup *cs;
117   GSource *source;
118   DBusWatch *watch;
119 } IOHandler;
120
121 typedef struct
122 {
123   ConnectionSetup *cs;
124   GSource *source;
125   DBusTimeout *timeout;
126 } TimeoutHandler;
127
128 dbus_int32_t _dbus_gmain_connection_slot = -1;
129 static dbus_int32_t server_slot = -1;
130
131 static ConnectionSetup*
132 connection_setup_new (GMainContext   *context,
133                       DBusConnection *connection)
134 {
135   ConnectionSetup *cs;
136
137   cs = g_new0 (ConnectionSetup, 1);
138
139   g_assert (context != NULL);
140   
141   cs->context = context;
142   g_main_context_ref (cs->context);  
143
144   if (connection)
145     {
146       cs->connection = connection;
147
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);
152     }
153   
154   return cs;
155 }
156
157 static void
158 io_handler_source_finalized (gpointer data)
159 {
160   IOHandler *handler;
161
162   handler = data;
163
164   if (handler->watch)
165     dbus_watch_set_data (handler->watch, NULL, NULL);
166   
167   g_free (handler);
168 }
169
170 static void
171 io_handler_destroy_source (void *data)
172 {
173   IOHandler *handler;
174
175   handler = data;
176
177   if (handler->source)
178     {
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);
184     }
185 }
186
187 static void
188 io_handler_watch_freed (void *data)
189 {
190   IOHandler *handler;
191
192   handler = data;
193
194   handler->watch = NULL;
195
196   io_handler_destroy_source (handler);
197 }
198
199 static gboolean
200 io_handler_dispatch (GIOChannel   *source,
201                      GIOCondition  condition,
202                      gpointer      data)
203 {
204   IOHandler *handler;
205   guint dbus_condition = 0;
206   DBusConnection *connection;
207
208   handler = data;
209
210   connection = handler->cs->connection;
211   
212   if (connection)
213     dbus_connection_ref (connection);
214   
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;
223
224   /* Note that we don't touch the handler after this, because
225    * dbus may have disabled the watch and thus killed the
226    * handler.
227    */
228   dbus_watch_handle (handler->watch, dbus_condition);
229   handler = NULL;
230   (void)handler;
231
232   if (connection)
233     dbus_connection_unref (connection);
234   
235   return TRUE;
236 }
237
238 /* Attach the connection setup to the given watch, removing any
239  * previously-attached connection setup.
240  */
241 static void
242 connection_setup_add_watch (ConnectionSetup *cs,
243                             DBusWatch       *watch)
244 {
245   guint flags;
246   GIOCondition condition;
247   GIOChannel *channel;
248   IOHandler *handler;
249   
250   if (!dbus_watch_get_enabled (watch))
251     return;
252   
253   flags = dbus_watch_get_flags (watch);
254
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;
260
261   handler = g_new0 (IOHandler, 1);
262   handler->cs = cs;
263   handler->watch = watch;
264   
265   channel = g_io_channel_unix_new (dbus_watch_get_unix_fd (watch));
266   
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);
271
272   cs->ios = g_slist_prepend (cs->ios, handler);
273   
274   dbus_watch_set_data (watch, handler, io_handler_watch_freed);
275   g_io_channel_unref (channel);
276 }
277
278 static void
279 connection_setup_remove_watch (ConnectionSetup *cs,
280                                DBusWatch       *watch)
281 {
282   IOHandler *handler;
283
284   handler = dbus_watch_get_data (watch);
285
286   if (handler == NULL || handler->cs != cs)
287     return;
288   
289   io_handler_destroy_source (handler);
290 }
291
292 static void
293 timeout_handler_source_finalized (gpointer data)
294 {
295   TimeoutHandler *handler;
296
297   handler = data;
298
299   if (handler->timeout)
300     dbus_timeout_set_data (handler->timeout, NULL, NULL);
301   
302   g_free (handler);
303 }
304
305 static void
306 timeout_handler_destroy_source (void *data)
307 {
308   TimeoutHandler *handler;
309
310   handler = data;
311
312   if (handler->source)
313     {
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);
319     }
320 }
321
322 static void
323 timeout_handler_timeout_freed (void *data)
324 {
325   TimeoutHandler *handler;
326
327   handler = data;
328
329   handler->timeout = NULL;
330
331   timeout_handler_destroy_source (handler);
332 }
333
334 static gboolean
335 timeout_handler_dispatch (gpointer      data)
336 {
337   TimeoutHandler *handler;
338
339   handler = data;
340
341   dbus_timeout_handle (handler->timeout);
342   
343   return TRUE;
344 }
345
346 static void
347 connection_setup_add_timeout (ConnectionSetup *cs,
348                               DBusTimeout     *timeout)
349 {
350   TimeoutHandler *handler;
351   
352   if (!dbus_timeout_get_enabled (timeout))
353     return;
354   
355   handler = g_new0 (TimeoutHandler, 1);
356   handler->cs = cs;
357   handler->timeout = timeout;
358
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);
363
364   cs->timeouts = g_slist_prepend (cs->timeouts, handler);
365
366   dbus_timeout_set_data (timeout, handler, timeout_handler_timeout_freed);
367 }
368
369 static void
370 connection_setup_remove_timeout (ConnectionSetup *cs,
371                                  DBusTimeout       *timeout)
372 {
373   TimeoutHandler *handler;
374   
375   handler = dbus_timeout_get_data (timeout);
376
377   if (handler == NULL)
378     return;
379   
380   timeout_handler_destroy_source (handler);
381 }
382
383 static void
384 connection_setup_free (ConnectionSetup *cs)
385 {
386   while (cs->ios)
387     io_handler_destroy_source (cs->ios->data);
388
389   while (cs->timeouts)
390     timeout_handler_destroy_source (cs->timeouts->data);
391
392   if (cs->message_queue_source)
393     {
394       GSource *source;
395
396       source = cs->message_queue_source;
397       cs->message_queue_source = NULL;
398
399       g_source_destroy (source);
400       g_source_unref (source);
401     }
402   
403   g_main_context_unref (cs->context);
404   g_free (cs);
405 }
406
407 static dbus_bool_t
408 add_watch (DBusWatch *watch,
409            gpointer   data)
410 {
411   ConnectionSetup *cs;
412
413   cs = data;
414
415   connection_setup_add_watch (cs, watch);
416   
417   return TRUE;
418 }
419
420 static void
421 remove_watch (DBusWatch *watch,
422               gpointer   data)
423 {
424   ConnectionSetup *cs;
425
426   cs = data;
427
428   connection_setup_remove_watch (cs, watch);
429 }
430
431 static void
432 watch_toggled (DBusWatch *watch,
433                void      *data)
434 {
435   /* Because we just exit on OOM, enable/disable is
436    * no different from add/remove
437    */
438   if (dbus_watch_get_enabled (watch))
439     add_watch (watch, data);
440   else
441     remove_watch (watch, data);
442 }
443
444 static dbus_bool_t
445 add_timeout (DBusTimeout *timeout,
446              void        *data)
447 {
448   ConnectionSetup *cs;
449
450   cs = data;
451   
452   if (!dbus_timeout_get_enabled (timeout))
453     return TRUE;
454
455   connection_setup_add_timeout (cs, timeout);
456
457   return TRUE;
458 }
459
460 static void
461 remove_timeout (DBusTimeout *timeout,
462                 void        *data)
463 {
464   ConnectionSetup *cs;
465
466   cs = data;
467
468   connection_setup_remove_timeout (cs, timeout);
469 }
470
471 static void
472 timeout_toggled (DBusTimeout *timeout,
473                  void        *data)
474 {
475   /* Because we just exit on OOM, enable/disable is
476    * no different from add/remove
477    */
478   if (dbus_timeout_get_enabled (timeout))
479     add_timeout (timeout, data);
480   else
481     remove_timeout (timeout, data);
482 }
483
484 static void
485 wakeup_main (void *data)
486 {
487   ConnectionSetup *cs = data;
488
489   g_main_context_wakeup (cs->context);
490 }
491
492
493 /* Move to a new context */
494 static ConnectionSetup*
495 connection_setup_new_from_old (GMainContext    *context,
496                                ConnectionSetup *old)
497 {
498   ConnectionSetup *cs;
499
500   g_assert (old->context != context);
501   
502   cs = connection_setup_new (context, old->connection);
503   
504   while (old->ios != NULL)
505     {
506       IOHandler *handler = old->ios->data;
507
508       connection_setup_add_watch (cs, handler->watch);
509       /* The old handler will be removed from old->ios as a side-effect */
510     }
511
512   while (old->timeouts != NULL)
513     {
514       TimeoutHandler *handler = old->timeouts->data;
515
516       connection_setup_add_timeout (cs, handler->timeout);
517     }
518
519   return cs;
520 }
521
522 /** @} */ /* End of GLib bindings internals */
523
524 /** @addtogroup DBusGLib
525  * @{
526  */
527
528 /**
529  * atspi_dbus_connection_setup_with_g_main:
530  * @connection: the connection
531  * @context: the #GMainContext or #NULL for default context
532  *
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.
537  *
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
541  * connection.
542  */
543 void
544 atspi_dbus_connection_setup_with_g_main (DBusConnection *connection,
545                                    GMainContext   *context)
546 {
547   ConnectionSetup *old_setup;
548   ConnectionSetup *cs;
549   
550   /* FIXME we never free the slot, so its refcount just keeps growing,
551    * which is kind of broken.
552    */
553   dbus_connection_allocate_data_slot (&_dbus_gmain_connection_slot);
554   if (_dbus_gmain_connection_slot < 0)
555     goto nomem;
556
557   if (context == NULL)
558     context = g_main_context_default ();
559
560   cs = NULL;
561   
562   old_setup = dbus_connection_get_data (connection, _dbus_gmain_connection_slot);
563   if (old_setup != NULL)
564     {
565       if (old_setup->context == context)
566         return; /* nothing to do */
567
568       cs = connection_setup_new_from_old (context, old_setup);
569       
570       /* Nuke the old setup */
571       dbus_connection_set_data (connection, _dbus_gmain_connection_slot, NULL, NULL);
572       old_setup = NULL;
573       (void)old_setup;
574     }
575
576   if (cs == NULL)
577     cs = connection_setup_new (context, connection);
578
579   if (!dbus_connection_set_data (connection, _dbus_gmain_connection_slot, cs,
580                                  (DBusFreeFunction)connection_setup_free))
581     goto nomem;
582   
583   if (!dbus_connection_set_watch_functions (connection,
584                                             add_watch,
585                                             remove_watch,
586                                             watch_toggled,
587                                             cs, NULL))
588     goto nomem;
589
590   if (!dbus_connection_set_timeout_functions (connection,
591                                               add_timeout,
592                                               remove_timeout,
593                                               timeout_toggled,
594                                               cs, NULL))
595     goto nomem;
596     
597   dbus_connection_set_wakeup_main_function (connection,
598                                             wakeup_main,
599                                             cs, NULL);
600       
601   return;
602
603  nomem:
604   g_error ("Not enough memory to set up DBusConnection for use with GLib");
605 }
606
607 /**
608  * atspi_dbus_server_setup_with_g_main:
609  * @server: the server
610  * @context: the #GMainContext or #NULL for default
611  *
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.
615  *
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
619  * connection.
620  */
621 void
622 atspi_dbus_server_setup_with_g_main (DBusServer   *server,
623                                GMainContext *context)
624 {
625   ConnectionSetup *old_setup;
626   ConnectionSetup *cs;
627   
628   /* FIXME we never free the slot, so its refcount just keeps growing,
629    * which is kind of broken.
630    */
631   dbus_server_allocate_data_slot (&server_slot);
632   if (server_slot < 0)
633     goto nomem;
634
635   if (context == NULL)
636     context = g_main_context_default ();
637
638   cs = NULL;
639   
640   old_setup = dbus_server_get_data (server, server_slot);
641   if (old_setup != NULL)
642     {
643       if (old_setup->context == context)
644         return; /* nothing to do */
645
646       cs = connection_setup_new_from_old (context, old_setup);
647       
648       /* Nuke the old setup */
649       if (!dbus_server_set_data (server, server_slot, NULL, NULL))
650         goto nomem;
651       old_setup = NULL;
652       (void)old_setup;
653     }
654
655   if (cs == NULL)
656     cs = connection_setup_new (context, NULL);
657
658   if (!dbus_server_set_data (server, server_slot, cs,
659                              (DBusFreeFunction)connection_setup_free))
660     goto nomem;
661   
662   if (!dbus_server_set_watch_functions (server,
663                                         add_watch,
664                                         remove_watch,
665                                         watch_toggled,
666                                         cs, NULL))
667     goto nomem;
668
669   if (!dbus_server_set_timeout_functions (server,
670                                           add_timeout,
671                                           remove_timeout,
672                                           timeout_toggled,
673                                           cs, NULL))
674     goto nomem;
675       
676   return;
677
678  nomem:
679   g_error ("Not enough memory to set up DBusServer for use with GLib");
680 }