2003-08-14 22:49:13 +00:00
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gcall.c convenience routines for calling methods, etc.
*
* Copyright ( C ) 2003 Red Hat , Inc .
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
2003-09-17 03:52:07 +00:00
# include "dbus-glib.h"
2003-09-23 23:47:09 +00:00
# include <string.h>
2003-08-14 22:49:13 +00:00
/**
* @ addtogroup DBusGLibInternals
*
* @ {
*/
2003-09-23 23:47:09 +00:00
typedef struct DBusGProxyManager DBusGProxyManager ;
/**
* Internals of DBusGProxy
*/
struct DBusGProxy
{
GObject parent ; /**< Parent instance */
DBusGProxyManager * manager ; /**< Proxy manager */
char * service ; /**< Service messages go to or NULL */
char * path ; /**< Path messages go to or NULL */
char * interface ; /**< Interface messages go to or NULL */
} ;
2003-09-24 02:58:14 +00:00
/**
* Class struct for DBusGProxy
*/
2003-09-23 23:47:09 +00:00
struct DBusGProxyClass
{
GObjectClass parent_class ;
} ;
static void dbus_gproxy_init ( DBusGProxy * proxy ) ;
static void dbus_gproxy_class_init ( DBusGProxyClass * klass ) ;
static void dbus_gproxy_finalize ( GObject * object ) ;
2003-09-24 02:58:14 +00:00
static void dbus_gproxy_dispose ( GObject * object ) ;
static void dbus_gproxy_destroy ( DBusGProxy * proxy ) ;
2003-09-23 23:47:09 +00:00
static void dbus_gproxy_emit_received ( DBusGProxy * proxy ,
DBusMessage * message ) ;
/**
* A list of proxies with a given service + path + interface , used to route incoming
* signals .
*/
typedef struct
{
GSList * proxies ;
char name [ 4 ] ; /**< service (empty string for none), nul byte,
* path , nul byte ,
* interface , nul byte
*/
} DBusGProxyList ;
2003-09-22 03:11:12 +00:00
/**
* DBusGProxyManager ' s primary task is to route signals to the proxies
* those signals are emitted on . In order to do this it also has to
* track the owners of the services proxies are bound to .
*/
2003-09-23 23:47:09 +00:00
struct DBusGProxyManager
2003-09-22 03:11:12 +00:00
{
GStaticMutex lock ; /**< Thread lock */
int refcount ; /**< Reference count */
2003-09-22 23:50:52 +00:00
DBusConnection * connection ; /**< Connection we're associated with. */
2003-09-22 03:11:12 +00:00
2003-09-23 23:47:09 +00:00
GHashTable * proxy_lists ; /**< Hash used to route incoming signals
* and iterate over proxies
*/
} ;
static void dbus_gproxy_manager_ref ( DBusGProxyManager * manager ) ;
static DBusHandlerResult dbus_gproxy_manager_filter ( DBusConnection * connection ,
DBusMessage * message ,
void * user_data ) ;
2003-09-22 03:11:12 +00:00
/** Lock the DBusGProxyManager */
# define LOCK_MANAGER(mgr) (g_static_mutex_lock (&(mgr)->lock))
/** Unlock the DBusGProxyManager */
# define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
2003-09-22 23:50:52 +00:00
static int gproxy_manager_slot = - 1 ;
/* Lock controlling get/set manager as data on each connection */
static GStaticMutex connection_gproxy_lock = G_STATIC_MUTEX_INIT ;
2003-09-22 03:11:12 +00:00
static DBusGProxyManager *
2003-09-22 23:50:52 +00:00
dbus_gproxy_manager_get ( DBusConnection * connection )
2003-09-22 03:11:12 +00:00
{
DBusGProxyManager * manager ;
2003-09-22 23:50:52 +00:00
dbus_connection_allocate_data_slot ( & gproxy_manager_slot ) ;
if ( gproxy_manager_slot < 0 )
g_error ( " out of memory " ) ;
g_static_mutex_lock ( & connection_gproxy_lock ) ;
manager = dbus_connection_get_data ( connection , gproxy_manager_slot ) ;
if ( manager ! = NULL )
{
dbus_connection_free_data_slot ( & gproxy_manager_slot ) ;
dbus_gproxy_manager_ref ( manager ) ;
g_static_mutex_unlock ( & connection_gproxy_lock ) ;
return manager ;
}
2003-09-22 03:11:12 +00:00
manager = g_new0 ( DBusGProxyManager , 1 ) ;
manager - > refcount = 1 ;
2003-09-22 23:50:52 +00:00
manager - > connection = connection ;
2003-09-22 03:11:12 +00:00
g_static_mutex_init ( & manager - > lock ) ;
2003-09-22 23:50:52 +00:00
/* Proxy managers keep the connection alive, which means that
* DBusGProxy indirectly does . To free a connection you have to free
* all the proxies referring to it .
*/
dbus_connection_ref ( manager - > connection ) ;
dbus_connection_set_data ( connection , gproxy_manager_slot ,
manager , NULL ) ;
2003-09-23 23:47:09 +00:00
dbus_connection_add_filter ( connection , dbus_gproxy_manager_filter ,
manager , NULL ) ;
2003-09-22 23:50:52 +00:00
g_static_mutex_unlock ( & connection_gproxy_lock ) ;
2003-09-22 03:11:12 +00:00
return manager ;
}
static void
dbus_gproxy_manager_ref ( DBusGProxyManager * manager )
{
g_assert ( manager ! = NULL ) ;
g_assert ( manager - > refcount > 0 ) ;
LOCK_MANAGER ( manager ) ;
manager - > refcount + = 1 ;
UNLOCK_MANAGER ( manager ) ;
}
static void
dbus_gproxy_manager_unref ( DBusGProxyManager * manager )
{
g_assert ( manager ! = NULL ) ;
g_assert ( manager - > refcount > 0 ) ;
LOCK_MANAGER ( manager ) ;
manager - > refcount - = 1 ;
if ( manager - > refcount = = 0 )
{
UNLOCK_MANAGER ( manager ) ;
2003-09-23 23:47:09 +00:00
if ( manager - > proxy_lists )
{
2003-09-24 02:58:14 +00:00
/* can't have any proxies left since they hold
* a reference to the proxy manager .
*/
g_assert ( g_hash_table_size ( manager - > proxy_lists ) = = 0 ) ;
2003-09-23 23:47:09 +00:00
g_hash_table_destroy ( manager - > proxy_lists ) ;
manager - > proxy_lists = NULL ;
}
2003-09-22 03:11:12 +00:00
g_static_mutex_free ( & manager - > lock ) ;
2003-09-22 23:50:52 +00:00
g_static_mutex_lock ( & connection_gproxy_lock ) ;
2003-09-23 23:47:09 +00:00
dbus_connection_remove_filter ( manager - > connection , dbus_gproxy_manager_filter ,
manager ) ;
2003-09-22 23:50:52 +00:00
dbus_connection_set_data ( manager - > connection ,
gproxy_manager_slot ,
NULL , NULL ) ;
g_static_mutex_unlock ( & connection_gproxy_lock ) ;
dbus_connection_unref ( manager - > connection ) ;
2003-09-22 03:11:12 +00:00
g_free ( manager ) ;
2003-09-22 23:50:52 +00:00
dbus_connection_free_data_slot ( & gproxy_manager_slot ) ;
2003-09-22 03:11:12 +00:00
}
else
{
UNLOCK_MANAGER ( manager ) ;
}
}
2003-09-23 23:47:09 +00:00
static guint
tristring_hash ( gconstpointer key )
2003-08-14 22:49:13 +00:00
{
2003-09-23 23:47:09 +00:00
const char * p = key ;
guint h = * p ;
if ( h )
{
for ( p + = 1 ; * p ! = ' \0 ' ; p + + )
h = ( h < < 5 ) - h + * p ;
}
/* skip nul and do the next substring */
for ( p + = 1 ; * p ! = ' \0 ' ; p + + )
h = ( h < < 5 ) - h + * p ;
/* skip nul again and another substring */
for ( p + = 1 ; * p ! = ' \0 ' ; p + + )
h = ( h < < 5 ) - h + * p ;
2003-09-23 04:20:06 +00:00
2003-09-23 23:47:09 +00:00
return h ;
}
2003-08-14 22:49:13 +00:00
2003-09-23 23:47:09 +00:00
static gboolean
strequal_len ( const char * a ,
const char * b ,
size_t * lenp )
2003-09-23 04:20:06 +00:00
{
2003-09-23 23:47:09 +00:00
size_t a_len ;
size_t b_len ;
a_len = strlen ( a ) ;
b_len = strlen ( b ) ;
if ( a_len ! = b_len )
return FALSE ;
if ( memcmp ( a , b , a_len ) ! = 0 )
return FALSE ;
* lenp = a_len ;
return TRUE ;
}
static gboolean
tristring_equal ( gconstpointer a ,
gconstpointer b )
{
const char * ap = a ;
const char * bp = b ;
size_t len ;
if ( ! strequal_len ( ap , bp , & len ) )
return FALSE ;
ap + = len + 1 ;
bp + = len + 1 ;
if ( ! strequal_len ( ap , bp , & len ) )
return FALSE ;
ap + = len + 1 ;
bp + = len + 1 ;
if ( strcmp ( ap , bp ) ! = 0 )
return FALSE ;
return TRUE ;
}
static char *
tristring_alloc_from_strings ( size_t padding_before ,
const char * service ,
const char * path ,
const char * interface )
{
size_t service_len , iface_len , path_len , len ;
char * tri ;
if ( service )
service_len = strlen ( service ) ;
else
service_len = 0 ;
path_len = strlen ( path ) ;
iface_len = strlen ( interface ) ;
tri = g_malloc ( padding_before + service_len + path_len + iface_len + 3 ) ;
len = padding_before ;
if ( service )
memcpy ( & tri [ len ] , service , service_len ) ;
len + = service_len ;
tri [ len ] = ' \0 ' ;
len + = 1 ;
g_assert ( len = = ( padding_before + service_len + 1 ) ) ;
memcpy ( & tri [ len ] , path , path_len ) ;
len + = path_len ;
tri [ len ] = ' \0 ' ;
len + = 1 ;
g_assert ( len = = ( padding_before + service_len + path_len + 2 ) ) ;
memcpy ( & tri [ len ] , interface , iface_len ) ;
len + = iface_len ;
tri [ len ] = ' \0 ' ;
len + = 1 ;
g_assert ( len = = ( padding_before + service_len + path_len + iface_len + 3 ) ) ;
return tri ;
}
static char *
tristring_from_proxy ( DBusGProxy * proxy )
{
return tristring_alloc_from_strings ( 0 ,
proxy - > service ,
proxy - > path ,
proxy - > interface ) ;
}
static char *
tristring_from_message ( DBusMessage * message )
{
return tristring_alloc_from_strings ( 0 ,
dbus_message_get_sender ( message ) ,
dbus_message_get_path ( message ) ,
dbus_message_get_interface ( message ) ) ;
}
static DBusGProxyList *
gproxy_list_new ( DBusGProxy * first_proxy )
{
DBusGProxyList * list ;
list = ( void * ) tristring_alloc_from_strings ( G_STRUCT_OFFSET ( DBusGProxyList , name ) ,
first_proxy - > service ,
first_proxy - > path ,
first_proxy - > interface ) ;
list - > proxies = NULL ;
return list ;
}
static void
gproxy_list_free ( DBusGProxyList * list )
{
/* we don't hold a reference to the proxies in the list,
* as they ref the GProxyManager
*/
g_slist_free ( list - > proxies ) ;
g_free ( list ) ;
}
static char *
gproxy_get_match_rule ( DBusGProxy * proxy )
{
/* FIXME Some sort of escaping is required here I think */
if ( proxy - > service )
return g_strdup_printf ( " type='signal',service='%s',path='%s',interface='%s' " ,
proxy - > service , proxy - > path , proxy - > interface ) ;
else
return g_strdup_printf ( " type='signal',path='%s',interface='%s' " ,
proxy - > path , proxy - > interface ) ;
}
static void
dbus_gproxy_manager_register ( DBusGProxyManager * manager ,
DBusGProxy * proxy )
{
DBusGProxyList * list ;
LOCK_MANAGER ( manager ) ;
if ( manager - > proxy_lists = = NULL )
{
list = NULL ;
manager - > proxy_lists = g_hash_table_new_full ( tristring_hash ,
tristring_equal ,
NULL ,
( GFreeFunc ) gproxy_list_free ) ;
}
else
{
char * tri ;
tri = tristring_from_proxy ( proxy ) ;
list = g_hash_table_lookup ( manager - > proxy_lists , tri ) ;
g_free ( tri ) ;
}
if ( list = = NULL )
{
list = gproxy_list_new ( proxy ) ;
g_hash_table_replace ( manager - > proxy_lists ,
list - > name , list ) ;
}
if ( list - > proxies = = NULL )
{
/* We have to add the match rule to the server,
* but FIXME only if the server is a message bus ,
* not if it ' s a peer .
*/
char * rule ;
rule = gproxy_get_match_rule ( proxy ) ;
/* We don't check for errors; it's not like anyone would handle them,
* and we don ' t want a round trip here .
*/
dbus_bus_add_match ( manager - > connection ,
rule , NULL ) ;
g_free ( rule ) ;
}
g_assert ( g_slist_find ( list - > proxies , proxy ) = = NULL ) ;
list - > proxies = g_slist_prepend ( list - > proxies , proxy ) ;
UNLOCK_MANAGER ( manager ) ;
}
static void
dbus_gproxy_manager_unregister ( DBusGProxyManager * manager ,
DBusGProxy * proxy )
{
DBusGProxyList * list ;
char * tri ;
LOCK_MANAGER ( manager ) ;
2003-09-24 02:58:14 +00:00
# ifndef G_DISABLE_CHECKS
2003-09-23 23:47:09 +00:00
if ( manager - > proxy_lists = = NULL )
{
2003-10-12 05:59:39 +00:00
g_warning ( " Trying to unregister a proxy but there aren't any registered " ) ;
2003-09-23 23:47:09 +00:00
return ;
}
2003-09-24 02:58:14 +00:00
# endif
2003-09-23 23:47:09 +00:00
tri = tristring_from_proxy ( proxy ) ;
list = g_hash_table_lookup ( manager - > proxy_lists , tri ) ;
2003-09-24 02:58:14 +00:00
# ifndef G_DISABLE_CHECKS
2003-09-23 23:47:09 +00:00
if ( list = = NULL )
{
2003-10-12 05:59:39 +00:00
g_warning ( " Trying to unregister a proxy but it isn't registered " ) ;
2003-09-23 23:47:09 +00:00
return ;
}
2003-09-24 02:58:14 +00:00
# endif
2003-09-23 23:47:09 +00:00
g_assert ( g_slist_find ( list - > proxies , proxy ) ! = NULL ) ;
list - > proxies = g_slist_remove ( list - > proxies , proxy ) ;
g_assert ( g_slist_find ( list - > proxies , proxy ) = = NULL ) ;
2003-09-24 02:58:14 +00:00
2003-10-12 05:59:39 +00:00
if ( list - > proxies = = NULL )
{
g_hash_table_remove ( manager - > proxy_lists ,
tri ) ;
list = NULL ;
}
2003-09-24 02:58:14 +00:00
if ( g_hash_table_size ( manager - > proxy_lists ) = = 0 )
{
g_hash_table_destroy ( manager - > proxy_lists ) ;
manager - > proxy_lists = NULL ;
}
2003-10-12 05:59:39 +00:00
g_free ( tri ) ;
2003-09-23 23:47:09 +00:00
UNLOCK_MANAGER ( manager ) ;
}
2003-09-24 02:58:14 +00:00
static void
list_proxies_foreach ( gpointer key ,
gpointer value ,
gpointer user_data )
{
DBusGProxyList * list ;
GSList * * ret ;
GSList * tmp ;
list = value ;
ret = user_data ;
tmp = list - > proxies ;
while ( tmp ! = NULL )
{
DBusGProxy * proxy = DBUS_GPROXY ( tmp - > data ) ;
g_object_ref ( proxy ) ;
* ret = g_slist_prepend ( * ret , proxy ) ;
tmp = tmp - > next ;
}
}
static GSList *
dbus_gproxy_manager_list_all ( DBusGProxyManager * manager )
{
GSList * ret ;
ret = NULL ;
if ( manager - > proxy_lists )
{
g_hash_table_foreach ( manager - > proxy_lists ,
list_proxies_foreach ,
& ret ) ;
}
return ret ;
}
2003-09-23 23:47:09 +00:00
static DBusHandlerResult
dbus_gproxy_manager_filter ( DBusConnection * connection ,
DBusMessage * message ,
void * user_data )
{
DBusGProxyManager * manager ;
if ( dbus_message_get_type ( message ) ! = DBUS_MESSAGE_TYPE_SIGNAL )
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED ;
2003-09-24 02:58:14 +00:00
manager = user_data ;
dbus_gproxy_manager_ref ( manager ) ;
LOCK_MANAGER ( manager ) ;
2003-09-23 23:47:09 +00:00
if ( dbus_message_is_signal ( message ,
DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL ,
" Disconnected " ) )
{
2003-09-24 02:58:14 +00:00
/* Destroy all the proxies, quite possibly resulting in unreferencing
* the proxy manager and the connection as well .
2003-09-23 23:47:09 +00:00
*/
2003-09-24 02:58:14 +00:00
GSList * all ;
GSList * tmp ;
all = dbus_gproxy_manager_list_all ( manager ) ;
tmp = all ;
while ( tmp ! = NULL )
{
DBusGProxy * proxy ;
proxy = DBUS_GPROXY ( tmp - > data ) ;
UNLOCK_MANAGER ( manager ) ;
dbus_gproxy_destroy ( proxy ) ;
g_object_unref ( G_OBJECT ( proxy ) ) ;
LOCK_MANAGER ( manager ) ;
tmp = tmp - > next ;
}
g_slist_free ( all ) ;
# ifndef G_DISABLE_CHECKS
if ( manager - > proxy_lists ! = NULL )
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. " ) ;
# endif
2003-09-23 23:47:09 +00:00
}
else
{
char * tri ;
DBusGProxyList * list ;
tri = tristring_from_message ( message ) ;
2003-08-16 21:28:47 +00:00
2003-09-23 23:47:09 +00:00
if ( manager - > proxy_lists )
list = g_hash_table_lookup ( manager - > proxy_lists , tri ) ;
else
list = NULL ;
g_free ( tri ) ;
2003-09-24 02:58:14 +00:00
/* Emit the signal */
2003-09-23 23:47:09 +00:00
if ( list ! = NULL )
{
2003-09-24 02:58:14 +00:00
GSList * tmp ;
GSList * copy ;
2003-09-23 23:47:09 +00:00
2003-09-24 02:58:14 +00:00
copy = g_slist_copy ( list - > proxies ) ;
g_slist_foreach ( copy , ( GFunc ) g_object_ref , NULL ) ;
tmp = copy ;
while ( tmp ! = NULL )
{
DBusGProxy * proxy ;
proxy = DBUS_GPROXY ( tmp - > data ) ;
UNLOCK_MANAGER ( manager ) ;
dbus_gproxy_emit_received ( proxy , message ) ;
g_object_unref ( G_OBJECT ( proxy ) ) ;
LOCK_MANAGER ( manager ) ;
tmp = tmp - > next ;
}
g_slist_free ( copy ) ;
2003-09-23 23:47:09 +00:00
}
}
2003-09-24 02:58:14 +00:00
UNLOCK_MANAGER ( manager ) ;
dbus_gproxy_manager_unref ( manager ) ;
2003-09-23 23:47:09 +00:00
/* "Handling" signals doesn't make sense, they are for everyone
* who cares
*/
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED ;
}
/* ---------- DBusGProxy -------------- */
enum
{
2003-09-24 02:58:14 +00:00
DESTROY ,
2003-09-23 23:47:09 +00:00
RECEIVED ,
LAST_SIGNAL
} ;
2003-09-23 04:20:06 +00:00
static void * parent_class ;
2003-09-23 23:47:09 +00:00
static guint signals [ LAST_SIGNAL ] = { 0 } ;
2003-09-23 04:20:06 +00:00
static void
dbus_gproxy_init ( DBusGProxy * proxy )
2003-08-14 22:49:13 +00:00
{
2003-09-23 04:20:06 +00:00
/* Nothing */
}
2003-08-14 22:49:13 +00:00
2003-09-23 04:20:06 +00:00
static void
dbus_gproxy_class_init ( DBusGProxyClass * klass )
{
GObjectClass * object_class = G_OBJECT_CLASS ( klass ) ;
2003-08-16 21:28:47 +00:00
2003-09-23 04:20:06 +00:00
parent_class = g_type_class_peek_parent ( klass ) ;
object_class - > finalize = dbus_gproxy_finalize ;
2003-09-24 02:58:14 +00:00
object_class - > dispose = dbus_gproxy_dispose ;
signals [ DESTROY ] =
g_signal_new ( " destroy " ,
G_OBJECT_CLASS_TYPE ( object_class ) ,
G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS ,
0 ,
NULL , NULL ,
g_cclosure_marshal_VOID__VOID ,
G_TYPE_NONE , 0 ) ;
2003-09-23 23:47:09 +00:00
signals [ RECEIVED ] =
g_signal_new ( " received " ,
G_OBJECT_CLASS_TYPE ( object_class ) ,
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED ,
0 ,
NULL , NULL ,
g_cclosure_marshal_VOID__BOXED ,
G_TYPE_NONE , 1 ,
DBUS_TYPE_MESSAGE ) ;
2003-09-23 04:20:06 +00:00
}
2003-08-14 22:49:13 +00:00
2003-09-24 02:58:14 +00:00
static void
dbus_gproxy_dispose ( GObject * object )
{
DBusGProxy * proxy ;
proxy = DBUS_GPROXY ( object ) ;
g_signal_emit ( object , signals [ DESTROY ] , 0 ) ;
G_OBJECT_CLASS ( parent_class ) - > dispose ( object ) ;
}
2003-09-23 04:20:06 +00:00
static void
dbus_gproxy_finalize ( GObject * object )
{
DBusGProxy * proxy ;
proxy = DBUS_GPROXY ( object ) ;
if ( proxy - > manager )
2003-09-23 23:47:09 +00:00
{
dbus_gproxy_manager_unregister ( proxy - > manager , proxy ) ;
dbus_gproxy_manager_unref ( proxy - > manager ) ;
}
2003-09-23 04:20:06 +00:00
g_free ( proxy - > service ) ;
g_free ( proxy - > path ) ;
g_free ( proxy - > interface ) ;
2003-08-16 21:28:47 +00:00
2003-09-23 04:20:06 +00:00
G_OBJECT_CLASS ( parent_class ) - > finalize ( object ) ;
2003-08-14 22:49:13 +00:00
}
2003-09-24 02:58:14 +00:00
static void
dbus_gproxy_destroy ( DBusGProxy * proxy )
{
/* FIXME do we need the GTK_IN_DESTRUCTION style flag
* from GtkObject ?
*/
g_object_run_dispose ( G_OBJECT ( proxy ) ) ;
}
2003-09-23 23:47:09 +00:00
static char *
create_signal_detail ( const char * interface ,
const char * signal )
{
GString * str ;
str = g_string_new ( interface ) ;
g_string_append ( str , " . " ) ;
g_string_append ( str , signal ) ;
return g_string_free ( str , FALSE ) ;
}
static void
dbus_gproxy_emit_received ( DBusGProxy * proxy ,
DBusMessage * message )
{
const char * interface ;
const char * signal ;
char * detail ;
GQuark q ;
interface = dbus_message_get_interface ( message ) ;
signal = dbus_message_get_member ( message ) ;
g_assert ( interface ! = NULL ) ;
g_assert ( signal ! = NULL ) ;
detail = create_signal_detail ( interface , signal ) ;
/* If the quark isn't preexisting, there's no way there
* are any handlers connected . We don ' t want to create
* extra quarks for every possible signal .
*/
q = g_quark_try_string ( detail ) ;
if ( q ! = 0 )
g_signal_emit ( G_OBJECT ( proxy ) ,
signals [ RECEIVED ] ,
q ,
message ) ;
g_free ( detail ) ;
}
2003-08-14 22:49:13 +00:00
/** @} End of DBusGLibInternals */
/** @addtogroup DBusGLib
* @ {
*/
2003-09-23 04:20:06 +00:00
/**
* Standard GObject get_type ( ) function for DBusGProxy .
*
* @ returns type ID for DBusGProxy class
*/
GType
dbus_gproxy_get_type ( void )
{
static GType object_type = 0 ;
if ( ! object_type )
{
static const GTypeInfo object_info =
{
sizeof ( DBusGProxyClass ) ,
( GBaseInitFunc ) NULL ,
( GBaseFinalizeFunc ) NULL ,
( GClassInitFunc ) dbus_gproxy_class_init ,
NULL , /* class_finalize */
NULL , /* class_data */
sizeof ( DBusGProxy ) ,
0 , /* n_preallocs */
( GInstanceInitFunc ) dbus_gproxy_init ,
} ;
object_type = g_type_register_static ( G_TYPE_OBJECT ,
" DBusGProxy " ,
& object_info , 0 ) ;
}
return object_type ;
}
2003-09-23 23:47:09 +00:00
static DBusGProxy *
dbus_gproxy_new ( DBusConnection * connection ,
const char * service_name ,
const char * path_name ,
const char * interface_name )
{
DBusGProxy * proxy ;
g_assert ( connection ! = NULL ) ;
proxy = g_object_new ( DBUS_TYPE_GPROXY , NULL ) ;
/* These should all be construct-only mandatory properties,
* for now we just don ' t let people use g_object_new ( ) .
*/
proxy - > manager = dbus_gproxy_manager_get ( connection ) ;
proxy - > service = g_strdup ( service_name ) ;
proxy - > path = g_strdup ( path_name ) ;
proxy - > interface = g_strdup ( interface_name ) ;
dbus_gproxy_manager_register ( proxy - > manager , proxy ) ;
return proxy ;
}
2003-08-14 22:49:13 +00:00
/**
2003-09-24 02:58:14 +00:00
* Creates a new proxy for a remote interface exported by a service on
* a message bus . Method calls and signal connections over this proxy
* will go to the service owner ; the service owner is expected to
* support the given interface name . THE SERVICE OWNER MAY CHANGE OVER
* TIME , for example between two different method calls . If you need a
* fixed owner , you need to request the current owner and bind a proxy
* to that rather than to the generic service name ; see
* dbus_gproxy_new_for_service_owner ( ) .
2003-08-14 22:49:13 +00:00
*
* A service - associated proxy only makes sense with a message bus ,
* not for app - to - app direct dbus connections .
*
2003-09-24 02:58:14 +00:00
* This proxy will only emit the " destroy " signal if the # DBusConnection
* is disconnected or the proxy is has no remaining references .
*
* @ param connection the connection to the remote bus
2003-08-14 22:49:13 +00:00
* @ param service_name name of the service on the message bus
2003-09-22 03:11:12 +00:00
* @ param path_name name of the object inside the service to call methods on
2003-08-14 22:49:13 +00:00
* @ param interface_name name of the interface to call methods on
* @ returns new proxy object
*/
DBusGProxy *
dbus_gproxy_new_for_service ( DBusConnection * connection ,
const char * service_name ,
2003-09-22 03:11:12 +00:00
const char * path_name ,
2003-08-14 22:49:13 +00:00
const char * interface_name )
{
DBusGProxy * proxy ;
g_return_val_if_fail ( connection ! = NULL , NULL ) ;
g_return_val_if_fail ( service_name ! = NULL , NULL ) ;
2003-09-22 03:11:12 +00:00
g_return_val_if_fail ( path_name ! = NULL , NULL ) ;
2003-08-14 22:49:13 +00:00
g_return_val_if_fail ( interface_name ! = NULL , NULL ) ;
2003-09-23 23:47:09 +00:00
proxy = dbus_gproxy_new ( connection , service_name ,
path_name , interface_name ) ;
2003-08-14 22:49:13 +00:00
return proxy ;
}
2003-09-24 02:58:14 +00:00
/**
* Similar to dbus_gproxy_new_for_service ( ) , but makes a round - trip
* request to the message bus to get the current service owner , then
* binds the proxy specifically to the current owner . As a result , the
* service owner will not change over time , and the proxy will emit
* the " destroy " signal when the owner disappears from the message
* bus .
*
* An example of the difference between dbus_gproxy_new_for_service ( )
* and dbus_gproxy_new_for_service_owner ( ) : if you pass the service name
* " org.freedesktop.Database " dbus_gproxy_new_for_service ( ) remains bound
* to that name as it changes owner . dbus_gproxy_new_for_service_owner ( )
* will fail if the service has no owner . If the service has an owner ,
* dbus_gproxy_new_for_service_owner ( ) will bind to the unique name
* of that owner rather than the generic service name .
*
* @ param connection the connection to the remote bus
* @ param service_name name of the service on the message bus
* @ param path_name name of the object inside the service to call methods on
* @ param interface_name name of the interface to call methods on
* @ param error return location for an error
* @ returns new proxy object , or # NULL on error
*/
DBusGProxy *
dbus_gproxy_new_for_service_owner ( DBusConnection * connection ,
const char * service_name ,
const char * path_name ,
const char * interface_name ,
GError * * error )
{
g_return_val_if_fail ( connection ! = NULL , NULL ) ;
g_return_val_if_fail ( service_name ! = NULL , NULL ) ;
g_return_val_if_fail ( path_name ! = NULL , NULL ) ;
g_return_val_if_fail ( interface_name ! = NULL , NULL ) ;
}
/**
* Creates a proxy for an object in peer application ( one
* we ' re directly connected to ) . That is , this function is
* intended for use when there ' s no message bus involved ,
* we ' re doing a simple 1 - to - 1 communication between two
* applications .
*
*
* @ param connection the connection to the peer
* @ param path_name name of the object inside the peer to call methods on
* @ param interface_name name of the interface to call methods on
* @ returns new proxy object
*
*/
DBusGProxy *
dbus_gproxy_new_for_peer ( DBusConnection * connection ,
const char * path_name ,
const char * interface_name )
{
DBusGProxy * proxy ;
g_return_val_if_fail ( connection ! = NULL , NULL ) ;
g_return_val_if_fail ( path_name ! = NULL , NULL ) ;
g_return_val_if_fail ( interface_name ! = NULL , NULL ) ;
proxy = dbus_gproxy_new ( connection , NULL ,
path_name , interface_name ) ;
return proxy ;
}
2003-08-14 22:49:13 +00:00
/**
* Invokes a method on a remote interface . This function does not
2003-08-16 21:28:47 +00:00
* block ; instead it returns an opaque # DBusPendingCall object that
2003-08-14 22:49:13 +00:00
* tracks the pending call . The method call will not be sent over the
* wire until the application returns to the main loop , or blocks in
* dbus_connection_flush ( ) to write out pending data . The call will
* be completed after a timeout , or when a reply is received .
2003-08-16 21:28:47 +00:00
* To collect the results of the call ( which may be an error ,
* or a reply ) , use dbus_gproxy_end_call ( ) .
2003-08-14 22:49:13 +00:00
*
2003-09-17 03:52:07 +00:00
* @ todo this particular function shouldn ' t die on out of memory ,
* since you should be able to do a call with large arguments .
*
2003-08-14 22:49:13 +00:00
* @ param proxy a proxy for a remote interface
* @ param method the name of the method to invoke
* @ param first_arg_type type of the first argument
*
* @ returns opaque pending call object
2003-09-17 03:52:07 +00:00
* */
2003-08-16 21:28:47 +00:00
DBusPendingCall *
2003-08-14 22:49:13 +00:00
dbus_gproxy_begin_call ( DBusGProxy * proxy ,
const char * method ,
int first_arg_type ,
. . . )
{
2003-09-17 03:52:07 +00:00
DBusPendingCall * pending ;
DBusMessage * message ;
va_list args ;
2003-09-23 23:47:09 +00:00
g_return_val_if_fail ( DBUS_IS_GPROXY ( proxy ) , NULL ) ;
2003-08-16 21:28:47 +00:00
2003-09-17 03:52:07 +00:00
message = dbus_message_new_method_call ( proxy - > service ,
proxy - > path ,
2003-09-21 19:53:56 +00:00
proxy - > interface ,
2003-09-17 03:52:07 +00:00
method ) ;
if ( message = = NULL )
goto oom ;
va_start ( args , first_arg_type ) ;
if ( ! dbus_message_append_args_valist ( message , first_arg_type ,
args ) )
goto oom ;
va_end ( args ) ;
2003-09-22 23:50:52 +00:00
if ( ! dbus_connection_send_with_reply ( proxy - > manager - > connection ,
2003-09-17 03:52:07 +00:00
message ,
& pending ,
- 1 ) )
goto oom ;
return pending ;
oom :
/* FIXME we should create a pending call that's
* immediately completed with an error status without
* ever going on the wire .
*/
g_error ( " Out of memory " ) ;
return NULL ;
2003-08-16 21:28:47 +00:00
}
/**
* Collects the results of a method call . The method call was normally
* initiated with dbus_gproxy_end_call ( ) . This function will block if
* the results haven ' t yet been received ; use
* dbus_pending_call_set_notify ( ) to be notified asynchronously that a
2003-09-17 03:52:07 +00:00
* pending call has been completed . Use
* dbus_pending_call_get_completed ( ) to check whether a call has been
* completed . If it ' s completed , it will not block .
2003-08-16 21:28:47 +00:00
*
* If the call results in an error , the error is set as normal for
* GError and the function returns # FALSE .
*
* Otherwise , the " out " parameters and return value of the
* method are stored in the provided varargs list .
* The list should be terminated with DBUS_TYPE_INVALID .
*
2003-09-17 03:52:07 +00:00
* This function doesn ' t affect the reference count of the
* # DBusPendingCall , the caller of dbus_gproxy_begin_call ( ) still owns
* a reference .
*
2003-08-16 21:28:47 +00:00
* @ param proxy a proxy for a remote interface
* @ param pending the pending call from dbus_gproxy_begin_call ( )
* @ param error return location for an error
* @ param first_arg_type type of first " out " argument
2003-09-17 03:52:07 +00:00
* @ returns # FALSE if an error is set */
2003-08-16 21:28:47 +00:00
gboolean
dbus_gproxy_end_call ( DBusGProxy * proxy ,
DBusPendingCall * pending ,
GError * * error ,
int first_arg_type ,
. . . )
{
2003-09-17 03:52:07 +00:00
DBusMessage * message ;
va_list args ;
DBusError derror ;
2003-09-23 23:47:09 +00:00
g_return_val_if_fail ( DBUS_IS_GPROXY ( proxy ) , FALSE ) ;
2003-09-17 03:52:07 +00:00
g_return_val_if_fail ( pending ! = NULL , FALSE ) ;
2003-08-16 21:28:47 +00:00
2003-09-17 03:52:07 +00:00
dbus_pending_call_block ( pending ) ;
message = dbus_pending_call_get_reply ( pending ) ;
g_assert ( message ! = NULL ) ;
dbus_error_init ( & derror ) ;
va_start ( args , first_arg_type ) ;
if ( ! dbus_message_get_args_valist ( message , & derror , first_arg_type , args ) )
{
va_end ( args ) ;
goto error ;
}
va_end ( args ) ;
return TRUE ;
error :
dbus_set_g_error ( error , & derror ) ;
dbus_error_free ( & derror ) ;
return FALSE ;
2003-08-16 21:28:47 +00:00
}
2003-09-23 23:47:09 +00:00
/**
* Sends a method call message as with dbus_gproxy_begin_call ( ) , but
* does not ask for a reply or allow you to receive one .
*
* @ todo this particular function shouldn ' t die on out of memory ,
* since you should be able to do a call with large arguments .
*
* @ param proxy a proxy for a remote interface
* @ param method the name of the method to invoke
* @ param first_arg_type type of the first argument
*/
void
2003-10-03 03:55:35 +00:00
dbus_gproxy_call_no_reply ( DBusGProxy * proxy ,
const char * method ,
int first_arg_type ,
. . . )
2003-09-23 23:47:09 +00:00
{
DBusMessage * message ;
va_list args ;
g_return_if_fail ( DBUS_IS_GPROXY ( proxy ) ) ;
message = dbus_message_new_method_call ( proxy - > service ,
proxy - > path ,
proxy - > interface ,
method ) ;
if ( message = = NULL )
goto oom ;
dbus_message_set_no_reply ( message , TRUE ) ;
va_start ( args , first_arg_type ) ;
if ( ! dbus_message_append_args_valist ( message , first_arg_type ,
args ) )
goto oom ;
va_end ( args ) ;
if ( ! dbus_connection_send ( proxy - > manager - > connection ,
message ,
NULL ) )
goto oom ;
oom :
g_error ( " Out of memory " ) ;
}
2003-08-16 21:28:47 +00:00
/**
* Sends a message to the interface we ' re proxying for . Does not
* block or wait for a reply . The message is only actually written out
* when you return to the main loop or block in
* dbus_connection_flush ( ) .
*
* The message is modified to be addressed to the target interface .
2003-09-17 03:52:07 +00:00
* That is , a destination service field or whatever is needed will be
* added to the message . The basic point of this function is to add
* the necessary header fields , otherwise it ' s equivalent to
* dbus_connection_send ( ) .
2003-08-16 21:28:47 +00:00
*
* This function adds a reference to the message , so the caller
* still owns its original reference .
*
* @ param proxy a proxy for a remote interface
* @ param message the message to address and send
2003-09-17 03:52:07 +00:00
* @ param client_serial return location for message ' s serial , or # NULL */
2003-08-16 21:28:47 +00:00
void
dbus_gproxy_send ( DBusGProxy * proxy ,
DBusMessage * message ,
dbus_uint32_t * client_serial )
{
2003-09-23 23:47:09 +00:00
g_return_if_fail ( DBUS_IS_GPROXY ( proxy ) ) ;
2003-08-14 22:49:13 +00:00
2003-08-16 21:28:47 +00:00
if ( proxy - > service )
{
if ( ! dbus_message_set_destination ( message , proxy - > service ) )
2003-09-17 03:52:07 +00:00
g_error ( " Out of memory " ) ;
2003-08-16 21:28:47 +00:00
}
2003-09-22 03:11:12 +00:00
if ( proxy - > path )
2003-08-16 21:28:47 +00:00
{
2003-09-22 03:11:12 +00:00
if ( ! dbus_message_set_path ( message , proxy - > path ) )
2003-09-17 03:52:07 +00:00
g_error ( " Out of memory " ) ;
2003-08-16 21:28:47 +00:00
}
2003-09-22 03:11:12 +00:00
if ( proxy - > interface )
2003-08-16 21:28:47 +00:00
{
2003-09-22 03:11:12 +00:00
if ( ! dbus_message_set_interface ( message , proxy - > interface ) )
2003-09-17 03:52:07 +00:00
g_error ( " Out of memory " ) ;
2003-08-16 21:28:47 +00:00
}
2003-09-17 03:52:07 +00:00
2003-09-22 23:50:52 +00:00
if ( ! dbus_connection_send ( proxy - > manager - > connection , message , client_serial ) )
2003-08-16 21:28:47 +00:00
g_error ( " Out of memory \n " ) ;
2003-08-14 22:49:13 +00:00
}
2003-09-23 05:04:51 +00:00
void
2003-09-23 23:47:09 +00:00
dbus_gproxy_connect_signal ( DBusGProxy * proxy ,
const char * signal_name ,
DBusGProxySignalHandler handler ,
void * data ,
2003-09-24 02:58:14 +00:00
GClosureNotify free_data_func )
2003-09-23 05:04:51 +00:00
{
2003-09-23 23:47:09 +00:00
GClosure * closure ;
char * detail ;
2003-09-23 05:04:51 +00:00
2003-09-23 23:47:09 +00:00
g_return_if_fail ( DBUS_IS_GPROXY ( proxy ) ) ;
g_return_if_fail ( signal_name ! = NULL ) ;
g_return_if_fail ( handler ! = NULL ) ;
detail = create_signal_detail ( proxy - > interface , signal_name ) ;
closure = g_cclosure_new ( G_CALLBACK ( handler ) , data , free_data_func ) ;
g_signal_connect_closure_by_id ( G_OBJECT ( proxy ) ,
signals [ RECEIVED ] ,
g_quark_from_string ( detail ) ,
closure , FALSE ) ;
2003-09-23 05:04:51 +00:00
2003-09-23 23:47:09 +00:00
g_free ( detail ) ;
2003-09-23 05:04:51 +00:00
}
void
2003-09-23 23:47:09 +00:00
dbus_gproxy_disconnect_signal ( DBusGProxy * proxy ,
const char * signal_name ,
DBusGProxySignalHandler handler ,
void * data )
2003-09-23 05:04:51 +00:00
{
2003-09-23 23:47:09 +00:00
char * detail ;
GQuark q ;
2003-09-23 05:04:51 +00:00
2003-09-23 23:47:09 +00:00
g_return_if_fail ( DBUS_IS_GPROXY ( proxy ) ) ;
g_return_if_fail ( signal_name ! = NULL ) ;
g_return_if_fail ( handler ! = NULL ) ;
detail = create_signal_detail ( proxy - > interface , signal_name ) ;
q = g_quark_try_string ( detail ) ;
g_free ( detail ) ;
2003-09-24 02:58:14 +00:00
# ifndef G_DISABLE_CHECKS
2003-09-23 23:47:09 +00:00
if ( q = = 0 )
{
g_warning ( " %s: No signal handlers for %s found on this DBusGProxy " ,
G_GNUC_FUNCTION , signal_name ) ;
return ;
}
2003-09-24 02:58:14 +00:00
# endif
2003-09-23 23:47:09 +00:00
g_signal_handlers_disconnect_matched ( G_OBJECT ( proxy ) ,
G_SIGNAL_MATCH_DETAIL |
G_SIGNAL_MATCH_FUNC |
G_SIGNAL_MATCH_DATA ,
signals [ RECEIVED ] ,
q ,
NULL ,
G_CALLBACK ( handler ) , data ) ;
2003-09-23 05:04:51 +00:00
}
2003-08-14 22:49:13 +00:00
/** @} End of DBusGLib public */
# ifdef DBUS_BUILD_TESTS
/**
* @ ingroup DBusGLibInternals
* Unit test for GLib proxy functions
* @ returns # TRUE on success .
*/
dbus_bool_t
_dbus_gproxy_test ( void )
{
2003-09-24 02:58:14 +00:00
2003-08-14 22:49:13 +00:00
return TRUE ;
}
# endif /* DBUS_BUILD_TESTS */