dbus-gmain.c 10.9 KB
Newer Older
1 2 3
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gmain.c GLib main loop integration
 *
4
 * Copyright (C) 2002, 2003  CodeFactory AB
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * Licensed under the Academic Free License version 1.2
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "dbus-glib.h"
#include <glib.h>

27 28 29 30 31 32 33 34 35 36
/**
 * @defgroup DBusGLib GLib bindings
 * @ingroup  DBus
 * @brief API for using D-BUS with GLib
 *
 * Convenience functions are provided for using D-BUS
 * with the GLib library (see http://www.gtk.org for GLib
 * information).
 * 
 */
37

38 39 40 41 42 43 44 45 46 47 48 49 50 51
/**
 * @defgroup DBusGLibInternals GLib bindings implementation details
 * @ingroup  DBusInternals
 * @brief Implementation details of GLib bindings
 *
 * @{
 */

/** @typedef DBusGSource
 * A GSource representing a #DBusConnection or #DBusServer
 */
typedef struct DBusGSource DBusGSource;

struct DBusGSource
52
{
53
  GSource source; /**< the parent GSource */
54

55 56
  GList *poll_fds;      /**< descriptors we're watching */
  GHashTable *watches;  /**< hash of DBusWatch objects */
57

58
  void *connection_or_server; /**< DBusConnection or DBusServer */
59 60
};

61
static GStaticMutex connection_slot_lock = G_STATIC_MUTEX_INIT;
62
static int connection_slot = -1;
63 64
static GStaticMutex server_slot_lock = G_STATIC_MUTEX_INIT;
static int server_slot = -1;
65

66
static gboolean dbus_connection_prepare  (GSource     *source,
67
                                          gint        *timeout);
68 69
static gboolean dbus_connection_check    (GSource     *source);
static gboolean dbus_connection_dispatch (GSource     *source,
70 71 72 73 74 75 76 77 78 79
                                          GSourceFunc  callback,
                                          gpointer     user_data);
static gboolean dbus_server_prepare      (GSource     *source,
                                          gint        *timeout);
static gboolean dbus_server_check        (GSource     *source);
static gboolean dbus_server_dispatch     (GSource     *source,
                                          GSourceFunc  callback,
                                          gpointer     user_data);

static GSourceFuncs dbus_connection_funcs = {
80 81 82 83 84
  dbus_connection_prepare,
  dbus_connection_check,
  dbus_connection_dispatch,
  NULL
};
85

86 87 88 89 90 91 92
static GSourceFuncs dbus_server_funcs = {
  dbus_server_prepare,
  dbus_server_check,
  dbus_server_dispatch,
  NULL
};

93
static gboolean
94 95
dbus_connection_prepare (GSource *source,
			 gint    *timeout)
96
{
97
  DBusConnection *connection = ((DBusGSource *)source)->connection_or_server;
98
  
99 100
  *timeout = -1;

101
  return (dbus_connection_get_n_messages (connection) > 0);  
102 103
}

104
static gboolean
105 106 107 108 109 110 111 112 113 114
dbus_server_prepare (GSource *source,
                     gint    *timeout)
{
  *timeout = -1;

  return FALSE;
}

static gboolean
dbus_gsource_check (GSource *source)
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
{
  DBusGSource *dbus_source = (DBusGSource *)source;
  GList *list;

  list = dbus_source->poll_fds;

  while (list)
    {
      GPollFD *poll_fd = list->data;

      if (poll_fd->revents != 0)
	return TRUE;

      list = list->next;
    }

  return FALSE;  
}

static gboolean
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
dbus_connection_check (GSource *source)
{
  return dbus_gsource_check (source);
}

static gboolean
dbus_server_check (GSource *source)
{
  return dbus_gsource_check (source);
}

static gboolean
dbus_gsource_dispatch (GSource     *source,
                       GSourceFunc  callback,
                       gpointer     user_data,
                       dbus_bool_t  is_server)
151
{
152
   DBusGSource *dbus_source = (DBusGSource *)source;
153
   GList *copy, *list;
154

155 156 157
   /* We need to traverse a copy of the list, since it can change in
      dbus_connect_handle_watch. */
   copy = g_list_copy (dbus_source->poll_fds);
158

159
   list = copy;
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
   while (list)
     {
       GPollFD *poll_fd = list->data;

       if (poll_fd->revents != 0)
	 {
	   DBusWatch *watch = g_hash_table_lookup (dbus_source->watches, poll_fd);
	   guint condition = 0;
	   
	   if (poll_fd->revents & G_IO_IN)
	     condition |= DBUS_WATCH_READABLE;
	   if (poll_fd->revents & G_IO_OUT)
	     condition |= DBUS_WATCH_WRITABLE;
	   if (poll_fd->revents & G_IO_ERR)
	     condition |= DBUS_WATCH_ERROR;
	   if (poll_fd->revents & G_IO_HUP)
	     condition |= DBUS_WATCH_HANGUP;
177 178 179 180 181 182 183

           if (is_server)
             dbus_server_handle_watch (dbus_source->connection_or_server,
                                       watch, condition);
           else
             dbus_connection_handle_watch (dbus_source->connection_or_server,
                                           watch, condition);
184
	 }
185

186 187 188
       list = list->next;
     }

189
   g_list_free (copy);   
190 191

   return TRUE;
192 193
}

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
static gboolean
dbus_connection_dispatch (GSource     *source,
			  GSourceFunc  callback,
			  gpointer     user_data)
{
  DBusGSource *dbus_source = (DBusGSource *)source;
  DBusConnection *connection = dbus_source->connection_or_server;

  dbus_connection_ref (connection);

  dbus_gsource_dispatch (source, callback, user_data,
                         FALSE);
  
  /* Dispatch messages */
  while (dbus_connection_dispatch_message (connection))
    ;

   dbus_connection_unref (connection);
   
   return TRUE;
}

static gboolean
dbus_server_dispatch (GSource     *source,
                      GSourceFunc  callback,
                      gpointer     user_data)
{
  DBusGSource *dbus_source = (DBusGSource *)source;
  DBusServer *server = dbus_source->connection_or_server;

  dbus_server_ref (server);

  dbus_gsource_dispatch (source, callback, user_data,
                         TRUE);

  dbus_server_unref (server);
   
  return TRUE;
}
     
234
static dbus_bool_t
235 236
add_watch (DBusWatch *watch,
	   gpointer   data)
237
{
238 239 240 241 242
  GPollFD *poll_fd;
  DBusGSource *dbus_source;
  guint flags;
  
  dbus_source = data;
243
  
244 245 246 247 248 249
  poll_fd = g_new (GPollFD, 1);
  poll_fd->fd = dbus_watch_get_fd (watch);
  poll_fd->events = 0;
  flags = dbus_watch_get_flags (watch);
  dbus_watch_set_data (watch, poll_fd, NULL);

250
  if (flags & DBUS_WATCH_READABLE)
251
    poll_fd->events |= G_IO_IN;
252
  if (flags & DBUS_WATCH_WRITABLE)
253
    poll_fd->events |= G_IO_OUT;
254
  poll_fd->events |= G_IO_ERR | G_IO_HUP;
255 256 257 258 259

  g_source_add_poll ((GSource *)dbus_source, poll_fd);

  dbus_source->poll_fds = g_list_prepend (dbus_source->poll_fds, poll_fd);
  g_hash_table_insert (dbus_source->watches, poll_fd, watch);
260 261

  return TRUE;
262 263 264
}

static void
265 266
remove_watch (DBusWatch *watch,
	      gpointer   data)
267
{
268 269 270 271
  DBusGSource *dbus_source = data;
  GPollFD *poll_fd;
  
  poll_fd = dbus_watch_get_data (watch);
272
  
273 274 275 276 277
  dbus_source->poll_fds = g_list_remove (dbus_source->poll_fds, poll_fd);
  g_hash_table_remove (dbus_source->watches, poll_fd);
  g_source_remove_poll ((GSource *)dbus_source, poll_fd);
  
  g_free (poll_fd);
278 279
}

280 281 282 283 284 285 286 287 288 289
static gboolean
timeout_handler (gpointer data)
{
  DBusTimeout *timeout = data;

  dbus_timeout_handle (timeout);

  return FALSE;
}

290
static dbus_bool_t
291 292
add_timeout (DBusTimeout *timeout,
	     void        *data)
293
{
294 295 296 297 298 299
  guint timeout_tag;

  timeout_tag = g_timeout_add (dbus_timeout_get_interval (timeout),
			       timeout_handler, timeout);
  
  dbus_timeout_set_data (timeout, GUINT_TO_POINTER (timeout_tag), NULL);
300 301

  return TRUE;
302
}
303

304 305 306 307
static void
remove_timeout (DBusTimeout *timeout,
		void        *data)
{
308 309 310
  guint timeout_tag;
  
  timeout_tag = GPOINTER_TO_UINT (dbus_timeout_get_data (timeout));
311
  
312
  g_source_remove (timeout_tag);
313
}
314

315 316 317 318 319 320
static void
free_source (GSource *source)
{
  g_source_destroy (source);
}

321 322 323 324 325 326 327
static void
wakeup_main (void *data)
{
  g_main_context_wakeup (NULL);
}


328 329 330 331 332 333 334 335 336
/** @} */ /* End of GLib bindings internals */

/** @addtogroup DBusGLib
 * @{
 */

static GSource*
create_source (void         *connection_or_server,
               GSourceFuncs *funcs)
337
{
338 339 340
  GSource *source;
  DBusGSource *dbus_source;

341
  source = g_source_new (funcs, sizeof (DBusGSource));
342 343 344
  
  dbus_source = (DBusGSource *)source;  
  dbus_source->watches = g_hash_table_new (NULL, NULL);
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
  dbus_source->connection_or_server = connection_or_server;

  return source;
}

/**
 * Sets the watch and timeout functions of a #DBusConnection
 * to integrate the connection with the GLib main loop.
 *
 * @param connection the connection
 */
void
dbus_connection_setup_with_g_main (DBusConnection *connection)
{
  GSource *source;

  source = create_source (connection, &dbus_connection_funcs);
362

363 364 365 366 367
  if (!dbus_connection_set_watch_functions (connection,
                                            add_watch,
                                            remove_watch,
                                            source, NULL))
    goto nomem;
368

369 370 371 372 373 374
  if (!dbus_connection_set_timeout_functions (connection,
                                              add_timeout,
                                              remove_timeout,
                                              NULL, NULL))
    goto nomem;
    
375 376 377 378
  dbus_connection_set_wakeup_main_function (connection,
					    wakeup_main,
					    NULL, NULL);
      
379
  g_source_attach (source, NULL);
380

381
  g_static_mutex_lock (&connection_slot_lock);
382 383
  if (connection_slot == -1 )
    connection_slot = dbus_connection_allocate_data_slot ();
384
  g_static_mutex_unlock (&connection_slot_lock);
385

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
  if (connection_slot < 0)
    goto nomem;

  if (!dbus_connection_set_data (connection, connection_slot, source,
                                 (DBusFreeFunction)free_source))
    goto nomem;

  return;

 nomem:
  g_error ("Not enough memory to set up DBusConnection for use with GLib");
}

/**
 * Sets the watch and timeout functions of a #DBusServer
 * to integrate the server with the GLib main loop.
 *
 * @param server the server
 */
void
dbus_server_setup_with_g_main (DBusServer *server)
{
  GSource *source;

  source = create_source (server, &dbus_server_funcs);

  dbus_server_set_watch_functions (server,
                                   add_watch,
                                   remove_watch,
                                   source, NULL);

  dbus_server_set_timeout_functions (server,
                                     add_timeout,
                                     remove_timeout,
                                     NULL, NULL);
421
  
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
  g_source_attach (source, NULL);

  g_static_mutex_lock (&server_slot_lock);
  if (server_slot == -1 )
    server_slot = dbus_server_allocate_data_slot ();
  g_static_mutex_unlock (&server_slot_lock);

  if (server_slot < 0)
    goto nomem;

  if (!dbus_server_set_data (server, server_slot, source,
                             (DBusFreeFunction)free_source))
    goto nomem;

  return;

 nomem:
  g_error ("Not enough memory to set up DBusServer for use with GLib");
440
}
441 442

/** @} */ /* end of public API */