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

Generated on Wed Mar 30 21:15:20 2005 for D-BUS by  doxygen 1.4.1