Main Page   Modules   Data Structures   File List   Data Fields   Related Pages  

dbus-gproxy.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-gcall.c convenience routines for calling methods, etc.
00003  *
00004  * Copyright (C) 2003  Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.0
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 #include "dbus-glib.h"
00024 #include <string.h>
00025 
00036 typedef struct DBusGProxyManager DBusGProxyManager;
00037 
00041 struct DBusGProxy
00042 {
00043   GObject parent;             
00045   DBusGProxyManager *manager; 
00046   char *service;              
00047   char *path;                 
00048   char *interface;            
00049 };
00050 
00054 struct DBusGProxyClass
00055 {
00056   GObjectClass parent_class;  
00057 };
00058 
00059 static void dbus_gproxy_init          (DBusGProxy      *proxy);
00060 static void dbus_gproxy_class_init    (DBusGProxyClass *klass);
00061 static void dbus_gproxy_finalize      (GObject         *object);
00062 static void dbus_gproxy_dispose       (GObject         *object);
00063 static void dbus_gproxy_destroy       (DBusGProxy      *proxy);
00064 static void dbus_gproxy_emit_received (DBusGProxy      *proxy,
00065                                        DBusMessage     *message);
00066 
00067 
00072 typedef struct
00073 {
00074   GSList *proxies; 
00076   char name[4]; 
00081 } DBusGProxyList;
00082 
00088 struct DBusGProxyManager
00089 {
00090   GStaticMutex lock; 
00091   int refcount;      
00092   DBusConnection *connection; 
00094   GHashTable *proxy_lists; 
00098 };
00099 
00100 static DBusGProxyManager *dbus_gproxy_manager_ref    (DBusGProxyManager *manager);
00101 static DBusHandlerResult dbus_gproxy_manager_filter (DBusConnection    *connection,
00102                                                      DBusMessage       *message,
00103                                                      void              *user_data);
00104 
00106 #define LOCK_MANAGER(mgr)   (g_static_mutex_lock (&(mgr)->lock))
00107 
00108 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
00109 
00110 static int gproxy_manager_slot = -1;
00111 
00112 /* Lock controlling get/set manager as data on each connection */
00113 static GStaticMutex connection_gproxy_lock = G_STATIC_MUTEX_INIT;
00114 
00115 static DBusGProxyManager*
00116 dbus_gproxy_manager_get (DBusConnection *connection)
00117 {
00118   DBusGProxyManager *manager;
00119 
00120   dbus_connection_allocate_data_slot (&gproxy_manager_slot);
00121   if (gproxy_manager_slot < 0)
00122     g_error ("out of memory");
00123   
00124   g_static_mutex_lock (&connection_gproxy_lock);
00125   
00126   manager = dbus_connection_get_data (connection, gproxy_manager_slot);
00127   if (manager != NULL)
00128     {
00129       dbus_connection_free_data_slot (&gproxy_manager_slot);
00130       dbus_gproxy_manager_ref (manager);
00131       g_static_mutex_unlock (&connection_gproxy_lock);
00132       return manager;
00133     }
00134   
00135   manager = g_new0 (DBusGProxyManager, 1);
00136 
00137   manager->refcount = 1;
00138   manager->connection = connection;
00139   
00140   g_static_mutex_init (&manager->lock);
00141 
00142   /* Proxy managers keep the connection alive, which means that
00143    * DBusGProxy indirectly does. To free a connection you have to free
00144    * all the proxies referring to it.
00145    */
00146   dbus_connection_ref (manager->connection);
00147 
00148   dbus_connection_set_data (connection, gproxy_manager_slot,
00149                             manager, NULL);
00150 
00151   dbus_connection_add_filter (connection, dbus_gproxy_manager_filter,
00152                               manager, NULL);
00153   
00154   g_static_mutex_unlock (&connection_gproxy_lock);
00155   
00156   return manager;
00157 }
00158 
00159 static DBusGProxyManager * 
00160 dbus_gproxy_manager_ref (DBusGProxyManager *manager)
00161 {
00162   g_assert (manager != NULL);
00163   g_assert (manager->refcount > 0);
00164 
00165   LOCK_MANAGER (manager);
00166   
00167   manager->refcount += 1;
00168 
00169   UNLOCK_MANAGER (manager);
00170 
00171   return manager;
00172 }
00173 
00174 static void
00175 dbus_gproxy_manager_unref (DBusGProxyManager *manager)
00176 {
00177   g_assert (manager != NULL);
00178   g_assert (manager->refcount > 0);
00179 
00180   LOCK_MANAGER (manager);
00181   manager->refcount -= 1;
00182   if (manager->refcount == 0)
00183     {
00184       UNLOCK_MANAGER (manager);
00185 
00186       if (manager->proxy_lists)
00187         {
00188           /* can't have any proxies left since they hold
00189            * a reference to the proxy manager.
00190            */
00191           g_assert (g_hash_table_size (manager->proxy_lists) == 0);
00192           
00193           g_hash_table_destroy (manager->proxy_lists);
00194           manager->proxy_lists = NULL;
00195         }
00196       
00197       g_static_mutex_free (&manager->lock);
00198 
00199       g_static_mutex_lock (&connection_gproxy_lock);
00200 
00201       dbus_connection_remove_filter (manager->connection, dbus_gproxy_manager_filter,
00202                                      manager);
00203       
00204       dbus_connection_set_data (manager->connection,
00205                                 gproxy_manager_slot,
00206                                 NULL, NULL);
00207 
00208       g_static_mutex_unlock (&connection_gproxy_lock);
00209       
00210       dbus_connection_unref (manager->connection);
00211       g_free (manager);
00212 
00213       dbus_connection_free_data_slot (&gproxy_manager_slot);
00214     }
00215   else
00216     {
00217       UNLOCK_MANAGER (manager);
00218     }
00219 }
00220 
00221 static guint
00222 tristring_hash (gconstpointer key)
00223 {
00224   const char *p = key;
00225   guint h = *p;
00226 
00227   if (h)
00228     {
00229       for (p += 1; *p != '\0'; p++)
00230         h = (h << 5) - h + *p;
00231     }
00232 
00233   /* skip nul and do the next substring */
00234   for (p += 1; *p != '\0'; p++)
00235     h = (h << 5) - h + *p;
00236 
00237   /* skip nul again and another substring */
00238   for (p += 1; *p != '\0'; p++)
00239     h = (h << 5) - h + *p;
00240   
00241   return h;
00242 }
00243 
00244 static gboolean
00245 strequal_len (const char *a,
00246               const char *b,
00247               size_t     *lenp)
00248 {
00249   size_t a_len;
00250   size_t b_len;
00251 
00252   a_len = strlen (a);
00253   b_len = strlen (b);
00254 
00255   if (a_len != b_len)
00256     return FALSE;
00257 
00258   if (memcmp (a, b, a_len) != 0)
00259     return FALSE;
00260   
00261   *lenp = a_len;
00262 
00263   return TRUE;
00264 }
00265 
00266 static gboolean
00267 tristring_equal (gconstpointer  a,
00268                  gconstpointer  b)
00269 {
00270   const char *ap = a;
00271   const char *bp = b;
00272   size_t len;
00273 
00274   if (!strequal_len (ap, bp, &len))
00275     return FALSE;
00276 
00277   ap += len + 1;
00278   bp += len + 1;
00279 
00280   if (!strequal_len (ap, bp, &len))
00281     return FALSE;
00282 
00283   ap += len + 1;
00284   bp += len + 1;
00285 
00286   if (strcmp (ap, bp) != 0)
00287     return FALSE;
00288   
00289   return TRUE;
00290 }
00291 
00292 static char*
00293 tristring_alloc_from_strings (size_t      padding_before,
00294                               const char *service,
00295                               const char *path,
00296                               const char *interface)
00297 {
00298   size_t service_len, iface_len, path_len, len;
00299   char *tri;
00300   
00301   if (service)
00302     service_len = strlen (service);
00303   else
00304     service_len = 0;
00305 
00306   path_len = strlen (path);
00307   
00308   iface_len = strlen (interface);
00309 
00310   tri = g_malloc (padding_before + service_len + path_len + iface_len + 3);
00311 
00312   len = padding_before;
00313   
00314   if (service)
00315     memcpy (&tri[len], service, service_len);
00316 
00317   len += service_len;
00318   tri[len] = '\0';
00319   len += 1;
00320 
00321   g_assert (len == (padding_before + service_len + 1));
00322   
00323   memcpy (&tri[len], path, path_len);
00324   len += path_len;
00325   tri[len] = '\0';
00326   len += 1;
00327 
00328   g_assert (len == (padding_before + service_len + path_len + 2));
00329   
00330   memcpy (&tri[len], interface, iface_len);
00331   len += iface_len;
00332   tri[len] = '\0';
00333   len += 1;
00334 
00335   g_assert (len == (padding_before + service_len + path_len + iface_len + 3));
00336 
00337   return tri;
00338 }
00339 
00340 static char*
00341 tristring_from_proxy (DBusGProxy *proxy)
00342 {
00343   return tristring_alloc_from_strings (0,
00344                                        proxy->service,
00345                                        proxy->path,
00346                                        proxy->interface);
00347 }
00348 
00349 static char*
00350 tristring_from_message (DBusMessage *message)
00351 {
00352   return tristring_alloc_from_strings (0,
00353                                        dbus_message_get_sender (message),
00354                                        dbus_message_get_path (message),
00355                                        dbus_message_get_interface (message));
00356 }
00357 
00358 static DBusGProxyList*
00359 gproxy_list_new (DBusGProxy *first_proxy)
00360 {
00361   DBusGProxyList *list;
00362   
00363   list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
00364                                                first_proxy->service,
00365                                                first_proxy->path,
00366                                                first_proxy->interface);
00367   list->proxies = NULL;
00368 
00369   return list;
00370 }
00371 
00372 static void
00373 gproxy_list_free (DBusGProxyList *list)
00374 {
00375   /* we don't hold a reference to the proxies in the list,
00376    * as they ref the GProxyManager
00377    */
00378   g_slist_free (list->proxies);  
00379 
00380   g_free (list);
00381 }
00382 
00383 static char*
00384 gproxy_get_match_rule (DBusGProxy *proxy)
00385 {
00386   /* FIXME Escaping is required here */
00387   
00388   if (proxy->service)
00389     return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
00390                             proxy->service, proxy->path, proxy->interface);
00391   else
00392     return g_strdup_printf ("type='signal',path='%s',interface='%s'",
00393                             proxy->path, proxy->interface);
00394 }
00395 
00396 static void
00397 dbus_gproxy_manager_register (DBusGProxyManager *manager,
00398                               DBusGProxy        *proxy)
00399 {
00400   DBusGProxyList *list;
00401 
00402   LOCK_MANAGER (manager);
00403 
00404   if (manager->proxy_lists == NULL)
00405     {
00406       list = NULL;
00407       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
00408                                                     tristring_equal,
00409                                                     NULL,
00410                                                     (GFreeFunc) gproxy_list_free);
00411     }
00412   else
00413     {
00414       char *tri;
00415 
00416       tri = tristring_from_proxy (proxy);
00417       
00418       list = g_hash_table_lookup (manager->proxy_lists, tri);
00419 
00420       g_free (tri);
00421     }
00422       
00423   if (list == NULL)
00424     {
00425       list = gproxy_list_new (proxy);
00426       
00427       g_hash_table_replace (manager->proxy_lists,
00428                             list->name, list);
00429     }
00430 
00431   if (list->proxies == NULL)
00432     {
00433       /* We have to add the match rule to the server,
00434        * but FIXME only if the server is a message bus,
00435        * not if it's a peer.
00436        */
00437       char *rule;
00438 
00439       rule = gproxy_get_match_rule (proxy);
00440       
00441       /* We don't check for errors; it's not like anyone would handle them,
00442        * and we don't want a round trip here.
00443        */
00444       dbus_bus_add_match (manager->connection,
00445                           rule, NULL);
00446 
00447       g_free (rule);
00448     }
00449 
00450   g_assert (g_slist_find (list->proxies, proxy) == NULL);
00451   
00452   list->proxies = g_slist_prepend (list->proxies, proxy);
00453   
00454   UNLOCK_MANAGER (manager);
00455 }
00456 
00457 static void
00458 dbus_gproxy_manager_unregister (DBusGProxyManager *manager,
00459                                 DBusGProxy        *proxy)
00460 {
00461   DBusGProxyList *list;
00462   char *tri;
00463   
00464   LOCK_MANAGER (manager);
00465 
00466 #ifndef G_DISABLE_CHECKS
00467   if (manager->proxy_lists == NULL)
00468     {
00469       g_warning ("Trying to unregister a proxy but there aren't any registered");
00470       return;
00471     }
00472 #endif
00473 
00474   tri = tristring_from_proxy (proxy);
00475   
00476   list = g_hash_table_lookup (manager->proxy_lists, tri);
00477 
00478 #ifndef G_DISABLE_CHECKS
00479   if (list == NULL)
00480     {
00481       g_warning ("Trying to unregister a proxy but it isn't registered");
00482       return;
00483     }
00484 #endif
00485 
00486   g_assert (g_slist_find (list->proxies, proxy) != NULL);
00487   
00488   list->proxies = g_slist_remove (list->proxies, proxy);
00489 
00490   g_assert (g_slist_find (list->proxies, proxy) == NULL);
00491 
00492   if (list->proxies == NULL)
00493     {
00494       g_hash_table_remove (manager->proxy_lists,
00495                            tri);
00496       list = NULL;
00497     }
00498   
00499   if (g_hash_table_size (manager->proxy_lists) == 0)
00500     {
00501       g_hash_table_destroy (manager->proxy_lists);
00502       manager->proxy_lists = NULL;
00503     }
00504 
00505   g_free (tri);
00506       
00507   UNLOCK_MANAGER (manager);
00508 }
00509 
00510 static void
00511 list_proxies_foreach (gpointer key,
00512                       gpointer value,
00513                       gpointer user_data)
00514 {
00515   DBusGProxyList *list;
00516   GSList **ret;
00517   GSList *tmp;
00518   
00519   list = value;
00520   ret = user_data;
00521 
00522   tmp = list->proxies;
00523   while (tmp != NULL)
00524     {
00525       DBusGProxy *proxy = DBUS_GPROXY (tmp->data);
00526 
00527       g_object_ref (proxy);
00528       *ret = g_slist_prepend (*ret, proxy);
00529       
00530       tmp = tmp->next;
00531     }
00532 }
00533 
00534 static GSList*
00535 dbus_gproxy_manager_list_all (DBusGProxyManager *manager)
00536 {
00537   GSList *ret;
00538 
00539   ret = NULL;
00540 
00541   if (manager->proxy_lists)
00542     {
00543       g_hash_table_foreach (manager->proxy_lists,
00544                             list_proxies_foreach,
00545                             &ret);
00546     }
00547 
00548   return ret;
00549 }
00550 
00551 static DBusHandlerResult
00552 dbus_gproxy_manager_filter (DBusConnection    *connection,
00553                             DBusMessage       *message,
00554                             void              *user_data)
00555 {
00556   DBusGProxyManager *manager;
00557   
00558   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
00559     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00560 
00561   manager = user_data;
00562 
00563   dbus_gproxy_manager_ref (manager);
00564   
00565   LOCK_MANAGER (manager);
00566   
00567   if (dbus_message_is_signal (message,
00568                               DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
00569                               "Disconnected"))
00570     {
00571       /* Destroy all the proxies, quite possibly resulting in unreferencing
00572        * the proxy manager and the connection as well.
00573        */
00574       GSList *all;
00575       GSList *tmp;
00576 
00577       all = dbus_gproxy_manager_list_all (manager);
00578 
00579       tmp = all;
00580       while (tmp != NULL)
00581         {
00582           DBusGProxy *proxy;
00583 
00584           proxy = DBUS_GPROXY (tmp->data);
00585 
00586           UNLOCK_MANAGER (manager);
00587           dbus_gproxy_destroy (proxy);
00588           g_object_unref (G_OBJECT (proxy));
00589           LOCK_MANAGER (manager);
00590           
00591           tmp = tmp->next;
00592         }
00593 
00594       g_slist_free (all);
00595 
00596 #ifndef G_DISABLE_CHECKS
00597       if (manager->proxy_lists != NULL)
00598         g_warning ("Disconnection emitted \"destroy\" on all DBusGProxy, but somehow new proxies were created in response to one of those destroy signals. This will cause a memory leak.");
00599 #endif
00600     }
00601   else
00602     {
00603       char *tri;
00604       DBusGProxyList *list;
00605       
00606       tri = tristring_from_message (message);
00607 
00608       if (manager->proxy_lists)
00609         list = g_hash_table_lookup (manager->proxy_lists, tri);
00610       else
00611         list = NULL;
00612 
00613 #if 0
00614       g_print ("proxy got %s,%s,%s = list %p\n",
00615                tri,
00616                tri + strlen (tri) + 1,
00617                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
00618                list);
00619 #endif
00620       
00621       g_free (tri);
00622 
00623       /* Emit the signal */
00624       
00625       if (list != NULL)
00626         {
00627           GSList *tmp;
00628           GSList *copy;
00629 
00630           copy = g_slist_copy (list->proxies);
00631           g_slist_foreach (copy, (GFunc) g_object_ref, NULL);
00632           
00633           tmp = copy;
00634           while (tmp != NULL)
00635             {
00636               DBusGProxy *proxy;
00637 
00638               proxy = DBUS_GPROXY (tmp->data);
00639 
00640               UNLOCK_MANAGER (manager);
00641               dbus_gproxy_emit_received (proxy, message);
00642               g_object_unref (G_OBJECT (proxy));
00643               LOCK_MANAGER (manager);
00644               
00645               tmp = tmp->next;
00646             }
00647 
00648           g_slist_free (copy);
00649         }
00650     }
00651 
00652   UNLOCK_MANAGER (manager);
00653   dbus_gproxy_manager_unref (manager);
00654   
00655   /* "Handling" signals doesn't make sense, they are for everyone
00656    * who cares
00657    */
00658   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00659 }
00660 
00661 
00662 
00663 /*      ---------- DBusGProxy --------------   */
00664 
00665 
00666 
00667 enum
00668 {
00669   DESTROY,
00670   RECEIVED,
00671   LAST_SIGNAL
00672 };
00673 
00674 static void *parent_class;
00675 static guint signals[LAST_SIGNAL] = { 0 };
00676 
00677 static void
00678 dbus_gproxy_init (DBusGProxy *proxy)
00679 {
00680   /* Nothing */
00681 }
00682 
00683 static void
00684 dbus_gproxy_class_init (DBusGProxyClass *klass)
00685 {
00686   GObjectClass *object_class = G_OBJECT_CLASS (klass);
00687   
00688   parent_class = g_type_class_peek_parent (klass);
00689   
00690   object_class->finalize = dbus_gproxy_finalize;
00691   object_class->dispose = dbus_gproxy_dispose;
00692   
00693   signals[DESTROY] =
00694     g_signal_new ("destroy",
00695                   G_OBJECT_CLASS_TYPE (object_class),
00696                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
00697                   0,
00698                   NULL, NULL,
00699                   g_cclosure_marshal_VOID__VOID,
00700                   G_TYPE_NONE, 0);
00701   
00702   signals[RECEIVED] =
00703     g_signal_new ("received",
00704                   G_OBJECT_CLASS_TYPE (object_class),
00705                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
00706                   0,
00707                   NULL, NULL,
00708                   g_cclosure_marshal_VOID__BOXED,
00709                   G_TYPE_NONE, 1,
00710                   DBUS_TYPE_MESSAGE);
00711 }
00712 
00713 
00714 static void
00715 dbus_gproxy_dispose (GObject *object)
00716 {
00717   DBusGProxy *proxy;
00718 
00719   proxy = DBUS_GPROXY (object);
00720 
00721   g_signal_emit (object, signals[DESTROY], 0);
00722   
00723   G_OBJECT_CLASS (parent_class)->dispose (object);
00724 }
00725 
00726 static void
00727 dbus_gproxy_finalize (GObject *object)
00728 {
00729   DBusGProxy *proxy;
00730 
00731   proxy = DBUS_GPROXY (object);
00732 
00733   if (proxy->manager)
00734     {
00735       dbus_gproxy_manager_unregister (proxy->manager, proxy);
00736       dbus_gproxy_manager_unref (proxy->manager);
00737     }
00738   
00739   g_free (proxy->service);
00740   g_free (proxy->path);
00741   g_free (proxy->interface);
00742   
00743   G_OBJECT_CLASS (parent_class)->finalize (object);
00744 }
00745 
00746 static void
00747 dbus_gproxy_destroy (DBusGProxy *proxy)
00748 {
00749   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
00750    * from GtkObject?
00751    */
00752   g_object_run_dispose (G_OBJECT (proxy));
00753 }
00754 
00755 static char*
00756 create_signal_detail (const char *interface,
00757                       const char *signal)
00758 {
00759   GString *str;
00760 
00761   str = g_string_new (interface);
00762 
00763   g_string_append (str, ".");
00764 
00765   g_string_append (str, signal);
00766 
00767   return g_string_free (str, FALSE);
00768 }
00769 
00770 static void
00771 dbus_gproxy_emit_received (DBusGProxy  *proxy,
00772                            DBusMessage *message)
00773 {
00774   const char *interface;
00775   const char *signal;
00776   char *detail;
00777   GQuark q;
00778   
00779   interface = dbus_message_get_interface (message);
00780   signal = dbus_message_get_member (message);
00781 
00782   g_assert (interface != NULL);
00783   g_assert (signal != NULL);
00784 
00785   detail = create_signal_detail (interface, signal);
00786 
00787   /* If the quark isn't preexisting, there's no way there
00788    * are any handlers connected. We don't want to create
00789    * extra quarks for every possible signal.
00790    */
00791   q = g_quark_try_string (detail);
00792 
00793   if (q != 0)
00794     g_signal_emit (G_OBJECT (proxy),
00795                    signals[RECEIVED],
00796                    q,
00797                    message);
00798 
00799   g_free (detail);
00800 }
00801 
00813 GType
00814 dbus_gproxy_get_type (void)
00815 {
00816   static GType object_type = 0;
00817 
00818   if (!object_type)
00819     {
00820       static const GTypeInfo object_info =
00821         {
00822           sizeof (DBusGProxyClass),
00823           (GBaseInitFunc) NULL,
00824           (GBaseFinalizeFunc) NULL,
00825           (GClassInitFunc) dbus_gproxy_class_init,
00826           NULL,           /* class_finalize */
00827           NULL,           /* class_data */
00828           sizeof (DBusGProxy),
00829           0,              /* n_preallocs */
00830           (GInstanceInitFunc) dbus_gproxy_init,
00831         };
00832       
00833       object_type = g_type_register_static (G_TYPE_OBJECT,
00834                                             "DBusGProxy",
00835                                             &object_info, 0);
00836     }
00837   
00838   return object_type;
00839 }
00840 
00841 static DBusGProxy*
00842 dbus_gproxy_new (DBusConnection *connection,
00843                  const char     *service_name,
00844                  const char     *path_name,
00845                  const char     *interface_name)
00846 {
00847   DBusGProxy *proxy;
00848 
00849   g_assert (connection != NULL);
00850   
00851   proxy = g_object_new (DBUS_TYPE_GPROXY, NULL);
00852 
00853   /* These should all be construct-only mandatory properties,
00854    * for now we just don't let people use g_object_new().
00855    */
00856   
00857   proxy->manager = dbus_gproxy_manager_get (connection);
00858   
00859   proxy->service = g_strdup (service_name);
00860   proxy->path = g_strdup (path_name);
00861   proxy->interface = g_strdup (interface_name);
00862 
00863   dbus_gproxy_manager_register (proxy->manager, proxy);
00864   
00865   return proxy;
00866 }
00867 
00890 DBusGProxy*
00891 dbus_gproxy_new_for_service (DBusConnection *connection,
00892                              const char     *service_name,
00893                              const char     *path_name,
00894                              const char     *interface_name)
00895 {
00896   DBusGProxy *proxy;
00897 
00898   g_return_val_if_fail (connection != NULL, NULL);
00899   g_return_val_if_fail (service_name != NULL, NULL);
00900   g_return_val_if_fail (path_name != NULL, NULL);
00901   g_return_val_if_fail (interface_name != NULL, NULL);
00902   
00903   proxy = dbus_gproxy_new (connection, service_name,
00904                            path_name, interface_name);
00905 
00906   return proxy;
00907 }
00908 
00932 DBusGProxy*
00933 dbus_gproxy_new_for_service_owner (DBusConnection           *connection,
00934                                    const char               *service_name,
00935                                    const char               *path_name,
00936                                    const char               *interface_name,
00937                                    GError                  **error)
00938 {
00939   DBusGProxy *proxy;
00940 
00941   DBusMessage *request, *reply;
00942   DBusError derror;
00943   char *base_service_name;
00944 
00945   g_return_val_if_fail (connection != NULL, NULL);
00946   g_return_val_if_fail (service_name != NULL, NULL);
00947   g_return_val_if_fail (path_name != NULL, NULL);
00948   g_return_val_if_fail (interface_name != NULL, NULL);
00949 
00950   dbus_error_init (&derror);
00951 
00952   proxy = NULL;
00953   base_service_name = NULL;
00954   reply = NULL;
00955 
00956   request = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
00957                                           DBUS_PATH_ORG_FREEDESKTOP_DBUS,
00958                                           DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
00959                                           "GetServiceOwner");
00960   if (request == NULL)
00961     g_error ("Out of memory");
00962   
00963   if (! dbus_message_append_args (request, 
00964                                   DBUS_TYPE_STRING, service_name, 
00965                                   DBUS_TYPE_INVALID))
00966     g_error ("Out of memory");
00967 
00968   reply = dbus_connection_send_with_reply_and_block (connection, request,
00969                                                      2000, &derror);
00970   if (reply == NULL)
00971     goto error;
00972 
00973   if (dbus_set_error_from_message (&derror, reply))
00974     goto error;
00975 
00976   if (! dbus_message_get_args (reply, &derror, 
00977                                DBUS_TYPE_STRING, &base_service_name, 
00978                                DBUS_TYPE_INVALID))
00979     goto error;
00980       
00981 
00982   proxy = dbus_gproxy_new (connection, base_service_name,
00983                            path_name, interface_name);
00984 
00985   goto out;
00986 
00987  error:
00988   g_assert (dbus_error_is_set (&derror));
00989   dbus_set_g_error (error, &derror);
00990   dbus_error_free (&derror);
00991 
00992  out:
00993   if (request)
00994     dbus_message_unref (request);
00995   if (reply)
00996     dbus_message_unref (reply);
00997   dbus_free (base_service_name);
00998 
00999   return proxy;
01000 }
01001 
01016 DBusGProxy*
01017 dbus_gproxy_new_for_peer (DBusConnection           *connection,
01018                           const char               *path_name,
01019                           const char               *interface_name)
01020 {
01021   DBusGProxy *proxy;
01022   
01023   g_return_val_if_fail (connection != NULL, NULL);
01024   g_return_val_if_fail (path_name != NULL, NULL);
01025   g_return_val_if_fail (interface_name != NULL, NULL);
01026 
01027   proxy = dbus_gproxy_new (connection, NULL,
01028                            path_name, interface_name);
01029 
01030   return proxy;
01031 }
01032 
01052 DBusPendingCall*
01053 dbus_gproxy_begin_call (DBusGProxy *proxy,
01054                         const char *method,
01055                         int         first_arg_type,
01056                         ...)
01057 {
01058   DBusPendingCall *pending;
01059   DBusMessage *message;
01060   va_list args;
01061   
01062   g_return_val_if_fail (DBUS_IS_GPROXY (proxy), NULL);
01063 
01064   message = dbus_message_new_method_call (proxy->service,
01065                                           proxy->path,
01066                                           proxy->interface,
01067                                           method);
01068   if (message == NULL)
01069     goto oom;
01070 
01071   va_start (args, first_arg_type);
01072   if (!dbus_message_append_args_valist (message, first_arg_type,
01073                                         args))
01074     goto oom;
01075   va_end (args);
01076 
01077   if (!dbus_connection_send_with_reply (proxy->manager->connection,
01078                                         message,
01079                                         &pending,
01080                                         -1))
01081     goto oom;
01082 
01083   return pending;
01084 
01085  oom:
01086   /* FIXME we should create a pending call that's
01087    * immediately completed with an error status without
01088    * ever going on the wire.
01089    */
01090   
01091   g_error ("Out of memory");
01092   return NULL;
01093 }
01094 
01120 gboolean
01121 dbus_gproxy_end_call (DBusGProxy          *proxy,
01122                       DBusPendingCall     *pending,
01123                       GError             **error,
01124                       int                  first_arg_type,
01125                       ...)
01126 {
01127   DBusMessage *message;
01128   va_list args;
01129   DBusError derror;
01130   
01131   g_return_val_if_fail (DBUS_IS_GPROXY (proxy), FALSE);
01132   g_return_val_if_fail (pending != NULL, FALSE);
01133 
01134   dbus_pending_call_block (pending);
01135   message = dbus_pending_call_get_reply (pending);
01136 
01137   g_assert (message != NULL);
01138 
01139   dbus_error_init (&derror);
01140 
01141   switch (dbus_message_get_type (message))
01142     {
01143     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
01144       va_start (args, first_arg_type);
01145       if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args))
01146         {
01147           va_end (args);
01148           goto error;
01149         }
01150       va_end (args);
01151 
01152       return TRUE;
01153       
01154     case DBUS_MESSAGE_TYPE_ERROR:
01155       dbus_set_error_from_message (&derror, message);
01156       goto error;
01157 
01158     default:
01159       dbus_set_error (&derror, DBUS_ERROR_FAILED,
01160                       "Reply was neither a method return nor an exception");
01161       goto error;
01162     }
01163 
01164  error:
01165   dbus_set_g_error (error, &derror);
01166   dbus_error_free (&derror);
01167   return FALSE;
01168 }
01169 
01181 void
01182 dbus_gproxy_call_no_reply (DBusGProxy               *proxy,
01183                            const char               *method,
01184                            int                       first_arg_type,
01185                            ...)
01186 {
01187   DBusMessage *message;
01188   va_list args;
01189   
01190   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01191 
01192   message = dbus_message_new_method_call (proxy->service,
01193                                           proxy->path,
01194                                           proxy->interface,
01195                                           method);
01196   if (message == NULL)
01197     goto oom;
01198 
01199   dbus_message_set_no_reply (message, TRUE);
01200   
01201   va_start (args, first_arg_type);
01202   if (!dbus_message_append_args_valist (message, first_arg_type,
01203                                         args))
01204     goto oom;
01205   va_end (args);
01206 
01207   if (!dbus_connection_send (proxy->manager->connection,
01208                              message,
01209                              NULL))
01210     goto oom;
01211 
01212   return;
01213   
01214  oom:
01215   g_error ("Out of memory");
01216 }
01217 
01236 void
01237 dbus_gproxy_send (DBusGProxy          *proxy,
01238                   DBusMessage         *message,
01239                   dbus_uint32_t       *client_serial)
01240 {
01241   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01242   
01243   if (proxy->service)
01244     {
01245       if (!dbus_message_set_destination (message, proxy->service))
01246         g_error ("Out of memory");
01247     }
01248   if (proxy->path)
01249     {
01250       if (!dbus_message_set_path (message, proxy->path))
01251         g_error ("Out of memory");
01252     }
01253   if (proxy->interface)
01254     {
01255       if (!dbus_message_set_interface (message, proxy->interface))
01256         g_error ("Out of memory");
01257     }
01258   
01259   if (!dbus_connection_send (proxy->manager->connection, message, client_serial))
01260     g_error ("Out of memory\n");
01261 }
01262 
01274 void
01275 dbus_gproxy_connect_signal (DBusGProxy             *proxy,
01276                             const char             *signal_name,
01277                             DBusGProxySignalHandler handler,
01278                             void                   *data,
01279                             GClosureNotify          free_data_func)
01280 {
01281   GClosure *closure;
01282   char *detail;
01283 
01284   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01285   g_return_if_fail (signal_name != NULL);
01286   g_return_if_fail (handler != NULL);
01287   
01288   detail = create_signal_detail (proxy->interface, signal_name);
01289   
01290   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
01291   g_signal_connect_closure_by_id (G_OBJECT (proxy),
01292                                   signals[RECEIVED],
01293                                   g_quark_from_string (detail),
01294                                   closure, FALSE);
01295 
01296   g_free (detail);
01297 }
01298 
01308 void
01309 dbus_gproxy_disconnect_signal (DBusGProxy             *proxy,
01310                                const char             *signal_name,
01311                                DBusGProxySignalHandler handler,
01312                                void                   *data)
01313 {
01314   char *detail;
01315   GQuark q;
01316   
01317   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01318   g_return_if_fail (signal_name != NULL);
01319   g_return_if_fail (handler != NULL);
01320 
01321   detail = create_signal_detail (proxy->interface, signal_name);
01322   q = g_quark_try_string (detail);
01323   g_free (detail);
01324 
01325 #ifndef G_DISABLE_CHECKS
01326   if (q == 0)
01327     {
01328       g_warning ("%s: No signal handlers for %s found on this DBusGProxy",
01329                  G_GNUC_FUNCTION, signal_name);
01330       return;
01331     }
01332 #endif
01333 
01334   g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
01335                                         G_SIGNAL_MATCH_DETAIL |
01336                                         G_SIGNAL_MATCH_FUNC   |
01337                                         G_SIGNAL_MATCH_DATA,
01338                                         signals[RECEIVED],
01339                                         q,
01340                                         NULL,
01341                                         G_CALLBACK (handler), data);
01342 }
01343 
01346 #ifdef DBUS_BUILD_TESTS
01347 
01353 dbus_bool_t
01354 _dbus_gproxy_test (void)
01355 {
01356   
01357   
01358   return TRUE;
01359 }
01360 
01361 #endif /* DBUS_BUILD_TESTS */

Generated on Wed Jun 9 05:01:25 2004 for D-BUS by doxygen1.2.15