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 
00032 typedef struct DBusGProxyManager DBusGProxyManager;
00033 
00037 struct DBusGProxy
00038 {
00039   GObject parent;             
00041   DBusGProxyManager *manager; 
00042   char *service;              
00043   char *path;                 
00044   char *interface;            
00045 };
00046 
00050 struct DBusGProxyClass
00051 {
00052   GObjectClass parent_class;  
00053 };
00054 
00055 static void dbus_gproxy_init          (DBusGProxy      *proxy);
00056 static void dbus_gproxy_class_init    (DBusGProxyClass *klass);
00057 static void dbus_gproxy_finalize      (GObject         *object);
00058 static void dbus_gproxy_dispose       (GObject         *object);
00059 static void dbus_gproxy_destroy       (DBusGProxy      *proxy);
00060 static void dbus_gproxy_emit_received (DBusGProxy      *proxy,
00061                                        DBusMessage     *message);
00062 
00063 
00068 typedef struct
00069 {
00070   GSList *proxies;
00071 
00072   char name[4]; 
00077 } DBusGProxyList;
00078 
00084 struct DBusGProxyManager
00085 {
00086   GStaticMutex lock; 
00087   int refcount;      
00088   DBusConnection *connection; 
00090   GHashTable *proxy_lists; 
00094 };
00095 
00096 static DBusGProxyManager *dbus_gproxy_manager_ref    (DBusGProxyManager *manager);
00097 static DBusHandlerResult dbus_gproxy_manager_filter (DBusConnection    *connection,
00098                                                      DBusMessage       *message,
00099                                                      void              *user_data);
00100 
00102 #define LOCK_MANAGER(mgr)   (g_static_mutex_lock (&(mgr)->lock))
00103 
00104 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
00105 
00106 static int gproxy_manager_slot = -1;
00107 
00108 /* Lock controlling get/set manager as data on each connection */
00109 static GStaticMutex connection_gproxy_lock = G_STATIC_MUTEX_INIT;
00110 
00111 static DBusGProxyManager*
00112 dbus_gproxy_manager_get (DBusConnection *connection)
00113 {
00114   DBusGProxyManager *manager;
00115 
00116   dbus_connection_allocate_data_slot (&gproxy_manager_slot);
00117   if (gproxy_manager_slot < 0)
00118     g_error ("out of memory");
00119   
00120   g_static_mutex_lock (&connection_gproxy_lock);
00121   
00122   manager = dbus_connection_get_data (connection, gproxy_manager_slot);
00123   if (manager != NULL)
00124     {
00125       dbus_connection_free_data_slot (&gproxy_manager_slot);
00126       dbus_gproxy_manager_ref (manager);
00127       g_static_mutex_unlock (&connection_gproxy_lock);
00128       return manager;
00129     }
00130   
00131   manager = g_new0 (DBusGProxyManager, 1);
00132 
00133   manager->refcount = 1;
00134   manager->connection = connection;
00135   
00136   g_static_mutex_init (&manager->lock);
00137 
00138   /* Proxy managers keep the connection alive, which means that
00139    * DBusGProxy indirectly does. To free a connection you have to free
00140    * all the proxies referring to it.
00141    */
00142   dbus_connection_ref (manager->connection);
00143 
00144   dbus_connection_set_data (connection, gproxy_manager_slot,
00145                             manager, NULL);
00146 
00147   dbus_connection_add_filter (connection, dbus_gproxy_manager_filter,
00148                               manager, NULL);
00149   
00150   g_static_mutex_unlock (&connection_gproxy_lock);
00151   
00152   return manager;
00153 }
00154 
00155 static DBusGProxyManager * 
00156 dbus_gproxy_manager_ref (DBusGProxyManager *manager)
00157 {
00158   g_assert (manager != NULL);
00159   g_assert (manager->refcount > 0);
00160 
00161   LOCK_MANAGER (manager);
00162   
00163   manager->refcount += 1;
00164 
00165   UNLOCK_MANAGER (manager);
00166 
00167   return manager;
00168 }
00169 
00170 static void
00171 dbus_gproxy_manager_unref (DBusGProxyManager *manager)
00172 {
00173   g_assert (manager != NULL);
00174   g_assert (manager->refcount > 0);
00175 
00176   LOCK_MANAGER (manager);
00177   manager->refcount -= 1;
00178   if (manager->refcount == 0)
00179     {
00180       UNLOCK_MANAGER (manager);
00181 
00182       if (manager->proxy_lists)
00183         {
00184           /* can't have any proxies left since they hold
00185            * a reference to the proxy manager.
00186            */
00187           g_assert (g_hash_table_size (manager->proxy_lists) == 0);
00188           
00189           g_hash_table_destroy (manager->proxy_lists);
00190           manager->proxy_lists = NULL;
00191         }
00192       
00193       g_static_mutex_free (&manager->lock);
00194 
00195       g_static_mutex_lock (&connection_gproxy_lock);
00196 
00197       dbus_connection_remove_filter (manager->connection, dbus_gproxy_manager_filter,
00198                                      manager);
00199       
00200       dbus_connection_set_data (manager->connection,
00201                                 gproxy_manager_slot,
00202                                 NULL, NULL);
00203 
00204       g_static_mutex_unlock (&connection_gproxy_lock);
00205       
00206       dbus_connection_unref (manager->connection);
00207       g_free (manager);
00208 
00209       dbus_connection_free_data_slot (&gproxy_manager_slot);
00210     }
00211   else
00212     {
00213       UNLOCK_MANAGER (manager);
00214     }
00215 }
00216 
00217 static guint
00218 tristring_hash (gconstpointer key)
00219 {
00220   const char *p = key;
00221   guint h = *p;
00222 
00223   if (h)
00224     {
00225       for (p += 1; *p != '\0'; p++)
00226         h = (h << 5) - h + *p;
00227     }
00228 
00229   /* skip nul and do the next substring */
00230   for (p += 1; *p != '\0'; p++)
00231     h = (h << 5) - h + *p;
00232 
00233   /* skip nul again and another substring */
00234   for (p += 1; *p != '\0'; p++)
00235     h = (h << 5) - h + *p;
00236   
00237   return h;
00238 }
00239 
00240 static gboolean
00241 strequal_len (const char *a,
00242               const char *b,
00243               size_t     *lenp)
00244 {
00245   size_t a_len;
00246   size_t b_len;
00247 
00248   a_len = strlen (a);
00249   b_len = strlen (b);
00250 
00251   if (a_len != b_len)
00252     return FALSE;
00253 
00254   if (memcmp (a, b, a_len) != 0)
00255     return FALSE;
00256   
00257   *lenp = a_len;
00258 
00259   return TRUE;
00260 }
00261 
00262 static gboolean
00263 tristring_equal (gconstpointer  a,
00264                  gconstpointer  b)
00265 {
00266   const char *ap = a;
00267   const char *bp = b;
00268   size_t len;
00269 
00270   if (!strequal_len (ap, bp, &len))
00271     return FALSE;
00272 
00273   ap += len + 1;
00274   bp += len + 1;
00275 
00276   if (!strequal_len (ap, bp, &len))
00277     return FALSE;
00278 
00279   ap += len + 1;
00280   bp += len + 1;
00281 
00282   if (strcmp (ap, bp) != 0)
00283     return FALSE;
00284   
00285   return TRUE;
00286 }
00287 
00288 static char*
00289 tristring_alloc_from_strings (size_t      padding_before,
00290                               const char *service,
00291                               const char *path,
00292                               const char *interface)
00293 {
00294   size_t service_len, iface_len, path_len, len;
00295   char *tri;
00296   
00297   if (service)
00298     service_len = strlen (service);
00299   else
00300     service_len = 0;
00301 
00302   path_len = strlen (path);
00303   
00304   iface_len = strlen (interface);
00305 
00306   tri = g_malloc (padding_before + service_len + path_len + iface_len + 3);
00307 
00308   len = padding_before;
00309   
00310   if (service)
00311     memcpy (&tri[len], service, service_len);
00312 
00313   len += service_len;
00314   tri[len] = '\0';
00315   len += 1;
00316 
00317   g_assert (len == (padding_before + service_len + 1));
00318   
00319   memcpy (&tri[len], path, path_len);
00320   len += path_len;
00321   tri[len] = '\0';
00322   len += 1;
00323 
00324   g_assert (len == (padding_before + service_len + path_len + 2));
00325   
00326   memcpy (&tri[len], interface, iface_len);
00327   len += iface_len;
00328   tri[len] = '\0';
00329   len += 1;
00330 
00331   g_assert (len == (padding_before + service_len + path_len + iface_len + 3));
00332 
00333   return tri;
00334 }
00335 
00336 static char*
00337 tristring_from_proxy (DBusGProxy *proxy)
00338 {
00339   return tristring_alloc_from_strings (0,
00340                                        proxy->service,
00341                                        proxy->path,
00342                                        proxy->interface);
00343 }
00344 
00345 static char*
00346 tristring_from_message (DBusMessage *message)
00347 {
00348   return tristring_alloc_from_strings (0,
00349                                        dbus_message_get_sender (message),
00350                                        dbus_message_get_path (message),
00351                                        dbus_message_get_interface (message));
00352 }
00353 
00354 static DBusGProxyList*
00355 gproxy_list_new (DBusGProxy *first_proxy)
00356 {
00357   DBusGProxyList *list;
00358   
00359   list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
00360                                                first_proxy->service,
00361                                                first_proxy->path,
00362                                                first_proxy->interface);
00363   list->proxies = NULL;
00364 
00365   return list;
00366 }
00367 
00368 static void
00369 gproxy_list_free (DBusGProxyList *list)
00370 {
00371   /* we don't hold a reference to the proxies in the list,
00372    * as they ref the GProxyManager
00373    */
00374   g_slist_free (list->proxies);  
00375 
00376   g_free (list);
00377 }
00378 
00379 static char*
00380 gproxy_get_match_rule (DBusGProxy *proxy)
00381 {
00382   /* FIXME Escaping is required here */
00383   
00384   if (proxy->service)
00385     return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
00386                             proxy->service, proxy->path, proxy->interface);
00387   else
00388     return g_strdup_printf ("type='signal',path='%s',interface='%s'",
00389                             proxy->path, proxy->interface);
00390 }
00391 
00392 static void
00393 dbus_gproxy_manager_register (DBusGProxyManager *manager,
00394                               DBusGProxy        *proxy)
00395 {
00396   DBusGProxyList *list;
00397 
00398   LOCK_MANAGER (manager);
00399 
00400   if (manager->proxy_lists == NULL)
00401     {
00402       list = NULL;
00403       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
00404                                                     tristring_equal,
00405                                                     NULL,
00406                                                     (GFreeFunc) gproxy_list_free);
00407     }
00408   else
00409     {
00410       char *tri;
00411 
00412       tri = tristring_from_proxy (proxy);
00413       
00414       list = g_hash_table_lookup (manager->proxy_lists, tri);
00415 
00416       g_free (tri);
00417     }
00418       
00419   if (list == NULL)
00420     {
00421       list = gproxy_list_new (proxy);
00422       
00423       g_hash_table_replace (manager->proxy_lists,
00424                             list->name, list);
00425     }
00426 
00427   if (list->proxies == NULL)
00428     {
00429       /* We have to add the match rule to the server,
00430        * but FIXME only if the server is a message bus,
00431        * not if it's a peer.
00432        */
00433       char *rule;
00434 
00435       rule = gproxy_get_match_rule (proxy);
00436       
00437       /* We don't check for errors; it's not like anyone would handle them,
00438        * and we don't want a round trip here.
00439        */
00440       dbus_bus_add_match (manager->connection,
00441                           rule, NULL);
00442 
00443       g_free (rule);
00444     }
00445 
00446   g_assert (g_slist_find (list->proxies, proxy) == NULL);
00447   
00448   list->proxies = g_slist_prepend (list->proxies, proxy);
00449   
00450   UNLOCK_MANAGER (manager);
00451 }
00452 
00453 static void
00454 dbus_gproxy_manager_unregister (DBusGProxyManager *manager,
00455                                 DBusGProxy        *proxy)
00456 {
00457   DBusGProxyList *list;
00458   char *tri;
00459   
00460   LOCK_MANAGER (manager);
00461 
00462 #ifndef G_DISABLE_CHECKS
00463   if (manager->proxy_lists == NULL)
00464     {
00465       g_warning ("Trying to unregister a proxy but there aren't any registered");
00466       return;
00467     }
00468 #endif
00469 
00470   tri = tristring_from_proxy (proxy);
00471   
00472   list = g_hash_table_lookup (manager->proxy_lists, tri);
00473 
00474 #ifndef G_DISABLE_CHECKS
00475   if (list == NULL)
00476     {
00477       g_warning ("Trying to unregister a proxy but it isn't registered");
00478       return;
00479     }
00480 #endif
00481 
00482   g_assert (g_slist_find (list->proxies, proxy) != NULL);
00483   
00484   list->proxies = g_slist_remove (list->proxies, proxy);
00485 
00486   g_assert (g_slist_find (list->proxies, proxy) == NULL);
00487 
00488   if (list->proxies == NULL)
00489     {
00490       g_hash_table_remove (manager->proxy_lists,
00491                            tri);
00492       list = NULL;
00493     }
00494   
00495   if (g_hash_table_size (manager->proxy_lists) == 0)
00496     {
00497       g_hash_table_destroy (manager->proxy_lists);
00498       manager->proxy_lists = NULL;
00499     }
00500 
00501   g_free (tri);
00502       
00503   UNLOCK_MANAGER (manager);
00504 }
00505 
00506 static void
00507 list_proxies_foreach (gpointer key,
00508                       gpointer value,
00509                       gpointer user_data)
00510 {
00511   DBusGProxyList *list;
00512   GSList **ret;
00513   GSList *tmp;
00514   
00515   list = value;
00516   ret = user_data;
00517 
00518   tmp = list->proxies;
00519   while (tmp != NULL)
00520     {
00521       DBusGProxy *proxy = DBUS_GPROXY (tmp->data);
00522 
00523       g_object_ref (proxy);
00524       *ret = g_slist_prepend (*ret, proxy);
00525       
00526       tmp = tmp->next;
00527     }
00528 }
00529 
00530 static GSList*
00531 dbus_gproxy_manager_list_all (DBusGProxyManager *manager)
00532 {
00533   GSList *ret;
00534 
00535   ret = NULL;
00536 
00537   if (manager->proxy_lists)
00538     {
00539       g_hash_table_foreach (manager->proxy_lists,
00540                             list_proxies_foreach,
00541                             &ret);
00542     }
00543 
00544   return ret;
00545 }
00546 
00547 static DBusHandlerResult
00548 dbus_gproxy_manager_filter (DBusConnection    *connection,
00549                             DBusMessage       *message,
00550                             void              *user_data)
00551 {
00552   DBusGProxyManager *manager;
00553   
00554   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
00555     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00556 
00557   manager = user_data;
00558 
00559   dbus_gproxy_manager_ref (manager);
00560   
00561   LOCK_MANAGER (manager);
00562   
00563   if (dbus_message_is_signal (message,
00564                               DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
00565                               "Disconnected"))
00566     {
00567       /* Destroy all the proxies, quite possibly resulting in unreferencing
00568        * the proxy manager and the connection as well.
00569        */
00570       GSList *all;
00571       GSList *tmp;
00572 
00573       all = dbus_gproxy_manager_list_all (manager);
00574 
00575       tmp = all;
00576       while (tmp != NULL)
00577         {
00578           DBusGProxy *proxy;
00579 
00580           proxy = DBUS_GPROXY (tmp->data);
00581 
00582           UNLOCK_MANAGER (manager);
00583           dbus_gproxy_destroy (proxy);
00584           g_object_unref (G_OBJECT (proxy));
00585           LOCK_MANAGER (manager);
00586           
00587           tmp = tmp->next;
00588         }
00589 
00590       g_slist_free (all);
00591 
00592 #ifndef G_DISABLE_CHECKS
00593       if (manager->proxy_lists != NULL)
00594         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.");
00595 #endif
00596     }
00597   else
00598     {
00599       char *tri;
00600       DBusGProxyList *list;
00601       
00602       tri = tristring_from_message (message);
00603 
00604       if (manager->proxy_lists)
00605         list = g_hash_table_lookup (manager->proxy_lists, tri);
00606       else
00607         list = NULL;
00608 
00609 #if 0
00610       g_print ("proxy got %s,%s,%s = list %p\n",
00611                tri,
00612                tri + strlen (tri) + 1,
00613                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
00614                list);
00615 #endif
00616       
00617       g_free (tri);
00618 
00619       /* Emit the signal */
00620       
00621       if (list != NULL)
00622         {
00623           GSList *tmp;
00624           GSList *copy;
00625 
00626           copy = g_slist_copy (list->proxies);
00627           g_slist_foreach (copy, (GFunc) g_object_ref, NULL);
00628           
00629           tmp = copy;
00630           while (tmp != NULL)
00631             {
00632               DBusGProxy *proxy;
00633 
00634               proxy = DBUS_GPROXY (tmp->data);
00635 
00636               UNLOCK_MANAGER (manager);
00637               dbus_gproxy_emit_received (proxy, message);
00638               g_object_unref (G_OBJECT (proxy));
00639               LOCK_MANAGER (manager);
00640               
00641               tmp = tmp->next;
00642             }
00643 
00644           g_slist_free (copy);
00645         }
00646     }
00647 
00648   UNLOCK_MANAGER (manager);
00649   dbus_gproxy_manager_unref (manager);
00650   
00651   /* "Handling" signals doesn't make sense, they are for everyone
00652    * who cares
00653    */
00654   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00655 }
00656 
00657 
00658 
00659 /*      ---------- DBusGProxy --------------   */
00660 
00661 
00662 
00663 enum
00664 {
00665   DESTROY,
00666   RECEIVED,
00667   LAST_SIGNAL
00668 };
00669 
00670 static void *parent_class;
00671 static guint signals[LAST_SIGNAL] = { 0 };
00672 
00673 static void
00674 dbus_gproxy_init (DBusGProxy *proxy)
00675 {
00676   /* Nothing */
00677 }
00678 
00679 static void
00680 dbus_gproxy_class_init (DBusGProxyClass *klass)
00681 {
00682   GObjectClass *object_class = G_OBJECT_CLASS (klass);
00683   
00684   parent_class = g_type_class_peek_parent (klass);
00685   
00686   object_class->finalize = dbus_gproxy_finalize;
00687   object_class->dispose = dbus_gproxy_dispose;
00688   
00689   signals[DESTROY] =
00690     g_signal_new ("destroy",
00691                   G_OBJECT_CLASS_TYPE (object_class),
00692                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
00693                   0,
00694                   NULL, NULL,
00695                   g_cclosure_marshal_VOID__VOID,
00696                   G_TYPE_NONE, 0);
00697   
00698   signals[RECEIVED] =
00699     g_signal_new ("received",
00700                   G_OBJECT_CLASS_TYPE (object_class),
00701                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
00702                   0,
00703                   NULL, NULL,
00704                   g_cclosure_marshal_VOID__BOXED,
00705                   G_TYPE_NONE, 1,
00706                   DBUS_TYPE_MESSAGE);
00707 }
00708 
00709 
00710 static void
00711 dbus_gproxy_dispose (GObject *object)
00712 {
00713   DBusGProxy *proxy;
00714 
00715   proxy = DBUS_GPROXY (object);
00716 
00717   g_signal_emit (object, signals[DESTROY], 0);
00718   
00719   G_OBJECT_CLASS (parent_class)->dispose (object);
00720 }
00721 
00722 static void
00723 dbus_gproxy_finalize (GObject *object)
00724 {
00725   DBusGProxy *proxy;
00726 
00727   proxy = DBUS_GPROXY (object);
00728 
00729   if (proxy->manager)
00730     {
00731       dbus_gproxy_manager_unregister (proxy->manager, proxy);
00732       dbus_gproxy_manager_unref (proxy->manager);
00733     }
00734   
00735   g_free (proxy->service);
00736   g_free (proxy->path);
00737   g_free (proxy->interface);
00738   
00739   G_OBJECT_CLASS (parent_class)->finalize (object);
00740 }
00741 
00742 static void
00743 dbus_gproxy_destroy (DBusGProxy *proxy)
00744 {
00745   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
00746    * from GtkObject?
00747    */
00748   g_object_run_dispose (G_OBJECT (proxy));
00749 }
00750 
00751 static char*
00752 create_signal_detail (const char *interface,
00753                       const char *signal)
00754 {
00755   GString *str;
00756 
00757   str = g_string_new (interface);
00758 
00759   g_string_append (str, ".");
00760 
00761   g_string_append (str, signal);
00762 
00763   return g_string_free (str, FALSE);
00764 }
00765 
00766 static void
00767 dbus_gproxy_emit_received (DBusGProxy  *proxy,
00768                            DBusMessage *message)
00769 {
00770   const char *interface;
00771   const char *signal;
00772   char *detail;
00773   GQuark q;
00774   
00775   interface = dbus_message_get_interface (message);
00776   signal = dbus_message_get_member (message);
00777 
00778   g_assert (interface != NULL);
00779   g_assert (signal != NULL);
00780 
00781   detail = create_signal_detail (interface, signal);
00782 
00783   /* If the quark isn't preexisting, there's no way there
00784    * are any handlers connected. We don't want to create
00785    * extra quarks for every possible signal.
00786    */
00787   q = g_quark_try_string (detail);
00788 
00789   if (q != 0)
00790     g_signal_emit (G_OBJECT (proxy),
00791                    signals[RECEIVED],
00792                    q,
00793                    message);
00794 
00795   g_free (detail);
00796 }
00797 
00809 GType
00810 dbus_gproxy_get_type (void)
00811 {
00812   static GType object_type = 0;
00813 
00814   if (!object_type)
00815     {
00816       static const GTypeInfo object_info =
00817         {
00818           sizeof (DBusGProxyClass),
00819           (GBaseInitFunc) NULL,
00820           (GBaseFinalizeFunc) NULL,
00821           (GClassInitFunc) dbus_gproxy_class_init,
00822           NULL,           /* class_finalize */
00823           NULL,           /* class_data */
00824           sizeof (DBusGProxy),
00825           0,              /* n_preallocs */
00826           (GInstanceInitFunc) dbus_gproxy_init,
00827         };
00828       
00829       object_type = g_type_register_static (G_TYPE_OBJECT,
00830                                             "DBusGProxy",
00831                                             &object_info, 0);
00832     }
00833   
00834   return object_type;
00835 }
00836 
00837 static DBusGProxy*
00838 dbus_gproxy_new (DBusConnection *connection,
00839                  const char     *service_name,
00840                  const char     *path_name,
00841                  const char     *interface_name)
00842 {
00843   DBusGProxy *proxy;
00844 
00845   g_assert (connection != NULL);
00846   
00847   proxy = g_object_new (DBUS_TYPE_GPROXY, NULL);
00848 
00849   /* These should all be construct-only mandatory properties,
00850    * for now we just don't let people use g_object_new().
00851    */
00852   
00853   proxy->manager = dbus_gproxy_manager_get (connection);
00854   
00855   proxy->service = g_strdup (service_name);
00856   proxy->path = g_strdup (path_name);
00857   proxy->interface = g_strdup (interface_name);
00858 
00859   dbus_gproxy_manager_register (proxy->manager, proxy);
00860   
00861   return proxy;
00862 }
00863 
00886 DBusGProxy*
00887 dbus_gproxy_new_for_service (DBusConnection *connection,
00888                              const char     *service_name,
00889                              const char     *path_name,
00890                              const char     *interface_name)
00891 {
00892   DBusGProxy *proxy;
00893 
00894   g_return_val_if_fail (connection != NULL, NULL);
00895   g_return_val_if_fail (service_name != NULL, NULL);
00896   g_return_val_if_fail (path_name != NULL, NULL);
00897   g_return_val_if_fail (interface_name != NULL, NULL);
00898   
00899   proxy = dbus_gproxy_new (connection, service_name,
00900                            path_name, interface_name);
00901 
00902   return proxy;
00903 }
00904 
00928 DBusGProxy*
00929 dbus_gproxy_new_for_service_owner (DBusConnection           *connection,
00930                                    const char               *service_name,
00931                                    const char               *path_name,
00932                                    const char               *interface_name,
00933                                    GError                  **error)
00934 {
00935   g_return_val_if_fail (connection != NULL, NULL);
00936   g_return_val_if_fail (service_name != NULL, NULL);
00937   g_return_val_if_fail (path_name != NULL, NULL);
00938   g_return_val_if_fail (interface_name != NULL, NULL);
00939 
00940 
00941 }
00942 
00957 DBusGProxy*
00958 dbus_gproxy_new_for_peer (DBusConnection           *connection,
00959                           const char               *path_name,
00960                           const char               *interface_name)
00961 {
00962   DBusGProxy *proxy;
00963   
00964   g_return_val_if_fail (connection != NULL, NULL);
00965   g_return_val_if_fail (path_name != NULL, NULL);
00966   g_return_val_if_fail (interface_name != NULL, NULL);
00967 
00968   proxy = dbus_gproxy_new (connection, NULL,
00969                            path_name, interface_name);
00970 
00971   return proxy;
00972 }
00973 
00993 DBusPendingCall*
00994 dbus_gproxy_begin_call (DBusGProxy *proxy,
00995                         const char *method,
00996                         int         first_arg_type,
00997                         ...)
00998 {
00999   DBusPendingCall *pending;
01000   DBusMessage *message;
01001   va_list args;
01002   
01003   g_return_val_if_fail (DBUS_IS_GPROXY (proxy), NULL);
01004 
01005   message = dbus_message_new_method_call (proxy->service,
01006                                           proxy->path,
01007                                           proxy->interface,
01008                                           method);
01009   if (message == NULL)
01010     goto oom;
01011 
01012   va_start (args, first_arg_type);
01013   if (!dbus_message_append_args_valist (message, first_arg_type,
01014                                         args))
01015     goto oom;
01016   va_end (args);
01017 
01018   if (!dbus_connection_send_with_reply (proxy->manager->connection,
01019                                         message,
01020                                         &pending,
01021                                         -1))
01022     goto oom;
01023 
01024   return pending;
01025 
01026  oom:
01027   /* FIXME we should create a pending call that's
01028    * immediately completed with an error status without
01029    * ever going on the wire.
01030    */
01031   
01032   g_error ("Out of memory");
01033   return NULL;
01034 }
01035 
01061 gboolean
01062 dbus_gproxy_end_call (DBusGProxy          *proxy,
01063                       DBusPendingCall     *pending,
01064                       GError             **error,
01065                       int                  first_arg_type,
01066                       ...)
01067 {
01068   DBusMessage *message;
01069   va_list args;
01070   DBusError derror;
01071   
01072   g_return_val_if_fail (DBUS_IS_GPROXY (proxy), FALSE);
01073   g_return_val_if_fail (pending != NULL, FALSE);
01074 
01075   dbus_pending_call_block (pending);
01076   message = dbus_pending_call_get_reply (pending);
01077 
01078   g_assert (message != NULL);
01079 
01080   dbus_error_init (&derror);
01081 
01082   switch (dbus_message_get_type (message))
01083     {
01084     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
01085       va_start (args, first_arg_type);
01086       if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args))
01087         {
01088           va_end (args);
01089           goto error;
01090         }
01091       va_end (args);
01092 
01093       return TRUE;
01094       
01095     case DBUS_MESSAGE_TYPE_ERROR:
01096       dbus_set_error_from_message (&derror, message);
01097       goto error;
01098 
01099     default:
01100       dbus_set_error (&derror, DBUS_ERROR_FAILED,
01101                       "Reply was neither a method return nor an exception");
01102       goto error;
01103     }
01104 
01105  error:
01106   dbus_set_g_error (error, &derror);
01107   dbus_error_free (&derror);
01108   return FALSE;
01109 }
01110 
01122 void
01123 dbus_gproxy_call_no_reply (DBusGProxy               *proxy,
01124                            const char               *method,
01125                            int                       first_arg_type,
01126                            ...)
01127 {
01128   DBusMessage *message;
01129   va_list args;
01130   
01131   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01132 
01133   message = dbus_message_new_method_call (proxy->service,
01134                                           proxy->path,
01135                                           proxy->interface,
01136                                           method);
01137   if (message == NULL)
01138     goto oom;
01139 
01140   dbus_message_set_no_reply (message, TRUE);
01141   
01142   va_start (args, first_arg_type);
01143   if (!dbus_message_append_args_valist (message, first_arg_type,
01144                                         args))
01145     goto oom;
01146   va_end (args);
01147 
01148   if (!dbus_connection_send (proxy->manager->connection,
01149                              message,
01150                              NULL))
01151     goto oom;
01152 
01153   return;
01154   
01155  oom:
01156   g_error ("Out of memory");
01157 }
01158 
01177 void
01178 dbus_gproxy_send (DBusGProxy          *proxy,
01179                   DBusMessage         *message,
01180                   dbus_uint32_t       *client_serial)
01181 {
01182   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01183   
01184   if (proxy->service)
01185     {
01186       if (!dbus_message_set_destination (message, proxy->service))
01187         g_error ("Out of memory");
01188     }
01189   if (proxy->path)
01190     {
01191       if (!dbus_message_set_path (message, proxy->path))
01192         g_error ("Out of memory");
01193     }
01194   if (proxy->interface)
01195     {
01196       if (!dbus_message_set_interface (message, proxy->interface))
01197         g_error ("Out of memory");
01198     }
01199   
01200   if (!dbus_connection_send (proxy->manager->connection, message, client_serial))
01201     g_error ("Out of memory\n");
01202 }
01203 
01204 void
01205 dbus_gproxy_connect_signal (DBusGProxy             *proxy,
01206                             const char             *signal_name,
01207                             DBusGProxySignalHandler handler,
01208                             void                   *data,
01209                             GClosureNotify          free_data_func)
01210 {
01211   GClosure *closure;
01212   char *detail;
01213 
01214   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01215   g_return_if_fail (signal_name != NULL);
01216   g_return_if_fail (handler != NULL);
01217   
01218   detail = create_signal_detail (proxy->interface, signal_name);
01219   
01220   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
01221   g_signal_connect_closure_by_id (G_OBJECT (proxy),
01222                                   signals[RECEIVED],
01223                                   g_quark_from_string (detail),
01224                                   closure, FALSE);
01225 
01226   g_free (detail);
01227 }
01228 
01229 void
01230 dbus_gproxy_disconnect_signal (DBusGProxy             *proxy,
01231                                const char             *signal_name,
01232                                DBusGProxySignalHandler handler,
01233                                void                   *data)
01234 {
01235   char *detail;
01236   GQuark q;
01237   
01238   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01239   g_return_if_fail (signal_name != NULL);
01240   g_return_if_fail (handler != NULL);
01241 
01242   detail = create_signal_detail (proxy->interface, signal_name);
01243   q = g_quark_try_string (detail);
01244   g_free (detail);
01245 
01246 #ifndef G_DISABLE_CHECKS
01247   if (q == 0)
01248     {
01249       g_warning ("%s: No signal handlers for %s found on this DBusGProxy",
01250                  G_GNUC_FUNCTION, signal_name);
01251       return;
01252     }
01253 #endif
01254 
01255   g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
01256                                         G_SIGNAL_MATCH_DETAIL |
01257                                         G_SIGNAL_MATCH_FUNC   |
01258                                         G_SIGNAL_MATCH_DATA,
01259                                         signals[RECEIVED],
01260                                         q,
01261                                         NULL,
01262                                         G_CALLBACK (handler), data);
01263 }
01264 
01267 #ifdef DBUS_BUILD_TESTS
01268 
01274 dbus_bool_t
01275 _dbus_gproxy_test (void)
01276 {
01277   
01278   
01279   return TRUE;
01280 }
01281 
01282 #endif /* DBUS_BUILD_TESTS */

Generated on Sun Mar 21 03:52:04 2004 for D-BUS by doxygen 1.3.6-20040222