00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "dbus-glib.h"
00025 #include <glib.h>
00026
00049 typedef struct DBusGSource DBusGSource;
00050
00051 struct DBusGSource
00052 {
00053 GSource source;
00055 GList *watch_fds;
00057 GMainContext *context;
00059 void *connection_or_server;
00060 };
00061
00062 typedef struct
00063 {
00064 int refcount;
00065
00066 GPollFD poll_fd;
00067 DBusWatch *watch;
00068
00069 unsigned int removed : 1;
00070 } WatchFD;
00071
00072 static WatchFD *
00073 watch_fd_new (void)
00074 {
00075 WatchFD *watch_fd;
00076
00077 watch_fd = g_new0 (WatchFD, 1);
00078 watch_fd->refcount = 1;
00079
00080 return watch_fd;
00081 }
00082
00083 static void
00084 watch_fd_ref (WatchFD *watch_fd)
00085 {
00086 watch_fd->refcount += 1;
00087 }
00088
00089 static void
00090 watch_fd_unref (WatchFD *watch_fd)
00091 {
00092 watch_fd->refcount -= 1;
00093
00094 if (watch_fd->refcount == 0)
00095 {
00096 g_assert (watch_fd->removed);
00097
00098 g_free (watch_fd);
00099 }
00100 }
00101
00102 static dbus_int32_t connection_slot = -1;
00103 static dbus_int32_t server_slot = -1;
00104
00105 static gboolean gsource_connection_prepare (GSource *source,
00106 gint *timeout);
00107 static gboolean gsource_connection_check (GSource *source);
00108 static gboolean gsource_connection_dispatch (GSource *source,
00109 GSourceFunc callback,
00110 gpointer user_data);
00111 static gboolean gsource_server_prepare (GSource *source,
00112 gint *timeout);
00113 static gboolean gsource_server_check (GSource *source);
00114 static gboolean gsource_server_dispatch (GSource *source,
00115 GSourceFunc callback,
00116 gpointer user_data);
00117
00118 static GSourceFuncs dbus_connection_funcs = {
00119 gsource_connection_prepare,
00120 gsource_connection_check,
00121 gsource_connection_dispatch,
00122 NULL
00123 };
00124
00125 static GSourceFuncs dbus_server_funcs = {
00126 gsource_server_prepare,
00127 gsource_server_check,
00128 gsource_server_dispatch,
00129 NULL
00130 };
00131
00132 static gboolean
00133 gsource_connection_prepare (GSource *source,
00134 gint *timeout)
00135 {
00136 DBusConnection *connection = ((DBusGSource *)source)->connection_or_server;
00137
00138 *timeout = -1;
00139
00140 return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);
00141 }
00142
00143 static gboolean
00144 gsource_server_prepare (GSource *source,
00145 gint *timeout)
00146 {
00147 *timeout = -1;
00148
00149 return FALSE;
00150 }
00151
00152 static gboolean
00153 dbus_gsource_check (GSource *source)
00154 {
00155 DBusGSource *dbus_source = (DBusGSource *)source;
00156 GList *list;
00157
00158 list = dbus_source->watch_fds;
00159
00160 while (list)
00161 {
00162 WatchFD *watch_fd = list->data;
00163
00164 if (watch_fd->poll_fd.revents != 0)
00165 return TRUE;
00166
00167 list = list->next;
00168 }
00169
00170 return FALSE;
00171 }
00172
00173 static gboolean
00174 gsource_connection_check (GSource *source)
00175 {
00176 return dbus_gsource_check (source);
00177 }
00178
00179 static gboolean
00180 gsource_server_check (GSource *source)
00181 {
00182 return dbus_gsource_check (source);
00183 }
00184
00185 static gboolean
00186 dbus_gsource_dispatch (GSource *source,
00187 GSourceFunc callback,
00188 gpointer user_data,
00189 dbus_bool_t is_server)
00190 {
00191 DBusGSource *dbus_source = (DBusGSource *)source;
00192 GList *copy, *list;
00193
00194
00195 copy = g_list_copy (dbus_source->watch_fds);
00196 g_list_foreach (copy, (GFunc)watch_fd_ref, NULL);
00197
00198 list = copy;
00199 while (list)
00200 {
00201 WatchFD *watch_fd = list->data;
00202
00203 if (!watch_fd->removed && watch_fd->poll_fd.revents != 0)
00204 {
00205 guint condition = 0;
00206
00207 if (watch_fd->poll_fd.revents & G_IO_IN)
00208 condition |= DBUS_WATCH_READABLE;
00209 if (watch_fd->poll_fd.revents & G_IO_OUT)
00210 condition |= DBUS_WATCH_WRITABLE;
00211 if (watch_fd->poll_fd.revents & G_IO_ERR)
00212 condition |= DBUS_WATCH_ERROR;
00213 if (watch_fd->poll_fd.revents & G_IO_HUP)
00214 condition |= DBUS_WATCH_HANGUP;
00215
00216 dbus_watch_handle (watch_fd->watch, condition);
00217 }
00218
00219 list = list->next;
00220 }
00221
00222 g_list_foreach (copy, (GFunc)watch_fd_unref, NULL);
00223 g_list_free (copy);
00224
00225 return TRUE;
00226 }
00227
00228 static gboolean
00229 gsource_connection_dispatch (GSource *source,
00230 GSourceFunc callback,
00231 gpointer user_data)
00232 {
00233 DBusGSource *dbus_source = (DBusGSource *)source;
00234 DBusConnection *connection = dbus_source->connection_or_server;
00235
00236 dbus_connection_ref (connection);
00237
00238 dbus_gsource_dispatch (source, callback, user_data,
00239 FALSE);
00240
00241
00242 while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS)
00243 ;
00244
00245 dbus_connection_unref (connection);
00246
00247 return TRUE;
00248 }
00249
00250 static gboolean
00251 gsource_server_dispatch (GSource *source,
00252 GSourceFunc callback,
00253 gpointer user_data)
00254 {
00255 DBusGSource *dbus_source = (DBusGSource *)source;
00256 DBusServer *server = dbus_source->connection_or_server;
00257
00258 dbus_server_ref (server);
00259
00260 dbus_gsource_dispatch (source, callback, user_data,
00261 TRUE);
00262
00263 dbus_server_unref (server);
00264
00265 return TRUE;
00266 }
00267
00268 static dbus_bool_t
00269 add_watch (DBusWatch *watch,
00270 gpointer data)
00271 {
00272 WatchFD *watch_fd;
00273 DBusGSource *dbus_source;
00274 guint flags;
00275
00276 if (!dbus_watch_get_enabled (watch))
00277 return TRUE;
00278
00279 dbus_source = data;
00280
00281 watch_fd = watch_fd_new ();
00282 watch_fd->poll_fd.fd = dbus_watch_get_fd (watch);
00283 watch_fd->poll_fd.events = 0;
00284 flags = dbus_watch_get_flags (watch);
00285 dbus_watch_set_data (watch, watch_fd, (DBusFreeFunction)watch_fd_unref);
00286
00287 if (flags & DBUS_WATCH_READABLE)
00288 watch_fd->poll_fd.events |= G_IO_IN;
00289 if (flags & DBUS_WATCH_WRITABLE)
00290 watch_fd->poll_fd.events |= G_IO_OUT;
00291 watch_fd->poll_fd.events |= G_IO_ERR | G_IO_HUP;
00292
00293 watch_fd->watch = watch;
00294
00295 g_source_add_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
00296
00297 dbus_source->watch_fds = g_list_prepend (dbus_source->watch_fds, watch_fd);
00298
00299 return TRUE;
00300 }
00301
00302 static void
00303 remove_watch (DBusWatch *watch,
00304 gpointer data)
00305 {
00306 DBusGSource *dbus_source = data;
00307 WatchFD *watch_fd;
00308
00309 watch_fd = dbus_watch_get_data (watch);
00310 if (watch_fd == NULL)
00311 return;
00312
00313 watch_fd->removed = TRUE;
00314 watch_fd->watch = NULL;
00315
00316 dbus_source->watch_fds = g_list_remove (dbus_source->watch_fds, watch_fd);
00317
00318 g_source_remove_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
00319
00320 dbus_watch_set_data (watch, NULL, NULL);
00321
00322
00323 }
00324
00325 static void
00326 watch_toggled (DBusWatch *watch,
00327 void *data)
00328 {
00329
00330
00331
00332 if (dbus_watch_get_enabled (watch))
00333 add_watch (watch, data);
00334 else
00335 remove_watch (watch, data);
00336 }
00337
00338 static gboolean
00339 timeout_handler (gpointer data)
00340 {
00341 DBusTimeout *timeout = data;
00342
00343 dbus_timeout_handle (timeout);
00344
00345 return TRUE;
00346 }
00347
00348 static dbus_bool_t
00349 add_timeout (DBusTimeout *timeout,
00350 void *data)
00351 {
00352 DBusGSource *dbus_source = data;
00353 GSource *source;
00354
00355 if (!dbus_timeout_get_enabled (timeout))
00356 return TRUE;
00357
00358 source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
00359 g_source_set_callback (source, timeout_handler, timeout, NULL);
00360 g_source_attach (source, dbus_source->context);
00361
00362 dbus_timeout_set_data (timeout, GUINT_TO_POINTER (g_source_get_id (source)),
00363 NULL);
00364
00365 return TRUE;
00366 }
00367
00368 static void
00369 remove_timeout (DBusTimeout *timeout,
00370 void *data)
00371 {
00372 guint timeout_tag;
00373
00374 timeout_tag = GPOINTER_TO_UINT (dbus_timeout_get_data (timeout));
00375
00376 if (timeout_tag != 0)
00377 g_source_remove (timeout_tag);
00378 }
00379
00380 static void
00381 timeout_toggled (DBusTimeout *timeout,
00382 void *data)
00383 {
00384
00385
00386
00387 if (dbus_timeout_get_enabled (timeout))
00388 add_timeout (timeout, data);
00389 else
00390 remove_timeout (timeout, data);
00391 }
00392
00393
00394 static void
00395 free_source (GSource *source)
00396 {
00397 g_source_destroy (source);
00398 }
00399
00400 static void
00401 wakeup_main (void *data)
00402 {
00403 DBusGSource *dbus_source = data;
00404
00405 g_main_context_wakeup (dbus_source->context);
00406 }
00407
00408
00410
00415 static GSource*
00416 create_source (void *connection_or_server,
00417 GSourceFuncs *funcs,
00418 GMainContext *context)
00419 {
00420 GSource *source;
00421 DBusGSource *dbus_source;
00422
00423 source = g_source_new (funcs, sizeof (DBusGSource));
00424
00425 dbus_source = (DBusGSource *)source;
00426 dbus_source->connection_or_server = connection_or_server;
00427 dbus_source->context = context;
00428
00429 return source;
00430 }
00431
00441 void
00442 dbus_connection_setup_with_g_main (DBusConnection *connection,
00443 GMainContext *context)
00444 {
00445 GSource *source;
00446
00447 source = create_source (connection, &dbus_connection_funcs, context);
00448
00449 if (!dbus_connection_set_watch_functions (connection,
00450 add_watch,
00451 remove_watch,
00452 watch_toggled,
00453 source, NULL))
00454 goto nomem;
00455
00456 if (!dbus_connection_set_timeout_functions (connection,
00457 add_timeout,
00458 remove_timeout,
00459 timeout_toggled,
00460 NULL, NULL))
00461 goto nomem;
00462
00463 dbus_connection_set_wakeup_main_function (connection,
00464 wakeup_main,
00465 source, NULL);
00466
00467 g_source_attach (source, context);
00468
00469
00470
00471
00472 dbus_connection_allocate_data_slot (&connection_slot);
00473 if (connection_slot < 0)
00474 goto nomem;
00475
00476 if (!dbus_connection_set_data (connection, connection_slot, source,
00477 (DBusFreeFunction)free_source))
00478 goto nomem;
00479
00480 return;
00481
00482 nomem:
00483 g_error ("Not enough memory to set up DBusConnection for use with GLib");
00484 }
00485
00494 void
00495 dbus_server_setup_with_g_main (DBusServer *server,
00496 GMainContext *context)
00497 {
00498 GSource *source;
00499
00500 source = create_source (server, &dbus_server_funcs, context);
00501
00502 dbus_server_set_watch_functions (server,
00503 add_watch,
00504 remove_watch,
00505 watch_toggled,
00506 source, NULL);
00507
00508 dbus_server_set_timeout_functions (server,
00509 add_timeout,
00510 remove_timeout,
00511 timeout_toggled,
00512 NULL, NULL);
00513
00514 g_source_attach (source, context);
00515
00516
00517
00518
00519 dbus_server_allocate_data_slot (&server_slot);
00520 if (server_slot < 0)
00521 goto nomem;
00522
00523 if (!dbus_server_set_data (server, server_slot, source,
00524 (DBusFreeFunction)free_source))
00525 goto nomem;
00526
00527 return;
00528
00529 nomem:
00530 g_error ("Not enough memory to set up DBusServer for use with GLib");
00531 }
00532