2010-05-06 20:13:59 +02:00
/* GDBus - GLib D-Bus Library
*
2010-05-09 19:14:55 +02:00
* Copyright ( C ) 2008 - 2010 Red Hat , Inc .
2010-05-06 20:13:59 +02:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2 of the License , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library ; if not , write to the
* Free Software Foundation , Inc . , 59 Temple Place , Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*
* Author : David Zeuthen < davidz @ redhat . com >
*/
# include "config.h"
# include <stdlib.h>
2010-05-06 22:34:23 +02:00
# include <string.h>
2010-05-06 20:13:59 +02:00
# include "gdbusutils.h"
# include "gdbusproxy.h"
# include "gioenumtypes.h"
# include "gdbusconnection.h"
# include "gdbuserror.h"
# include "gdbusprivate.h"
# include "gio-marshal.h"
# include "ginitable.h"
# include "gasyncinitable.h"
# include "gioerror.h"
# include "gasyncresult.h"
# include "gsimpleasyncresult.h"
2010-06-11 21:45:18 +02:00
# include "gcancellable.h"
2011-04-08 21:14:47 +02:00
# include "gdbusinterface.h"
2010-05-06 20:13:59 +02:00
2010-05-06 22:34:23 +02:00
# include "glibintl.h"
2010-05-06 20:13:59 +02:00
/**
* SECTION : gdbusproxy
2011-04-08 22:12:09 +02:00
* @ short_description : Client - side D - Bus interface proxy
2010-05-06 21:31:45 +02:00
* @ include : gio / gio . h
2010-05-06 20:13:59 +02:00
*
* # GDBusProxy is a base class used for proxies to access a D - Bus
2010-06-11 21:45:18 +02:00
* interface on a remote object . A # GDBusProxy can be constructed for
* both well - known and unique names .
2010-05-14 03:45:18 +02:00
*
2010-06-11 21:45:18 +02:00
* By default , # GDBusProxy will cache all properties ( and listen to
* changes ) of the remote object , and proxy all signals that gets
2010-05-14 03:45:18 +02:00
* emitted . This behaviour can be changed by passing suitable
2010-06-11 21:45:18 +02:00
* # GDBusProxyFlags when the proxy is created . If the proxy is for a
* well - known name , the property cache is flushed when the name owner
* vanishes and reloaded when a name owner appears .
*
* If a # GDBusProxy is used for a well - known name , the owner of the
* name is tracked and can be read from
* # GDBusProxy : g - name - owner . Connect to the # GObject : : notify signal to
* get notified of changes . Additionally , only signals and property
2010-08-18 17:35:25 +02:00
* changes emitted from the current name owner are considered and
* calls are always sent to the current name owner . This avoids a
* number of race conditions when the name is lost by one owner and
* claimed by another . However , if no name owner currently exists ,
* then calls will be sent to the well - known name which may result in
* the message bus launching an owner ( unless
* % G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START is set ) .
2010-05-14 03:45:18 +02:00
*
2011-05-26 16:18:44 +02:00
* The generic # GDBusProxy : : g - properties - changed and
* # GDBusProxy : : g - signal signals are not very convenient to work
* with . Therefore , the recommended way of working with proxies is to
* subclass # GDBusProxy , and have more natural properties and signals
* in your derived class . See < xref linkend = " gdbus-example-gdbus-codegen " / >
* for how this can easily be done using the
* < command > < link linkend = " gdbus-codegen " > gdbus - codegen < / link > < / command >
* tool .
2010-05-14 03:45:18 +02:00
*
2011-05-26 15:54:47 +02:00
* A # GDBusProxy instance can be used from multiple threads but note
2011-05-26 16:18:44 +02:00
* that all signals ( e . g . # GDBusProxy : : g - signal , # GDBusProxy : : g - properties - changed
2011-05-26 15:54:47 +02:00
* and # GObject : : notify ) are emitted in the
* < link linkend = " g-main-context-push-thread-default " > thread - default main loop < / link >
* of the thread where the instance was constructed .
*
2010-06-11 21:45:18 +02:00
* < example id = " gdbus-wellknown-proxy " > < title > GDBusProxy for a well - known - name < / title > < programlisting > < xi : include xmlns : xi = " http://www.w3.org/2001/XInclude " parse = " text " href = " ../../../../gio/tests/gdbus-example-watch-proxy.c " > < xi : fallback > FIXME : MISSING XINCLUDE CONTENT < / xi : fallback > < / xi : include > < / programlisting > < / example >
2010-05-06 20:13:59 +02:00
*/
2011-05-26 15:54:47 +02:00
/* lock protecting the properties GHashTable */
G_LOCK_DEFINE_STATIC ( properties_lock ) ;
2011-05-26 15:26:29 +02:00
/* ---------------------------------------------------------------------------------------------------- */
G_LOCK_DEFINE_STATIC ( signal_subscription_lock ) ;
typedef struct
{
volatile gint ref_count ;
GDBusProxy * proxy ;
} SignalSubscriptionData ;
static SignalSubscriptionData *
signal_subscription_ref ( SignalSubscriptionData * data )
{
g_atomic_int_inc ( & data - > ref_count ) ;
return data ;
}
static void
signal_subscription_unref ( SignalSubscriptionData * data )
{
if ( g_atomic_int_dec_and_test ( & data - > ref_count ) )
{
g_slice_free ( SignalSubscriptionData , data ) ;
}
}
/* ---------------------------------------------------------------------------------------------------- */
2010-05-06 20:13:59 +02:00
struct _GDBusProxyPrivate
{
2010-06-11 21:45:18 +02:00
GBusType bus_type ;
2011-04-12 16:00:37 +02:00
GDBusProxyFlags flags ;
2010-05-06 20:13:59 +02:00
GDBusConnection * connection ;
2010-06-11 21:45:18 +02:00
gchar * name ;
gchar * name_owner ;
2010-05-06 20:13:59 +02:00
gchar * object_path ;
gchar * interface_name ;
gint timeout_msec ;
2010-06-11 21:45:18 +02:00
guint name_owner_changed_subscription_id ;
GCancellable * get_all_cancellable ;
2010-05-06 20:13:59 +02:00
/* gchar* -> GVariant* */
GHashTable * properties ;
GDBusInterfaceInfo * expected_interface ;
2011-05-26 15:26:29 +02:00
guint properties_changed_subscription_id ;
guint signals_subscription_id ;
2010-05-13 23:20:39 +02:00
gboolean initialized ;
2011-04-08 22:12:33 +02:00
GDBusObject * object ;
2011-05-26 15:26:29 +02:00
SignalSubscriptionData * signal_subscription_data ;
2010-05-06 20:13:59 +02:00
} ;
enum
{
PROP_0 ,
PROP_G_CONNECTION ,
2010-06-11 21:45:18 +02:00
PROP_G_BUS_TYPE ,
PROP_G_NAME ,
PROP_G_NAME_OWNER ,
2010-05-06 20:13:59 +02:00
PROP_G_FLAGS ,
PROP_G_OBJECT_PATH ,
PROP_G_INTERFACE_NAME ,
PROP_G_DEFAULT_TIMEOUT ,
PROP_G_INTERFACE_INFO
} ;
enum
{
PROPERTIES_CHANGED_SIGNAL ,
SIGNAL_SIGNAL ,
LAST_SIGNAL ,
} ;
guint signals [ LAST_SIGNAL ] = { 0 } ;
2011-04-08 21:14:47 +02:00
static void dbus_interface_iface_init ( GDBusInterfaceIface * dbus_interface_iface ) ;
2010-05-06 20:13:59 +02:00
static void initable_iface_init ( GInitableIface * initable_iface ) ;
static void async_initable_iface_init ( GAsyncInitableIface * async_initable_iface ) ;
G_DEFINE_TYPE_WITH_CODE ( GDBusProxy , g_dbus_proxy , G_TYPE_OBJECT ,
2011-04-08 21:14:47 +02:00
G_IMPLEMENT_INTERFACE ( G_TYPE_DBUS_INTERFACE , dbus_interface_iface_init )
2010-05-06 20:13:59 +02:00
G_IMPLEMENT_INTERFACE ( G_TYPE_INITABLE , initable_iface_init )
G_IMPLEMENT_INTERFACE ( G_TYPE_ASYNC_INITABLE , async_initable_iface_init )
) ;
2011-05-26 15:26:29 +02:00
static void
g_dbus_proxy_dispose ( GObject * object )
{
GDBusProxy * proxy = G_DBUS_PROXY ( object ) ;
G_LOCK ( signal_subscription_lock ) ;
if ( proxy - > priv - > signal_subscription_data ! = NULL )
{
proxy - > priv - > signal_subscription_data - > proxy = NULL ;
signal_subscription_unref ( proxy - > priv - > signal_subscription_data ) ;
proxy - > priv - > signal_subscription_data = NULL ;
}
G_UNLOCK ( signal_subscription_lock ) ;
G_OBJECT_CLASS ( g_dbus_proxy_parent_class ) - > dispose ( object ) ;
}
2010-05-06 20:13:59 +02:00
static void
g_dbus_proxy_finalize ( GObject * object )
{
GDBusProxy * proxy = G_DBUS_PROXY ( object ) ;
2010-06-11 21:45:18 +02:00
g_warn_if_fail ( proxy - > priv - > get_all_cancellable = = NULL ) ;
if ( proxy - > priv - > name_owner_changed_subscription_id > 0 )
g_dbus_connection_signal_unsubscribe ( proxy - > priv - > connection ,
proxy - > priv - > name_owner_changed_subscription_id ) ;
2011-05-26 15:26:29 +02:00
if ( proxy - > priv - > properties_changed_subscription_id > 0 )
2010-05-10 04:13:18 +02:00
g_dbus_connection_signal_unsubscribe ( proxy - > priv - > connection ,
2011-05-26 15:26:29 +02:00
proxy - > priv - > properties_changed_subscription_id ) ;
2010-05-06 20:13:59 +02:00
2011-05-26 15:26:29 +02:00
if ( proxy - > priv - > signals_subscription_id > 0 )
2010-05-10 04:13:18 +02:00
g_dbus_connection_signal_unsubscribe ( proxy - > priv - > connection ,
2011-05-26 15:26:29 +02:00
proxy - > priv - > signals_subscription_id ) ;
2010-05-06 20:13:59 +02:00
2011-03-14 19:54:46 +01:00
if ( proxy - > priv - > connection ! = NULL )
g_object_unref ( proxy - > priv - > connection ) ;
2010-06-11 21:45:18 +02:00
g_free ( proxy - > priv - > name ) ;
g_free ( proxy - > priv - > name_owner ) ;
2010-05-06 20:13:59 +02:00
g_free ( proxy - > priv - > object_path ) ;
g_free ( proxy - > priv - > interface_name ) ;
if ( proxy - > priv - > properties ! = NULL )
g_hash_table_unref ( proxy - > priv - > properties ) ;
if ( proxy - > priv - > expected_interface ! = NULL )
2011-03-28 17:34:48 +02:00
{
g_dbus_interface_info_cache_release ( proxy - > priv - > expected_interface ) ;
g_dbus_interface_info_unref ( proxy - > priv - > expected_interface ) ;
}
2010-05-06 20:13:59 +02:00
2011-04-08 22:12:33 +02:00
if ( proxy - > priv - > object ! = NULL )
g_object_remove_weak_pointer ( G_OBJECT ( proxy - > priv - > object ) , ( gpointer * ) & proxy - > priv - > object ) ;
2010-05-10 04:13:18 +02:00
G_OBJECT_CLASS ( g_dbus_proxy_parent_class ) - > finalize ( object ) ;
2010-05-06 20:13:59 +02:00
}
static void
g_dbus_proxy_get_property ( GObject * object ,
guint prop_id ,
GValue * value ,
GParamSpec * pspec )
{
GDBusProxy * proxy = G_DBUS_PROXY ( object ) ;
switch ( prop_id )
{
case PROP_G_CONNECTION :
g_value_set_object ( value , proxy - > priv - > connection ) ;
break ;
case PROP_G_FLAGS :
g_value_set_flags ( value , proxy - > priv - > flags ) ;
break ;
2010-06-11 21:45:18 +02:00
case PROP_G_NAME :
g_value_set_string ( value , proxy - > priv - > name ) ;
break ;
case PROP_G_NAME_OWNER :
g_value_set_string ( value , proxy - > priv - > name_owner ) ;
2010-05-06 20:13:59 +02:00
break ;
case PROP_G_OBJECT_PATH :
g_value_set_string ( value , proxy - > priv - > object_path ) ;
break ;
case PROP_G_INTERFACE_NAME :
g_value_set_string ( value , proxy - > priv - > interface_name ) ;
break ;
case PROP_G_DEFAULT_TIMEOUT :
g_value_set_int ( value , proxy - > priv - > timeout_msec ) ;
break ;
case PROP_G_INTERFACE_INFO :
g_value_set_boxed ( value , g_dbus_proxy_get_interface_info ( proxy ) ) ;
break ;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , prop_id , pspec ) ;
break ;
}
}
static void
g_dbus_proxy_set_property ( GObject * object ,
guint prop_id ,
const GValue * value ,
GParamSpec * pspec )
{
GDBusProxy * proxy = G_DBUS_PROXY ( object ) ;
switch ( prop_id )
{
case PROP_G_CONNECTION :
proxy - > priv - > connection = g_value_dup_object ( value ) ;
break ;
case PROP_G_FLAGS :
proxy - > priv - > flags = g_value_get_flags ( value ) ;
break ;
2010-06-11 21:45:18 +02:00
case PROP_G_NAME :
proxy - > priv - > name = g_value_dup_string ( value ) ;
2010-05-06 20:13:59 +02:00
break ;
case PROP_G_OBJECT_PATH :
proxy - > priv - > object_path = g_value_dup_string ( value ) ;
break ;
case PROP_G_INTERFACE_NAME :
proxy - > priv - > interface_name = g_value_dup_string ( value ) ;
break ;
case PROP_G_DEFAULT_TIMEOUT :
g_dbus_proxy_set_default_timeout ( proxy , g_value_get_int ( value ) ) ;
break ;
case PROP_G_INTERFACE_INFO :
g_dbus_proxy_set_interface_info ( proxy , g_value_get_boxed ( value ) ) ;
break ;
2010-06-11 21:45:18 +02:00
case PROP_G_BUS_TYPE :
proxy - > priv - > bus_type = g_value_get_enum ( value ) ;
break ;
2010-05-06 20:13:59 +02:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , prop_id , pspec ) ;
break ;
}
}
static void
g_dbus_proxy_class_init ( GDBusProxyClass * klass )
{
GObjectClass * gobject_class = G_OBJECT_CLASS ( klass ) ;
2011-05-26 15:26:29 +02:00
gobject_class - > dispose = g_dbus_proxy_dispose ;
2010-05-06 20:13:59 +02:00
gobject_class - > finalize = g_dbus_proxy_finalize ;
gobject_class - > set_property = g_dbus_proxy_set_property ;
gobject_class - > get_property = g_dbus_proxy_get_property ;
/* Note that all property names are prefixed to avoid collisions with D-Bus property names
* in derived classes */
/**
* GDBusProxy : g - interface - info :
*
* Ensure that interactions with this proxy conform to the given
* interface . For example , when completing a method call , if the
* type signature of the message isn ' t what ' s expected , the given
* # GError is set . Signals that have a type signature mismatch are
* simply dropped .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
g_object_class_install_property ( gobject_class ,
PROP_G_INTERFACE_INFO ,
g_param_spec_boxed ( " g-interface-info " ,
2010-05-10 04:13:18 +02:00
P_ ( " Interface Information " ) ,
P_ ( " Interface Information " ) ,
2010-05-06 20:13:59 +02:00
G_TYPE_DBUS_INTERFACE_INFO ,
G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK ) ) ;
/**
* GDBusProxy : g - connection :
*
* The # GDBusConnection the proxy is for .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
g_object_class_install_property ( gobject_class ,
PROP_G_CONNECTION ,
g_param_spec_object ( " g-connection " ,
2010-05-10 04:13:18 +02:00
P_ ( " g-connection " ) ,
P_ ( " The connection the proxy is for " ) ,
2010-05-06 20:13:59 +02:00
G_TYPE_DBUS_CONNECTION ,
G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK ) ) ;
2010-06-11 21:45:18 +02:00
/**
* GDBusProxy : g - bus - type :
*
* If this property is not % G_BUS_TYPE_NONE , then
* # GDBusProxy : g - connection must be % NULL and will be set to the
* # GDBusConnection obtained by calling g_bus_get ( ) with the value
* of this property .
*
* Since : 2.26
*/
g_object_class_install_property ( gobject_class ,
PROP_G_BUS_TYPE ,
g_param_spec_enum ( " g-bus-type " ,
P_ ( " Bus Type " ) ,
P_ ( " The bus to connect to, if any " ) ,
G_TYPE_BUS_TYPE ,
G_BUS_TYPE_NONE ,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK ) ) ;
2010-05-06 20:13:59 +02:00
/**
* GDBusProxy : g - flags :
*
* Flags from the # GDBusProxyFlags enumeration .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
g_object_class_install_property ( gobject_class ,
PROP_G_FLAGS ,
g_param_spec_flags ( " g-flags " ,
2010-05-10 04:13:18 +02:00
P_ ( " g-flags " ) ,
P_ ( " Flags for the proxy " ) ,
2010-05-06 20:13:59 +02:00
G_TYPE_DBUS_PROXY_FLAGS ,
G_DBUS_PROXY_FLAGS_NONE ,
G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK ) ) ;
/**
2010-06-11 21:45:18 +02:00
* GDBusProxy : g - name :
2010-05-06 20:13:59 +02:00
*
2010-06-11 21:45:18 +02:00
* The well - known or unique name that the proxy is for .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
g_object_class_install_property ( gobject_class ,
2010-06-11 21:45:18 +02:00
PROP_G_NAME ,
g_param_spec_string ( " g-name " ,
P_ ( " g-name " ) ,
P_ ( " The well-known or unique name that the proxy is for " ) ,
2010-05-06 20:13:59 +02:00
NULL ,
G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK ) ) ;
2010-06-11 21:45:18 +02:00
/**
* GDBusProxy : g - name - owner :
*
* The unique name that owns # GDBusProxy : name or % NULL if no - one
* currently owns that name . You may connect to # GObject : : notify signal to
* track changes to this property .
*
* Since : 2.26
*/
g_object_class_install_property ( gobject_class ,
PROP_G_NAME_OWNER ,
g_param_spec_string ( " g-name-owner " ,
P_ ( " g-name-owner " ) ,
P_ ( " The unique name for the owner " ) ,
NULL ,
G_PARAM_READABLE |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK ) ) ;
2010-05-06 20:13:59 +02:00
/**
* GDBusProxy : g - object - path :
*
* The object path the proxy is for .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
g_object_class_install_property ( gobject_class ,
PROP_G_OBJECT_PATH ,
g_param_spec_string ( " g-object-path " ,
2010-05-10 04:13:18 +02:00
P_ ( " g-object-path " ) ,
P_ ( " The object path the proxy is for " ) ,
2010-05-06 20:13:59 +02:00
NULL ,
G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK ) ) ;
/**
* GDBusProxy : g - interface - name :
*
* The D - Bus interface name the proxy is for .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
g_object_class_install_property ( gobject_class ,
PROP_G_INTERFACE_NAME ,
g_param_spec_string ( " g-interface-name " ,
2010-05-10 04:13:18 +02:00
P_ ( " g-interface-name " ) ,
P_ ( " The D-Bus interface name the proxy is for " ) ,
2010-05-06 20:13:59 +02:00
NULL ,
G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK ) ) ;
/**
* GDBusProxy : g - default - timeout :
*
* The timeout to use if - 1 ( specifying default timeout ) is passed
2010-05-10 17:47:08 +02:00
* as @ timeout_msec in the g_dbus_proxy_call ( ) and
* g_dbus_proxy_call_sync ( ) functions .
2010-05-06 20:13:59 +02:00
*
* This allows applications to set a proxy - wide timeout for all
* remote method invocations on the proxy . If this property is - 1 ,
* the default timeout ( typically 25 seconds ) is used . If set to
* % G_MAXINT , then no timeout is used .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
g_object_class_install_property ( gobject_class ,
PROP_G_DEFAULT_TIMEOUT ,
g_param_spec_int ( " g-default-timeout " ,
2010-05-10 04:13:18 +02:00
P_ ( " Default Timeout " ) ,
P_ ( " Timeout for remote method invocation " ) ,
2010-05-06 20:13:59 +02:00
- 1 ,
G_MAXINT ,
- 1 ,
G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK ) ) ;
/**
* GDBusProxy : : g - properties - changed :
* @ proxy : The # GDBusProxy emitting the signal .
2010-05-13 22:57:29 +02:00
* @ changed_properties : A # GVariant containing the properties that changed
* @ invalidated_properties : A % NULL terminated array of properties that was invalidated
2010-05-06 20:13:59 +02:00
*
2010-05-13 17:56:15 +02:00
* Emitted when one or more D - Bus properties on @ proxy changes . The
2010-05-13 22:57:29 +02:00
* local cache has already been updated when this signal fires . Note
* that both @ changed_properties and @ invalidated_properties are
* guaranteed to never be % NULL ( either may be empty though ) .
2010-05-13 17:56:15 +02:00
*
* This signal corresponds to the
* < literal > PropertiesChanged < / literal > D - Bus signal on the
* < literal > org . freedesktop . DBus . Properties < / literal > interface .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
signals [ PROPERTIES_CHANGED_SIGNAL ] = g_signal_new ( " g-properties-changed " ,
G_TYPE_DBUS_PROXY ,
2011-03-04 18:21:51 +01:00
G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT ,
2010-05-06 20:13:59 +02:00
G_STRUCT_OFFSET ( GDBusProxyClass , g_properties_changed ) ,
NULL ,
NULL ,
2010-06-17 21:27:18 +02:00
_gio_marshal_VOID__VARIANT_BOXED ,
2010-05-06 20:13:59 +02:00
G_TYPE_NONE ,
2010-05-13 17:56:15 +02:00
2 ,
G_TYPE_VARIANT ,
2010-05-13 19:01:04 +02:00
G_TYPE_STRV | G_SIGNAL_TYPE_STATIC_SCOPE ) ;
2010-05-06 20:13:59 +02:00
/**
* GDBusProxy : : g - signal :
* @ proxy : The # GDBusProxy emitting the signal .
* @ sender_name : The sender of the signal or % NULL if the connection is not a bus connection .
* @ signal_name : The name of the signal .
* @ parameters : A # GVariant tuple with parameters for the signal .
*
* Emitted when a signal from the remote object and interface that @ proxy is for , has been received .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
*/
2010-05-06 20:13:59 +02:00
signals [ SIGNAL_SIGNAL ] = g_signal_new ( " g-signal " ,
G_TYPE_DBUS_PROXY ,
2011-03-04 18:21:51 +01:00
G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT ,
2010-05-06 20:13:59 +02:00
G_STRUCT_OFFSET ( GDBusProxyClass , g_signal ) ,
NULL ,
NULL ,
2010-06-17 21:27:18 +02:00
_gio_marshal_VOID__STRING_STRING_VARIANT ,
2010-05-06 20:13:59 +02:00
G_TYPE_NONE ,
3 ,
G_TYPE_STRING ,
G_TYPE_STRING ,
G_TYPE_VARIANT ) ;
g_type_class_add_private ( klass , sizeof ( GDBusProxyPrivate ) ) ;
}
static void
g_dbus_proxy_init ( GDBusProxy * proxy )
{
proxy - > priv = G_TYPE_INSTANCE_GET_PRIVATE ( proxy , G_TYPE_DBUS_PROXY , GDBusProxyPrivate ) ;
2011-05-26 15:26:29 +02:00
proxy - > priv - > signal_subscription_data = g_slice_new0 ( SignalSubscriptionData ) ;
proxy - > priv - > signal_subscription_data - > ref_count = 1 ;
proxy - > priv - > signal_subscription_data - > proxy = proxy ;
2010-05-13 23:10:15 +02:00
proxy - > priv - > properties = g_hash_table_new_full ( g_str_hash ,
g_str_equal ,
g_free ,
( GDestroyNotify ) g_variant_unref ) ;
2010-05-06 20:13:59 +02:00
}
/* ---------------------------------------------------------------------------------------------------- */
2010-07-30 22:33:29 +02:00
static gint
property_name_sort_func ( const gchar * * a ,
const gchar * * b )
{
return g_strcmp0 ( * a , * b ) ;
}
2010-05-06 20:13:59 +02:00
/**
* g_dbus_proxy_get_cached_property_names :
* @ proxy : A # GDBusProxy .
*
* Gets the names of all cached properties on @ proxy .
*
2010-05-13 23:10:15 +02:00
* Returns : A % NULL - terminated array of strings or % NULL if @ proxy has
* no cached properties . Free the returned array with g_strfreev ( ) .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
gchar * *
2010-05-13 23:10:15 +02:00
g_dbus_proxy_get_cached_property_names ( GDBusProxy * proxy )
2010-05-06 20:13:59 +02:00
{
gchar * * names ;
GPtrArray * p ;
GHashTableIter iter ;
const gchar * key ;
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , NULL ) ;
2011-05-26 15:54:47 +02:00
G_LOCK ( properties_lock ) ;
2010-05-06 20:13:59 +02:00
names = NULL ;
2010-05-13 23:10:15 +02:00
if ( g_hash_table_size ( proxy - > priv - > properties ) = = 0 )
goto out ;
2010-05-06 20:13:59 +02:00
p = g_ptr_array_new ( ) ;
g_hash_table_iter_init ( & iter , proxy - > priv - > properties ) ;
while ( g_hash_table_iter_next ( & iter , ( gpointer ) & key , NULL ) )
2010-05-10 04:13:18 +02:00
g_ptr_array_add ( p , g_strdup ( key ) ) ;
2010-07-30 22:33:29 +02:00
g_ptr_array_sort ( p , ( GCompareFunc ) property_name_sort_func ) ;
2010-05-06 20:13:59 +02:00
g_ptr_array_add ( p , NULL ) ;
names = ( gchar * * ) g_ptr_array_free ( p , FALSE ) ;
out :
2011-05-26 15:54:47 +02:00
G_UNLOCK ( properties_lock ) ;
2010-05-06 20:13:59 +02:00
return names ;
}
2010-05-13 02:43:40 +02:00
static const GDBusPropertyInfo *
lookup_property_info_or_warn ( GDBusProxy * proxy ,
const gchar * property_name )
{
const GDBusPropertyInfo * info ;
if ( proxy - > priv - > expected_interface = = NULL )
return NULL ;
info = g_dbus_interface_info_lookup_property ( proxy - > priv - > expected_interface , property_name ) ;
if ( info = = NULL )
{
g_warning ( " Trying to lookup property %s which isn't in expected interface %s " ,
property_name ,
proxy - > priv - > expected_interface - > name ) ;
}
return info ;
}
2010-05-06 20:13:59 +02:00
/**
* g_dbus_proxy_get_cached_property :
* @ proxy : A # GDBusProxy .
* @ property_name : Property name .
*
2010-05-13 02:43:40 +02:00
* Looks up the value for a property from the cache . This call does no
* blocking IO .
2010-05-06 20:13:59 +02:00
*
2010-05-13 02:43:40 +02:00
* If @ proxy has an expected interface ( see
* # GDBusProxy : g - interface - info ) , then @ property_name ( for existence )
* is checked against it .
2010-05-06 20:13:59 +02:00
*
2010-05-13 02:43:40 +02:00
* Returns : A reference to the # GVariant instance that holds the value
* for @ property_name or % NULL if the value is not in the cache . The
* returned reference must be freed with g_variant_unref ( ) .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
GVariant *
2010-05-10 04:13:18 +02:00
g_dbus_proxy_get_cached_property ( GDBusProxy * proxy ,
2010-05-13 02:43:40 +02:00
const gchar * property_name )
2010-05-06 20:13:59 +02:00
{
GVariant * value ;
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , NULL ) ;
g_return_val_if_fail ( property_name ! = NULL , NULL ) ;
2011-05-26 15:54:47 +02:00
G_LOCK ( properties_lock ) ;
2010-05-06 20:13:59 +02:00
value = g_hash_table_lookup ( proxy - > priv - > properties , property_name ) ;
if ( value = = NULL )
{
2011-04-08 21:44:25 +02:00
lookup_property_info_or_warn ( proxy , property_name ) ;
2010-05-13 02:43:40 +02:00
/* no difference */
2010-05-06 20:13:59 +02:00
goto out ;
}
g_variant_ref ( value ) ;
out :
2011-05-26 15:54:47 +02:00
G_UNLOCK ( properties_lock ) ;
2010-05-06 20:13:59 +02:00
return value ;
}
2010-05-13 02:43:40 +02:00
/**
* g_dbus_proxy_set_cached_property :
* @ proxy : A # GDBusProxy
* @ property_name : Property name .
2011-03-30 19:52:31 +02:00
* @ value : ( allow - none ) : Value for the property or % NULL to remove it from the cache .
2010-05-13 02:43:40 +02:00
*
* If @ value is not % NULL , sets the cached value for the property with
* name @ property_name to the value in @ value .
*
* If @ value is % NULL , then the cached value is removed from the
* property cache .
*
* If @ proxy has an expected interface ( see
* # GDBusProxy : g - interface - info ) , then @ property_name ( for existence )
* and @ value ( for the type ) is checked against it .
*
* If the @ value # GVariant is floating , it is consumed . This allows
* convenient ' inline ' use of g_variant_new ( ) , e . g .
* | [
* g_dbus_proxy_set_cached_property ( proxy ,
* " SomeProperty " ,
* g_variant_new ( " (si) " ,
* " A String " ,
* 42 ) ) ;
* ] |
*
* Normally you will not need to use this method since @ proxy is
* tracking changes using the
* < literal > org . freedesktop . DBus . Properties . PropertiesChanged < / literal >
* D - Bus signal . However , for performance reasons an object may decide
* to not use this signal for some properties and instead use a
* proprietary out - of - band mechanism to transmit changes .
*
* As a concrete example , consider an object with a property
* < literal > ChatroomParticipants < / literal > which is an array of
* strings . Instead of transmitting the same ( long ) array every time
* the property changes , it is more efficient to only transmit the
* delta using e . g . signals < literal > ChatroomParticipantJoined ( String
* name ) < / literal > and < literal > ChatroomParticipantParted ( String
* name ) < / literal > .
*
* Since : 2.26
*/
void
g_dbus_proxy_set_cached_property ( GDBusProxy * proxy ,
const gchar * property_name ,
GVariant * value )
{
const GDBusPropertyInfo * info ;
g_return_if_fail ( G_IS_DBUS_PROXY ( proxy ) ) ;
g_return_if_fail ( property_name ! = NULL ) ;
2011-05-26 15:54:47 +02:00
G_LOCK ( properties_lock ) ;
2010-05-13 02:43:40 +02:00
if ( value ! = NULL )
{
info = lookup_property_info_or_warn ( proxy , property_name ) ;
if ( info ! = NULL )
{
if ( g_strcmp0 ( info - > signature , g_variant_get_type_string ( value ) ) ! = 0 )
{
2011-04-29 16:59:42 +02:00
g_warning ( " Trying to set property %s of type %s but according to the expected "
" interface the type is %s " ,
2010-05-13 02:43:40 +02:00
property_name ,
g_variant_get_type_string ( value ) ,
info - > signature ) ;
goto out ;
}
}
g_hash_table_insert ( proxy - > priv - > properties ,
g_strdup ( property_name ) ,
g_variant_ref_sink ( value ) ) ;
}
else
{
g_hash_table_remove ( proxy - > priv - > properties , property_name ) ;
}
out :
2011-05-26 15:54:47 +02:00
G_UNLOCK ( properties_lock ) ;
2010-05-13 02:43:40 +02:00
}
2010-05-06 20:13:59 +02:00
/* ---------------------------------------------------------------------------------------------------- */
static void
2010-05-10 04:13:18 +02:00
on_signal_received ( GDBusConnection * connection ,
const gchar * sender_name ,
const gchar * object_path ,
const gchar * interface_name ,
const gchar * signal_name ,
GVariant * parameters ,
gpointer user_data )
2010-05-06 20:13:59 +02:00
{
2011-05-26 15:26:29 +02:00
SignalSubscriptionData * data = user_data ;
GDBusProxy * proxy ;
G_LOCK ( signal_subscription_lock ) ;
proxy = data - > proxy ;
if ( proxy = = NULL )
2011-05-26 16:07:38 +02:00
{
G_UNLOCK ( signal_subscription_lock ) ;
goto out ;
}
else
{
g_object_ref ( proxy ) ;
G_UNLOCK ( signal_subscription_lock ) ;
}
2010-05-06 20:13:59 +02:00
2010-05-13 23:20:39 +02:00
if ( ! proxy - > priv - > initialized )
goto out ;
2010-07-14 17:14:58 +02:00
if ( proxy - > priv - > name_owner ! = NULL & & g_strcmp0 ( sender_name , proxy - > priv - > name_owner ) ! = 0 )
2010-06-11 21:45:18 +02:00
goto out ;
2011-03-28 18:10:25 +02:00
if ( proxy - > priv - > expected_interface ! = NULL )
{
const GDBusSignalInfo * info ;
2011-03-28 19:04:34 +02:00
GVariantType * expected_type ;
2011-03-28 18:10:25 +02:00
info = g_dbus_interface_info_lookup_signal ( proxy - > priv - > expected_interface , signal_name ) ;
if ( info = = NULL )
goto out ;
2011-03-28 19:04:34 +02:00
expected_type = _g_dbus_compute_complete_signature ( info - > args ) ;
if ( ! g_variant_type_equal ( expected_type , g_variant_get_type ( parameters ) ) )
{
g_variant_type_free ( expected_type ) ;
goto out ;
}
g_variant_type_free ( expected_type ) ;
2011-03-28 18:10:25 +02:00
}
2010-05-06 20:13:59 +02:00
g_signal_emit ( proxy ,
signals [ SIGNAL_SIGNAL ] ,
0 ,
sender_name ,
signal_name ,
parameters ) ;
2010-05-13 23:20:39 +02:00
out :
2011-05-26 15:26:29 +02:00
if ( proxy ! = NULL )
g_object_unref ( proxy ) ;
2010-05-06 20:13:59 +02:00
}
/* ---------------------------------------------------------------------------------------------------- */
2011-05-26 15:54:47 +02:00
/* must hold properties_lock */
2011-02-19 02:34:06 +01:00
static void
insert_property_checked ( GDBusProxy * proxy ,
gchar * property_name ,
GVariant * value )
{
if ( proxy - > priv - > expected_interface ! = NULL )
{
const GDBusPropertyInfo * info ;
info = g_dbus_interface_info_lookup_property ( proxy - > priv - > expected_interface , property_name ) ;
/* Ignore unknown properties */
if ( info = = NULL )
goto invalid ;
/* Ignore properties with the wrong type */
if ( g_strcmp0 ( info - > signature , g_variant_get_type_string ( value ) ) ! = 0 )
goto invalid ;
}
g_hash_table_insert ( proxy - > priv - > properties ,
property_name , /* adopts string */
value ) ; /* adopts value */
return ;
invalid :
g_variant_unref ( value ) ;
g_free ( property_name ) ;
}
2010-05-06 20:13:59 +02:00
static void
2010-05-10 04:13:18 +02:00
on_properties_changed ( GDBusConnection * connection ,
const gchar * sender_name ,
const gchar * object_path ,
const gchar * interface_name ,
const gchar * signal_name ,
GVariant * parameters ,
gpointer user_data )
2010-05-06 20:13:59 +02:00
{
2011-05-26 15:26:29 +02:00
SignalSubscriptionData * data = user_data ;
GDBusProxy * proxy ;
2010-05-06 20:13:59 +02:00
const gchar * interface_name_for_signal ;
2010-05-10 19:31:54 +02:00
GVariant * changed_properties ;
2010-05-13 17:56:15 +02:00
gchar * * invalidated_properties ;
2010-05-13 19:01:04 +02:00
GVariantIter iter ;
gchar * key ;
GVariant * value ;
2010-05-14 18:55:25 +02:00
guint n ;
2010-05-06 20:13:59 +02:00
2011-05-26 15:26:29 +02:00
G_LOCK ( signal_subscription_lock ) ;
proxy = data - > proxy ;
if ( proxy = = NULL )
2011-05-26 16:07:38 +02:00
{
G_UNLOCK ( signal_subscription_lock ) ;
goto out ;
}
else
{
g_object_ref ( proxy ) ;
G_UNLOCK ( signal_subscription_lock ) ;
}
2011-05-26 15:26:29 +02:00
2010-05-13 23:20:39 +02:00
changed_properties = NULL ;
invalidated_properties = NULL ;
2010-05-06 20:13:59 +02:00
2010-05-13 23:20:39 +02:00
if ( ! proxy - > priv - > initialized )
goto out ;
2010-05-06 20:13:59 +02:00
2010-07-14 17:14:58 +02:00
if ( proxy - > priv - > name_owner ! = NULL & & g_strcmp0 ( sender_name , proxy - > priv - > name_owner ) ! = 0 )
2010-06-11 21:45:18 +02:00
goto out ;
2010-05-13 19:01:04 +02:00
if ( ! g_variant_is_of_type ( parameters , G_VARIANT_TYPE ( " (sa{sv}as) " ) ) )
2010-05-06 20:13:59 +02:00
{
2010-05-13 17:56:15 +02:00
g_warning ( " Value for PropertiesChanged signal with type `%s' does not match `(sa{sv}as)' " ,
2010-05-06 20:13:59 +02:00
g_variant_get_type_string ( parameters ) ) ;
2010-05-13 23:20:39 +02:00
goto out ;
2010-05-06 20:13:59 +02:00
}
g_variant_get ( parameters ,
2010-05-13 19:01:04 +02:00
" (&s@a{sv}^a&s) " ,
2010-05-06 20:13:59 +02:00
& interface_name_for_signal ,
2010-05-13 19:01:04 +02:00
& changed_properties ,
& invalidated_properties ) ;
2010-05-06 20:13:59 +02:00
if ( g_strcmp0 ( interface_name_for_signal , proxy - > priv - > interface_name ) ! = 0 )
goto out ;
2011-05-26 15:54:47 +02:00
G_LOCK ( properties_lock ) ;
2010-05-13 19:01:04 +02:00
g_variant_iter_init ( & iter , changed_properties ) ;
while ( g_variant_iter_next ( & iter , " {sv} " , & key , & value ) )
2010-05-06 20:13:59 +02:00
{
2011-02-19 02:34:06 +01:00
insert_property_checked ( proxy ,
key , /* adopts string */
value ) ; /* adopts value */
2010-05-06 20:13:59 +02:00
}
2010-05-14 18:55:25 +02:00
for ( n = 0 ; invalidated_properties [ n ] ! = NULL ; n + + )
{
g_hash_table_remove ( proxy - > priv - > properties , invalidated_properties [ n ] ) ;
}
2011-05-26 15:54:47 +02:00
G_UNLOCK ( properties_lock ) ;
2010-05-06 20:13:59 +02:00
/* emit signal */
2010-05-13 17:56:15 +02:00
g_signal_emit ( proxy , signals [ PROPERTIES_CHANGED_SIGNAL ] ,
0 ,
changed_properties ,
invalidated_properties ) ;
2010-05-06 20:13:59 +02:00
out :
2010-05-13 23:20:39 +02:00
if ( changed_properties ! = NULL )
g_variant_unref ( changed_properties ) ;
2010-05-13 19:01:04 +02:00
g_free ( invalidated_properties ) ;
2011-05-26 15:26:29 +02:00
if ( proxy ! = NULL )
g_object_unref ( proxy ) ;
2010-05-06 20:13:59 +02:00
}
/* ---------------------------------------------------------------------------------------------------- */
static void
process_get_all_reply ( GDBusProxy * proxy ,
GVariant * result )
{
2010-05-15 00:08:29 +02:00
GVariantIter * iter ;
gchar * key ;
GVariant * value ;
2011-05-26 15:54:47 +02:00
guint num_properties ;
2010-05-06 20:13:59 +02:00
2010-07-07 15:50:44 +02:00
if ( ! g_variant_is_of_type ( result , G_VARIANT_TYPE ( " (a{sv}) " ) ) )
2010-05-06 20:13:59 +02:00
{
g_warning ( " Value for GetAll reply with type `%s' does not match `(a{sv})' " ,
g_variant_get_type_string ( result ) ) ;
goto out ;
}
2011-05-26 15:54:47 +02:00
G_LOCK ( properties_lock ) ;
2010-05-15 00:08:29 +02:00
g_variant_get ( result , " (a{sv}) " , & iter ) ;
while ( g_variant_iter_next ( iter , " {sv} " , & key , & value ) )
2010-05-06 20:13:59 +02:00
{
2011-02-19 02:34:06 +01:00
insert_property_checked ( proxy ,
key , /* adopts string */
value ) ; /* adopts value */
2010-05-06 20:13:59 +02:00
}
2010-05-15 00:08:29 +02:00
g_variant_iter_free ( iter ) ;
2011-05-26 15:54:47 +02:00
num_properties = g_hash_table_size ( proxy - > priv - > properties ) ;
G_UNLOCK ( properties_lock ) ;
2010-07-07 15:50:44 +02:00
/* Synthesize ::g-properties-changed changed */
2011-05-26 15:54:47 +02:00
if ( num_properties > 0 )
2010-07-07 15:50:44 +02:00
{
GVariant * changed_properties ;
const gchar * invalidated_properties [ 1 ] = { NULL } ;
g_variant_get ( result ,
" (@a{sv}) " ,
& changed_properties ) ;
g_signal_emit ( proxy , signals [ PROPERTIES_CHANGED_SIGNAL ] ,
0 ,
changed_properties ,
invalidated_properties ) ;
g_variant_unref ( changed_properties ) ;
}
2010-05-06 20:13:59 +02:00
out :
;
}
2010-06-11 21:45:18 +02:00
typedef struct
2010-05-06 20:13:59 +02:00
{
2010-06-11 21:45:18 +02:00
GDBusProxy * proxy ;
GCancellable * cancellable ;
gchar * name_owner ;
} LoadPropertiesOnNameOwnerChangedData ;
static void
on_name_owner_changed_get_all_cb ( GDBusConnection * connection ,
GAsyncResult * res ,
gpointer user_data )
{
LoadPropertiesOnNameOwnerChangedData * data = user_data ;
2010-05-06 20:13:59 +02:00
GVariant * result ;
2010-06-11 21:45:18 +02:00
GError * error ;
gboolean cancelled ;
2010-05-06 20:13:59 +02:00
2010-06-11 21:45:18 +02:00
cancelled = FALSE ;
2010-05-06 20:13:59 +02:00
2010-06-11 21:45:18 +02:00
error = NULL ;
result = g_dbus_connection_call_finish ( connection ,
res ,
& error ) ;
if ( result = = NULL )
{
if ( error - > domain = = G_IO_ERROR & & error - > code = = G_IO_ERROR_CANCELLED )
cancelled = TRUE ;
/* We just ignore if GetAll() is failing. Because this might happen
* if the object has no properties at all . Or if the caller is
* not authorized to see the properties .
*
* Either way , apps can know about this by using
* get_cached_property_names ( ) or get_cached_property ( ) .
*
* TODO : handle G_DBUS_DEBUG flag ' proxy ' and , if enabled , log the
* fact that GetAll ( ) failed
*/
//g_debug ("error: %d %d %s", error->domain, error->code, error->message);
g_error_free ( error ) ;
}
2010-05-13 23:20:39 +02:00
2010-06-11 21:45:18 +02:00
/* and finally we can notify */
if ( ! cancelled )
2010-05-06 20:13:59 +02:00
{
2010-06-11 21:45:18 +02:00
g_free ( data - > proxy - > priv - > name_owner ) ;
data - > proxy - > priv - > name_owner = data - > name_owner ;
data - > name_owner = NULL ; /* to avoid an extra copy, we steal the string */
2011-05-26 15:54:47 +02:00
G_LOCK ( properties_lock ) ;
2010-06-11 21:45:18 +02:00
g_hash_table_remove_all ( data - > proxy - > priv - > properties ) ;
2011-05-26 15:54:47 +02:00
G_UNLOCK ( properties_lock ) ;
2010-06-11 21:45:18 +02:00
if ( result ! = NULL )
2010-06-09 16:56:35 +02:00
{
2010-06-11 21:45:18 +02:00
process_get_all_reply ( data - > proxy , result ) ;
g_variant_unref ( result ) ;
2010-06-09 16:56:35 +02:00
}
2010-05-06 20:13:59 +02:00
2010-06-11 21:45:18 +02:00
g_object_notify ( G_OBJECT ( data - > proxy ) , " g-name-owner " ) ;
2010-05-06 20:13:59 +02:00
}
2010-06-11 21:45:18 +02:00
if ( data - > cancellable = = data - > proxy - > priv - > get_all_cancellable )
data - > proxy - > priv - > get_all_cancellable = NULL ;
2010-05-06 20:13:59 +02:00
2010-06-11 21:45:18 +02:00
g_object_unref ( data - > proxy ) ;
g_object_unref ( data - > cancellable ) ;
g_free ( data - > name_owner ) ;
g_free ( data ) ;
2010-05-06 20:13:59 +02:00
}
static void
2010-06-11 21:45:18 +02:00
on_name_owner_changed ( GDBusConnection * connection ,
const gchar * sender_name ,
const gchar * object_path ,
const gchar * interface_name ,
const gchar * signal_name ,
GVariant * parameters ,
gpointer user_data )
2010-05-06 20:13:59 +02:00
{
2011-05-26 15:26:29 +02:00
SignalSubscriptionData * data = user_data ;
GDBusProxy * proxy ;
2010-06-11 21:45:18 +02:00
const gchar * old_owner ;
const gchar * new_owner ;
2011-05-26 15:26:29 +02:00
G_LOCK ( signal_subscription_lock ) ;
proxy = data - > proxy ;
if ( proxy = = NULL )
2011-05-26 16:07:38 +02:00
{
G_UNLOCK ( signal_subscription_lock ) ;
goto out ;
}
else
{
g_object_ref ( proxy ) ;
G_UNLOCK ( signal_subscription_lock ) ;
}
2011-05-26 15:26:29 +02:00
2010-06-11 21:45:18 +02:00
/* if we are already trying to load properties, cancel that */
if ( proxy - > priv - > get_all_cancellable ! = NULL )
{
g_cancellable_cancel ( proxy - > priv - > get_all_cancellable ) ;
proxy - > priv - > get_all_cancellable = NULL ;
}
g_variant_get ( parameters ,
" (&s&s&s) " ,
2010-07-07 15:05:42 +02:00
NULL ,
2010-06-11 21:45:18 +02:00
& old_owner ,
& new_owner ) ;
if ( strlen ( new_owner ) = = 0 )
{
g_free ( proxy - > priv - > name_owner ) ;
proxy - > priv - > name_owner = NULL ;
2010-07-07 15:50:44 +02:00
2011-05-26 15:54:47 +02:00
G_LOCK ( properties_lock ) ;
2010-07-07 15:50:44 +02:00
/* Synthesize ::g-properties-changed changed */
if ( ! ( proxy - > priv - > flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES ) & &
g_hash_table_size ( proxy - > priv - > properties ) > 0 )
{
GVariantBuilder builder ;
GPtrArray * invalidated_properties ;
GHashTableIter iter ;
const gchar * key ;
/* Build changed_properties (always empty) and invalidated_properties ... */
g_variant_builder_init ( & builder , G_VARIANT_TYPE ( " a{sv} " ) ) ;
2011-03-04 18:21:51 +01:00
2010-07-07 15:50:44 +02:00
invalidated_properties = g_ptr_array_new_with_free_func ( g_free ) ;
g_hash_table_iter_init ( & iter , proxy - > priv - > properties ) ;
while ( g_hash_table_iter_next ( & iter , ( gpointer ) & key , NULL ) )
g_ptr_array_add ( invalidated_properties , g_strdup ( key ) ) ;
g_ptr_array_add ( invalidated_properties , NULL ) ;
/* ... throw out the properties ... */
g_hash_table_remove_all ( proxy - > priv - > properties ) ;
2011-05-26 15:54:47 +02:00
G_UNLOCK ( properties_lock ) ;
2010-07-07 15:50:44 +02:00
/* ... and finally emit the ::g-properties-changed signal */
g_signal_emit ( proxy , signals [ PROPERTIES_CHANGED_SIGNAL ] ,
0 ,
2011-03-04 18:21:51 +01:00
g_variant_builder_end ( & builder ) /* consumed */ ,
2010-07-07 15:50:44 +02:00
( const gchar * const * ) invalidated_properties - > pdata ) ;
g_ptr_array_unref ( invalidated_properties ) ;
}
2011-05-26 15:54:47 +02:00
else
{
G_UNLOCK ( properties_lock ) ;
}
2010-06-11 21:45:18 +02:00
g_object_notify ( G_OBJECT ( proxy ) , " g-name-owner " ) ;
}
else
{
/* ignore duplicates - this can happen when activating the service */
if ( g_strcmp0 ( new_owner , proxy - > priv - > name_owner ) = = 0 )
goto out ;
if ( proxy - > priv - > flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES )
{
g_free ( proxy - > priv - > name_owner ) ;
proxy - > priv - > name_owner = g_strdup ( new_owner ) ;
2011-05-26 15:54:47 +02:00
G_LOCK ( properties_lock ) ;
2010-06-11 21:45:18 +02:00
g_hash_table_remove_all ( proxy - > priv - > properties ) ;
2011-05-26 15:54:47 +02:00
G_UNLOCK ( properties_lock ) ;
2010-06-11 21:45:18 +02:00
g_object_notify ( G_OBJECT ( proxy ) , " g-name-owner " ) ;
}
else
{
LoadPropertiesOnNameOwnerChangedData * data ;
/* start loading properties.. only then emit notify::g-name-owner .. we
* need to be able to cancel this in the event another NameOwnerChanged
* signal suddenly happens
*/
g_assert ( proxy - > priv - > get_all_cancellable = = NULL ) ;
proxy - > priv - > get_all_cancellable = g_cancellable_new ( ) ;
data = g_new0 ( LoadPropertiesOnNameOwnerChangedData , 1 ) ;
data - > proxy = g_object_ref ( proxy ) ;
data - > cancellable = proxy - > priv - > get_all_cancellable ;
data - > name_owner = g_strdup ( new_owner ) ;
g_dbus_connection_call ( proxy - > priv - > connection ,
data - > name_owner ,
proxy - > priv - > object_path ,
" org.freedesktop.DBus.Properties " ,
" GetAll " ,
g_variant_new ( " (s) " , proxy - > priv - > interface_name ) ,
G_VARIANT_TYPE ( " (a{sv}) " ) ,
G_DBUS_CALL_FLAGS_NONE ,
- 1 , /* timeout */
proxy - > priv - > get_all_cancellable ,
( GAsyncReadyCallback ) on_name_owner_changed_get_all_cb ,
data ) ;
}
}
out :
2011-05-26 15:26:29 +02:00
if ( proxy ! = NULL )
g_object_unref ( proxy ) ;
2010-05-06 20:13:59 +02:00
}
/* ---------------------------------------------------------------------------------------------------- */
2010-06-11 21:45:18 +02:00
typedef struct
{
GDBusProxy * proxy ;
GCancellable * cancellable ;
GSimpleAsyncResult * simple ;
} AsyncInitData ;
2010-05-06 20:13:59 +02:00
static void
2010-06-11 21:45:18 +02:00
async_init_data_free ( AsyncInitData * data )
2010-05-06 20:13:59 +02:00
{
2010-06-11 21:45:18 +02:00
g_object_unref ( data - > proxy ) ;
if ( data - > cancellable ! = NULL )
g_object_unref ( data - > cancellable ) ;
g_object_unref ( data - > simple ) ;
g_free ( data ) ;
}
static void
async_init_get_all_cb ( GDBusConnection * connection ,
GAsyncResult * res ,
gpointer user_data )
{
AsyncInitData * data = user_data ;
2010-05-06 20:13:59 +02:00
GVariant * result ;
GError * error ;
error = NULL ;
2010-05-10 17:47:08 +02:00
result = g_dbus_connection_call_finish ( connection ,
res ,
& error ) ;
2010-05-06 20:13:59 +02:00
if ( result = = NULL )
{
2010-06-09 16:56:35 +02:00
/* We just ignore if GetAll() is failing. Because this might happen
* if the object has no properties at all . Or if the caller is
* not authorized to see the properties .
*
* Either way , apps can know about this by using
* get_cached_property_names ( ) or get_cached_property ( ) .
*
* TODO : handle G_DBUS_DEBUG flag ' proxy ' and , if enabled , log the
* fact that GetAll ( ) failed
*/
//g_debug ("error: %d %d %s", error->domain, error->code, error->message);
2010-05-06 20:13:59 +02:00
g_error_free ( error ) ;
}
else
{
2010-06-11 21:45:18 +02:00
g_simple_async_result_set_op_res_gpointer ( data - > simple ,
2010-05-06 20:13:59 +02:00
result ,
( GDestroyNotify ) g_variant_unref ) ;
}
2010-06-11 21:45:18 +02:00
g_simple_async_result_complete_in_idle ( data - > simple ) ;
async_init_data_free ( data ) ;
2010-05-06 20:13:59 +02:00
}
2010-06-11 21:45:18 +02:00
2010-05-06 20:13:59 +02:00
static void
2010-06-11 21:45:18 +02:00
async_init_get_name_owner_cb ( GDBusConnection * connection ,
GAsyncResult * res ,
gpointer user_data )
2010-05-06 20:13:59 +02:00
{
2010-06-11 21:45:18 +02:00
AsyncInitData * data = user_data ;
2010-05-06 20:13:59 +02:00
2010-06-11 21:45:18 +02:00
if ( res ! = NULL )
{
GError * error ;
GVariant * result ;
2010-05-06 20:13:59 +02:00
2010-06-11 21:45:18 +02:00
error = NULL ;
result = g_dbus_connection_call_finish ( connection ,
res ,
& error ) ;
if ( result = = NULL )
{
if ( error - > domain = = G_DBUS_ERROR & &
error - > code = = G_DBUS_ERROR_NAME_HAS_NO_OWNER )
{
g_error_free ( error ) ;
}
else
{
2010-09-23 13:02:50 +02:00
g_simple_async_result_take_error ( data - > simple , error ) ;
2010-06-11 21:45:18 +02:00
g_simple_async_result_complete_in_idle ( data - > simple ) ;
async_init_data_free ( data ) ;
goto out ;
}
}
else
{
g_variant_get ( result ,
" (s) " ,
& data - > proxy - > priv - > name_owner ) ;
g_variant_unref ( result ) ;
}
}
2010-05-13 23:20:39 +02:00
2010-06-11 21:45:18 +02:00
if ( ! ( data - > proxy - > priv - > flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES ) )
2010-05-06 20:13:59 +02:00
{
/* load all properties asynchronously */
2010-06-11 21:45:18 +02:00
g_dbus_connection_call ( data - > proxy - > priv - > connection ,
data - > proxy - > priv - > name_owner ,
data - > proxy - > priv - > object_path ,
2010-05-10 17:47:08 +02:00
" org.freedesktop.DBus.Properties " ,
" GetAll " ,
2010-06-11 21:45:18 +02:00
g_variant_new ( " (s) " , data - > proxy - > priv - > interface_name ) ,
2010-05-24 22:46:24 +02:00
G_VARIANT_TYPE ( " (a{sv}) " ) ,
2010-05-10 17:47:08 +02:00
G_DBUS_CALL_FLAGS_NONE ,
- 1 , /* timeout */
2010-06-11 21:45:18 +02:00
data - > cancellable ,
( GAsyncReadyCallback ) async_init_get_all_cb ,
data ) ;
2010-05-06 20:13:59 +02:00
}
else
{
2010-06-11 21:45:18 +02:00
g_simple_async_result_complete_in_idle ( data - > simple ) ;
async_init_data_free ( data ) ;
}
out :
;
}
static void
async_init_call_get_name_owner ( AsyncInitData * data )
{
g_dbus_connection_call ( data - > proxy - > priv - > connection ,
" org.freedesktop.DBus " , /* name */
" /org/freedesktop/DBus " , /* object path */
" org.freedesktop.DBus " , /* interface */
" GetNameOwner " ,
g_variant_new ( " (s) " ,
data - > proxy - > priv - > name ) ,
G_VARIANT_TYPE ( " (s) " ) ,
G_DBUS_CALL_FLAGS_NONE ,
- 1 , /* timeout */
data - > cancellable ,
( GAsyncReadyCallback ) async_init_get_name_owner_cb ,
data ) ;
}
static void
async_init_start_service_by_name_cb ( GDBusConnection * connection ,
GAsyncResult * res ,
gpointer user_data )
{
AsyncInitData * data = user_data ;
GError * error ;
GVariant * result ;
error = NULL ;
result = g_dbus_connection_call_finish ( connection ,
res ,
& error ) ;
if ( result = = NULL )
{
/* Errors are not unexpected; the bus will reply e.g.
*
* org . freedesktop . DBus . Error . ServiceUnknown : The name org . gnome . Epiphany2
* was not provided by any . service files
*
* This doesn ' t mean that the name doesn ' t have an owner , just
* that it ' s not provided by a . service file . So just proceed to
* invoke GetNameOwner ( ) if dealing with that error .
*/
if ( error - > domain = = G_DBUS_ERROR & &
error - > code = = G_DBUS_ERROR_SERVICE_UNKNOWN )
{
g_error_free ( error ) ;
}
else
{
g_prefix_error ( & error ,
_ ( " Error calling StartServiceByName for %s: " ) ,
data - > proxy - > priv - > name ) ;
goto failed ;
}
}
else
{
guint32 start_service_result ;
g_variant_get ( result ,
" (u) " ,
& start_service_result ) ;
g_variant_unref ( result ) ;
if ( start_service_result = = 1 | | /* DBUS_START_REPLY_SUCCESS */
start_service_result = = 2 ) /* DBUS_START_REPLY_ALREADY_RUNNING */
{
/* continue to invoke GetNameOwner() */
}
else
{
error = g_error_new ( G_IO_ERROR ,
G_IO_ERROR_FAILED ,
_ ( " Unexpected reply %d from StartServiceByName( \" %s \" ) method " ) ,
start_service_result ,
data - > proxy - > priv - > name ) ;
goto failed ;
}
}
async_init_call_get_name_owner ( data ) ;
return ;
failed :
g_warn_if_fail ( error ! = NULL ) ;
2010-09-23 13:02:50 +02:00
g_simple_async_result_take_error ( data - > simple , error ) ;
2010-06-11 21:45:18 +02:00
g_simple_async_result_complete_in_idle ( data - > simple ) ;
async_init_data_free ( data ) ;
}
static void
async_init_call_start_service_by_name ( AsyncInitData * data )
{
g_dbus_connection_call ( data - > proxy - > priv - > connection ,
" org.freedesktop.DBus " , /* name */
" /org/freedesktop/DBus " , /* object path */
" org.freedesktop.DBus " , /* interface */
" StartServiceByName " ,
g_variant_new ( " (su) " ,
data - > proxy - > priv - > name ,
0 ) ,
G_VARIANT_TYPE ( " (u) " ) ,
G_DBUS_CALL_FLAGS_NONE ,
- 1 , /* timeout */
data - > cancellable ,
( GAsyncReadyCallback ) async_init_start_service_by_name_cb ,
data ) ;
}
static void
async_initable_init_second_async ( GAsyncInitable * initable ,
gint io_priority ,
GCancellable * cancellable ,
GAsyncReadyCallback callback ,
gpointer user_data )
{
GDBusProxy * proxy = G_DBUS_PROXY ( initable ) ;
AsyncInitData * data ;
data = g_new0 ( AsyncInitData , 1 ) ;
data - > proxy = g_object_ref ( proxy ) ;
data - > cancellable = cancellable ! = NULL ? g_object_ref ( cancellable ) : NULL ;
data - > simple = g_simple_async_result_new ( G_OBJECT ( proxy ) ,
callback ,
user_data ,
NULL ) ;
/* Check name ownership asynchronously - possibly also start the service */
if ( proxy - > priv - > name = = NULL )
{
/* Do nothing */
async_init_get_name_owner_cb ( proxy - > priv - > connection , NULL , data ) ;
}
else if ( g_dbus_is_unique_name ( proxy - > priv - > name ) )
{
proxy - > priv - > name_owner = g_strdup ( proxy - > priv - > name ) ;
async_init_get_name_owner_cb ( proxy - > priv - > connection , NULL , data ) ;
}
else
{
if ( proxy - > priv - > flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START )
{
async_init_call_get_name_owner ( data ) ;
}
else
{
async_init_call_start_service_by_name ( data ) ;
}
2010-05-06 20:13:59 +02:00
}
}
static gboolean
2010-06-11 21:45:18 +02:00
async_initable_init_second_finish ( GAsyncInitable * initable ,
GAsyncResult * res ,
GError * * error )
2010-05-06 20:13:59 +02:00
{
GDBusProxy * proxy = G_DBUS_PROXY ( initable ) ;
GSimpleAsyncResult * simple = G_SIMPLE_ASYNC_RESULT ( res ) ;
GVariant * result ;
gboolean ret ;
ret = FALSE ;
2010-06-09 16:56:35 +02:00
if ( g_simple_async_result_propagate_error ( simple , error ) )
goto out ;
2010-05-06 20:13:59 +02:00
result = g_simple_async_result_get_op_res_gpointer ( simple ) ;
2010-06-09 16:56:35 +02:00
if ( result ! = NULL )
2010-05-06 20:13:59 +02:00
{
process_get_all_reply ( proxy , result ) ;
}
ret = TRUE ;
out :
2010-05-13 23:20:39 +02:00
proxy - > priv - > initialized = TRUE ;
2010-05-06 20:13:59 +02:00
return ret ;
}
2010-06-11 21:45:18 +02:00
/* ---------------------------------------------------------------------------------------------------- */
static void
async_initable_init_first ( GAsyncInitable * initable )
{
GDBusProxy * proxy = G_DBUS_PROXY ( initable ) ;
if ( ! ( proxy - > priv - > flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES ) )
{
/* subscribe to PropertiesChanged() */
2011-05-26 15:26:29 +02:00
proxy - > priv - > properties_changed_subscription_id =
2010-06-11 21:45:18 +02:00
g_dbus_connection_signal_subscribe ( proxy - > priv - > connection ,
proxy - > priv - > name ,
" org.freedesktop.DBus.Properties " ,
" PropertiesChanged " ,
proxy - > priv - > object_path ,
proxy - > priv - > interface_name ,
2010-07-19 21:03:00 +02:00
G_DBUS_SIGNAL_FLAGS_NONE ,
2010-06-11 21:45:18 +02:00
on_properties_changed ,
2011-05-26 15:26:29 +02:00
signal_subscription_ref ( proxy - > priv - > signal_subscription_data ) ,
( GDestroyNotify ) signal_subscription_unref ) ;
2010-06-11 21:45:18 +02:00
}
if ( ! ( proxy - > priv - > flags & G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS ) )
{
/* subscribe to all signals for the object */
2011-05-26 15:26:29 +02:00
proxy - > priv - > signals_subscription_id =
2010-06-11 21:45:18 +02:00
g_dbus_connection_signal_subscribe ( proxy - > priv - > connection ,
proxy - > priv - > name ,
proxy - > priv - > interface_name ,
NULL , /* member */
proxy - > priv - > object_path ,
NULL , /* arg0 */
2010-07-19 21:03:00 +02:00
G_DBUS_SIGNAL_FLAGS_NONE ,
2010-06-11 21:45:18 +02:00
on_signal_received ,
2011-05-26 15:26:29 +02:00
signal_subscription_ref ( proxy - > priv - > signal_subscription_data ) ,
( GDestroyNotify ) signal_subscription_unref ) ;
2010-06-11 21:45:18 +02:00
}
if ( proxy - > priv - > name ! = NULL & & ! g_dbus_is_unique_name ( proxy - > priv - > name ) )
{
proxy - > priv - > name_owner_changed_subscription_id =
g_dbus_connection_signal_subscribe ( proxy - > priv - > connection ,
" org.freedesktop.DBus " , /* name */
" org.freedesktop.DBus " , /* interface */
" NameOwnerChanged " , /* signal name */
" /org/freedesktop/DBus " , /* path */
proxy - > priv - > name , /* arg0 */
2010-07-19 21:03:00 +02:00
G_DBUS_SIGNAL_FLAGS_NONE ,
2010-06-11 21:45:18 +02:00
on_name_owner_changed ,
2011-05-26 15:26:29 +02:00
signal_subscription_ref ( proxy - > priv - > signal_subscription_data ) ,
( GDestroyNotify ) signal_subscription_unref ) ;
2010-06-11 21:45:18 +02:00
}
}
/* ---------------------------------------------------------------------------------------------------- */
/* initialization is split into two parts - the first is the
* non - blocing part that requires the callers GMainContext - the
* second is a blocking part async part that doesn ' t require the
* callers GMainContext . . we do this split so the code can be reused
* in the GInitable implementation below .
*
* Note that obtaining a GDBusConnection is not shared between the two
* paths .
*/
typedef struct
{
GDBusProxy * proxy ;
gint io_priority ;
GCancellable * cancellable ;
GAsyncReadyCallback callback ;
gpointer user_data ;
} GetConnectionData ;
static void
get_connection_cb ( GObject * source_object ,
GAsyncResult * res ,
gpointer user_data )
{
GetConnectionData * data = user_data ;
GError * error ;
2010-06-16 04:06:56 +02:00
error = NULL ;
2010-06-11 21:45:18 +02:00
data - > proxy - > priv - > connection = g_bus_get_finish ( res , & error ) ;
if ( data - > proxy - > priv - > connection = = NULL )
{
GSimpleAsyncResult * simple ;
simple = g_simple_async_result_new ( G_OBJECT ( data - > proxy ) ,
data - > callback ,
data - > user_data ,
NULL ) ;
2010-09-23 13:02:50 +02:00
g_simple_async_result_take_error ( simple , error ) ;
2010-06-11 21:45:18 +02:00
g_simple_async_result_complete_in_idle ( simple ) ;
g_object_unref ( simple ) ;
}
else
{
async_initable_init_first ( G_ASYNC_INITABLE ( data - > proxy ) ) ;
async_initable_init_second_async ( G_ASYNC_INITABLE ( data - > proxy ) ,
data - > io_priority ,
data - > cancellable ,
data - > callback ,
data - > user_data ) ;
}
if ( data - > cancellable ! = NULL )
g_object_unref ( data - > cancellable ) ;
2011-06-14 15:50:55 +02:00
g_object_unref ( data - > proxy ) ;
2010-06-11 21:45:18 +02:00
g_free ( data ) ;
}
static void
async_initable_init_async ( GAsyncInitable * initable ,
gint io_priority ,
GCancellable * cancellable ,
GAsyncReadyCallback callback ,
gpointer user_data )
{
GDBusProxy * proxy = G_DBUS_PROXY ( initable ) ;
if ( proxy - > priv - > bus_type ! = G_BUS_TYPE_NONE )
{
GetConnectionData * data ;
g_assert ( proxy - > priv - > connection = = NULL ) ;
data = g_new0 ( GetConnectionData , 1 ) ;
2010-06-17 18:26:15 +02:00
data - > proxy = g_object_ref ( proxy ) ;
2010-06-11 21:45:18 +02:00
data - > io_priority = io_priority ;
data - > cancellable = cancellable ! = NULL ? g_object_ref ( cancellable ) : NULL ;
data - > callback = callback ;
data - > user_data = user_data ;
g_bus_get ( proxy - > priv - > bus_type ,
cancellable ,
get_connection_cb ,
data ) ;
}
else
{
async_initable_init_first ( initable ) ;
async_initable_init_second_async ( initable , io_priority , cancellable , callback , user_data ) ;
}
}
static gboolean
async_initable_init_finish ( GAsyncInitable * initable ,
GAsyncResult * res ,
GError * * error )
{
return async_initable_init_second_finish ( initable , res , error ) ;
}
2010-05-06 20:13:59 +02:00
static void
async_initable_iface_init ( GAsyncInitableIface * async_initable_iface )
{
async_initable_iface - > init_async = async_initable_init_async ;
async_initable_iface - > init_finish = async_initable_init_finish ;
}
/* ---------------------------------------------------------------------------------------------------- */
2010-06-11 21:45:18 +02:00
typedef struct
{
GMainContext * context ;
GMainLoop * loop ;
GAsyncResult * res ;
} InitableAsyncInitableData ;
static void
async_initable_init_async_cb ( GObject * source_object ,
GAsyncResult * res ,
gpointer user_data )
{
InitableAsyncInitableData * data = user_data ;
data - > res = g_object_ref ( res ) ;
g_main_loop_quit ( data - > loop ) ;
}
/* Simply reuse the GAsyncInitable implementation but run the first
* part ( that is non - blocking and requires the callers GMainContext )
* with the callers GMainContext . . and the second with a private
* GMainContext ( bug 621310 is slightly related ) .
*
* Note that obtaining a GDBusConnection is not shared between the two
* paths .
*/
static gboolean
initable_init ( GInitable * initable ,
GCancellable * cancellable ,
GError * * error )
{
GDBusProxy * proxy = G_DBUS_PROXY ( initable ) ;
InitableAsyncInitableData * data ;
gboolean ret ;
ret = FALSE ;
if ( proxy - > priv - > bus_type ! = G_BUS_TYPE_NONE )
{
g_assert ( proxy - > priv - > connection = = NULL ) ;
proxy - > priv - > connection = g_bus_get_sync ( proxy - > priv - > bus_type ,
cancellable ,
error ) ;
if ( proxy - > priv - > connection = = NULL )
goto out ;
}
async_initable_init_first ( G_ASYNC_INITABLE ( initable ) ) ;
data = g_new0 ( InitableAsyncInitableData , 1 ) ;
data - > context = g_main_context_new ( ) ;
data - > loop = g_main_loop_new ( data - > context , FALSE ) ;
g_main_context_push_thread_default ( data - > context ) ;
async_initable_init_second_async ( G_ASYNC_INITABLE ( initable ) ,
G_PRIORITY_DEFAULT ,
cancellable ,
async_initable_init_async_cb ,
data ) ;
g_main_loop_run ( data - > loop ) ;
ret = async_initable_init_second_finish ( G_ASYNC_INITABLE ( initable ) ,
data - > res ,
error ) ;
g_main_context_pop_thread_default ( data - > context ) ;
g_main_context_unref ( data - > context ) ;
g_main_loop_unref ( data - > loop ) ;
g_object_unref ( data - > res ) ;
g_free ( data ) ;
out :
return ret ;
}
static void
initable_iface_init ( GInitableIface * initable_iface )
{
initable_iface - > init = initable_init ;
}
/* ---------------------------------------------------------------------------------------------------- */
2010-05-06 20:13:59 +02:00
/**
* g_dbus_proxy_new :
* @ connection : A # GDBusConnection .
* @ flags : Flags used when constructing the proxy .
2011-03-30 19:52:31 +02:00
* @ info : ( allow - none ) : A # GDBusInterfaceInfo specifying the minimal interface that @ proxy conforms to or % NULL .
* @ name : ( allow - none ) : A bus name ( well - known or unique ) or % NULL if @ connection is not a message bus connection .
2010-05-06 20:13:59 +02:00
* @ object_path : An object path .
* @ interface_name : A D - Bus interface name .
* @ cancellable : A # GCancellable or % NULL .
* @ callback : Callback function to invoke when the proxy is ready .
* @ user_data : User data to pass to @ callback .
*
2010-06-11 21:45:18 +02:00
* Creates a proxy for accessing @ interface_name on the remote object
* at @ object_path owned by @ name at @ connection and asynchronously
* loads D - Bus properties unless the
2010-08-18 16:52:28 +02:00
* % G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used . Connect to
2010-06-11 21:45:18 +02:00
* the # GDBusProxy : : g - properties - changed signal to get notified about
* property changes .
2010-05-06 20:13:59 +02:00
*
2010-08-18 16:52:28 +02:00
* If the % G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set , also sets up
2010-05-06 20:13:59 +02:00
* match rules for signals . Connect to the # GDBusProxy : : g - signal signal
* to handle signals from the remote object .
*
2010-06-11 21:45:18 +02:00
* If @ name is a well - known name and the
2010-08-18 16:52:28 +02:00
* % G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag isn ' t set and no name
2010-06-11 21:45:18 +02:00
* owner currently exists , the message bus will be requested to launch
* a name owner for the name .
*
2010-05-06 20:13:59 +02:00
* This is a failable asynchronous constructor - when the proxy is
* ready , @ callback will be invoked and you can use
* g_dbus_proxy_new_finish ( ) to get the result .
*
* See g_dbus_proxy_new_sync ( ) and for a synchronous version of this constructor .
2010-05-06 22:02:08 +02:00
*
2010-06-11 21:45:18 +02:00
* See < xref linkend = " gdbus-wellknown-proxy " / > for an example of how # GDBusProxy can be used .
*
2010-05-06 22:02:08 +02:00
* Since : 2.26
*/
2010-05-06 20:13:59 +02:00
void
g_dbus_proxy_new ( GDBusConnection * connection ,
GDBusProxyFlags flags ,
GDBusInterfaceInfo * info ,
2010-06-11 21:45:18 +02:00
const gchar * name ,
2010-05-06 20:13:59 +02:00
const gchar * object_path ,
const gchar * interface_name ,
GCancellable * cancellable ,
GAsyncReadyCallback callback ,
gpointer user_data )
{
g_return_if_fail ( G_IS_DBUS_CONNECTION ( connection ) ) ;
2010-06-11 21:45:18 +02:00
g_return_if_fail ( ( name = = NULL & & g_dbus_connection_get_unique_name ( connection ) = = NULL ) | | g_dbus_is_name ( name ) ) ;
2010-05-06 20:13:59 +02:00
g_return_if_fail ( g_variant_is_object_path ( object_path ) ) ;
g_return_if_fail ( g_dbus_is_interface_name ( interface_name ) ) ;
2010-06-11 21:45:18 +02:00
g_async_initable_new_async ( G_TYPE_DBUS_PROXY ,
2010-05-06 20:13:59 +02:00
G_PRIORITY_DEFAULT ,
cancellable ,
callback ,
user_data ,
" g-flags " , flags ,
" g-interface-info " , info ,
2010-06-11 21:45:18 +02:00
" g-name " , name ,
2010-05-06 20:13:59 +02:00
" g-connection " , connection ,
" g-object-path " , object_path ,
" g-interface-name " , interface_name ,
NULL ) ;
}
/**
* g_dbus_proxy_new_finish :
* @ res : A # GAsyncResult obtained from the # GAsyncReadyCallback function passed to g_dbus_proxy_new ( ) .
* @ error : Return location for error or % NULL .
*
* Finishes creating a # GDBusProxy .
*
* Returns : A # GDBusProxy or % NULL if @ error is set . Free with g_object_unref ( ) .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
*/
2010-05-06 20:13:59 +02:00
GDBusProxy *
g_dbus_proxy_new_finish ( GAsyncResult * res ,
GError * * error )
{
GObject * object ;
GObject * source_object ;
source_object = g_async_result_get_source_object ( res ) ;
g_assert ( source_object ! = NULL ) ;
object = g_async_initable_new_finish ( G_ASYNC_INITABLE ( source_object ) ,
res ,
error ) ;
g_object_unref ( source_object ) ;
if ( object ! = NULL )
return G_DBUS_PROXY ( object ) ;
else
return NULL ;
}
/**
* g_dbus_proxy_new_sync :
* @ connection : A # GDBusConnection .
* @ flags : Flags used when constructing the proxy .
2010-07-15 15:32:45 +02:00
* @ info : ( allow - none ) : A # GDBusInterfaceInfo specifying the minimal interface that @ proxy conforms to or % NULL .
* @ name : ( allow - none ) : A bus name ( well - known or unique ) or % NULL if @ connection is not a message bus connection .
2010-05-06 20:13:59 +02:00
* @ object_path : An object path .
* @ interface_name : A D - Bus interface name .
2010-07-15 15:32:45 +02:00
* @ cancellable : ( allow - none ) : A # GCancellable or % NULL .
* @ error : ( allow - none ) : Return location for error or % NULL .
2010-05-06 20:13:59 +02:00
*
2010-06-11 21:45:18 +02:00
* Creates a proxy for accessing @ interface_name on the remote object
* at @ object_path owned by @ name at @ connection and synchronously
* loads D - Bus properties unless the
2010-08-18 16:52:28 +02:00
* % G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES flag is used .
2010-05-06 20:13:59 +02:00
*
2010-08-18 16:52:28 +02:00
* If the % G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS flag is not set , also sets up
2010-05-06 20:13:59 +02:00
* match rules for signals . Connect to the # GDBusProxy : : g - signal signal
* to handle signals from the remote object .
*
2010-06-11 21:45:18 +02:00
* If @ name is a well - known name and the
2010-08-18 16:52:28 +02:00
* % G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag isn ' t set and no name
2010-06-11 21:45:18 +02:00
* owner currently exists , the message bus will be requested to launch
* a name owner for the name .
*
2010-05-06 20:13:59 +02:00
* This is a synchronous failable constructor . See g_dbus_proxy_new ( )
* and g_dbus_proxy_new_finish ( ) for the asynchronous version .
*
2010-06-11 21:45:18 +02:00
* See < xref linkend = " gdbus-wellknown-proxy " / > for an example of how # GDBusProxy can be used .
*
2010-05-06 20:13:59 +02:00
* Returns : A # GDBusProxy or % NULL if error is set . Free with g_object_unref ( ) .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
*/
2010-05-06 20:13:59 +02:00
GDBusProxy *
g_dbus_proxy_new_sync ( GDBusConnection * connection ,
GDBusProxyFlags flags ,
GDBusInterfaceInfo * info ,
2010-06-11 21:45:18 +02:00
const gchar * name ,
2010-05-06 20:13:59 +02:00
const gchar * object_path ,
const gchar * interface_name ,
GCancellable * cancellable ,
GError * * error )
{
GInitable * initable ;
g_return_val_if_fail ( G_IS_DBUS_CONNECTION ( connection ) , NULL ) ;
2010-06-11 21:45:18 +02:00
g_return_val_if_fail ( ( name = = NULL & & g_dbus_connection_get_unique_name ( connection ) = = NULL ) | |
g_dbus_is_name ( name ) , NULL ) ;
2010-05-06 20:13:59 +02:00
g_return_val_if_fail ( g_variant_is_object_path ( object_path ) , NULL ) ;
g_return_val_if_fail ( g_dbus_is_interface_name ( interface_name ) , NULL ) ;
2010-06-11 21:45:18 +02:00
initable = g_initable_new ( G_TYPE_DBUS_PROXY ,
2010-05-06 20:13:59 +02:00
cancellable ,
error ,
" g-flags " , flags ,
" g-interface-info " , info ,
2010-06-11 21:45:18 +02:00
" g-name " , name ,
2010-05-06 20:13:59 +02:00
" g-connection " , connection ,
" g-object-path " , object_path ,
" g-interface-name " , interface_name ,
NULL ) ;
if ( initable ! = NULL )
return G_DBUS_PROXY ( initable ) ;
else
return NULL ;
}
/* ---------------------------------------------------------------------------------------------------- */
2010-06-11 21:45:18 +02:00
/**
* g_dbus_proxy_new_for_bus :
* @ bus_type : A # GBusType .
* @ flags : Flags used when constructing the proxy .
2011-03-30 19:52:31 +02:00
* @ info : ( allow - none ) : A # GDBusInterfaceInfo specifying the minimal interface that @ proxy conforms to or % NULL .
2010-06-11 21:45:18 +02:00
* @ name : A bus name ( well - known or unique ) .
* @ object_path : An object path .
* @ interface_name : A D - Bus interface name .
* @ cancellable : A # GCancellable or % NULL .
* @ callback : Callback function to invoke when the proxy is ready .
* @ user_data : User data to pass to @ callback .
*
* Like g_dbus_proxy_new ( ) but takes a # GBusType instead of a # GDBusConnection .
*
* See < xref linkend = " gdbus-wellknown-proxy " / > for an example of how # GDBusProxy can be used .
*
* Since : 2.26
*/
void
g_dbus_proxy_new_for_bus ( GBusType bus_type ,
GDBusProxyFlags flags ,
GDBusInterfaceInfo * info ,
const gchar * name ,
const gchar * object_path ,
const gchar * interface_name ,
GCancellable * cancellable ,
GAsyncReadyCallback callback ,
gpointer user_data )
{
g_return_if_fail ( g_dbus_is_name ( name ) ) ;
g_return_if_fail ( g_variant_is_object_path ( object_path ) ) ;
g_return_if_fail ( g_dbus_is_interface_name ( interface_name ) ) ;
g_async_initable_new_async ( G_TYPE_DBUS_PROXY ,
G_PRIORITY_DEFAULT ,
cancellable ,
callback ,
user_data ,
" g-flags " , flags ,
" g-interface-info " , info ,
" g-name " , name ,
" g-bus-type " , bus_type ,
" g-object-path " , object_path ,
" g-interface-name " , interface_name ,
NULL ) ;
}
/**
* g_dbus_proxy_new_for_bus_finish :
* @ res : A # GAsyncResult obtained from the # GAsyncReadyCallback function passed to g_dbus_proxy_new_for_bus ( ) .
* @ error : Return location for error or % NULL .
*
* Finishes creating a # GDBusProxy .
*
* Returns : A # GDBusProxy or % NULL if @ error is set . Free with g_object_unref ( ) .
*
* Since : 2.26
*/
GDBusProxy *
g_dbus_proxy_new_for_bus_finish ( GAsyncResult * res ,
GError * * error )
{
return g_dbus_proxy_new_finish ( res , error ) ;
}
/**
* g_dbus_proxy_new_for_bus_sync :
* @ bus_type : A # GBusType .
* @ flags : Flags used when constructing the proxy .
2011-03-30 19:52:31 +02:00
* @ info : ( allow - none ) : A # GDBusInterfaceInfo specifying the minimal interface
* that @ proxy conforms to or % NULL .
2010-06-11 21:45:18 +02:00
* @ name : A bus name ( well - known or unique ) .
* @ object_path : An object path .
* @ interface_name : A D - Bus interface name .
* @ cancellable : A # GCancellable or % NULL .
* @ error : Return location for error or % NULL .
*
* Like g_dbus_proxy_new_sync ( ) but takes a # GBusType instead of a # GDBusConnection .
*
* See < xref linkend = " gdbus-wellknown-proxy " / > for an example of how # GDBusProxy can be used .
*
* Returns : A # GDBusProxy or % NULL if error is set . Free with g_object_unref ( ) .
*
* Since : 2.26
*/
GDBusProxy *
g_dbus_proxy_new_for_bus_sync ( GBusType bus_type ,
GDBusProxyFlags flags ,
GDBusInterfaceInfo * info ,
const gchar * name ,
const gchar * object_path ,
const gchar * interface_name ,
GCancellable * cancellable ,
GError * * error )
{
GInitable * initable ;
g_return_val_if_fail ( g_dbus_is_name ( name ) , NULL ) ;
g_return_val_if_fail ( g_variant_is_object_path ( object_path ) , NULL ) ;
g_return_val_if_fail ( g_dbus_is_interface_name ( interface_name ) , NULL ) ;
initable = g_initable_new ( G_TYPE_DBUS_PROXY ,
cancellable ,
error ,
" g-flags " , flags ,
" g-interface-info " , info ,
" g-name " , name ,
" g-bus-type " , bus_type ,
" g-object-path " , object_path ,
" g-interface-name " , interface_name ,
NULL ) ;
if ( initable ! = NULL )
return G_DBUS_PROXY ( initable ) ;
else
return NULL ;
}
/* ---------------------------------------------------------------------------------------------------- */
2010-05-06 20:13:59 +02:00
/**
* g_dbus_proxy_get_connection :
* @ proxy : A # GDBusProxy .
*
* Gets the connection @ proxy is for .
*
2010-09-24 23:24:41 +02:00
* Returns : ( transfer none ) : A # GDBusConnection owned by @ proxy . Do not free .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
*/
2010-05-06 20:13:59 +02:00
GDBusConnection *
g_dbus_proxy_get_connection ( GDBusProxy * proxy )
{
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , NULL ) ;
return proxy - > priv - > connection ;
}
/**
* g_dbus_proxy_get_flags :
* @ proxy : A # GDBusProxy .
*
* Gets the flags that @ proxy was constructed with .
*
* Returns : Flags from the # GDBusProxyFlags enumeration .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
*/
2010-05-06 20:13:59 +02:00
GDBusProxyFlags
g_dbus_proxy_get_flags ( GDBusProxy * proxy )
{
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , 0 ) ;
return proxy - > priv - > flags ;
}
/**
2010-06-11 21:45:18 +02:00
* g_dbus_proxy_get_name :
2010-05-06 20:13:59 +02:00
* @ proxy : A # GDBusProxy .
*
2010-06-11 21:45:18 +02:00
* Gets the name that @ proxy was constructed for .
2010-05-06 20:13:59 +02:00
*
* Returns : A string owned by @ proxy . Do not free .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
*/
2010-05-06 20:13:59 +02:00
const gchar *
2010-06-11 21:45:18 +02:00
g_dbus_proxy_get_name ( GDBusProxy * proxy )
{
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , NULL ) ;
return proxy - > priv - > name ;
}
/**
* g_dbus_proxy_get_name_owner :
* @ proxy : A # GDBusProxy .
*
* The unique name that owns the name that @ proxy is for or % NULL if
* no - one currently owns that name . You may connect to the
* # GObject : : notify signal to track changes to the
* # GDBusProxy : g - name - owner property .
*
* Returns : The name owner or % NULL if no name owner exists . Free with g_free ( ) .
*
* Since : 2.26
*/
gchar *
g_dbus_proxy_get_name_owner ( GDBusProxy * proxy )
2010-05-06 20:13:59 +02:00
{
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , NULL ) ;
2010-06-11 21:45:18 +02:00
return g_strdup ( proxy - > priv - > name_owner ) ;
2010-05-06 20:13:59 +02:00
}
/**
* g_dbus_proxy_get_object_path :
* @ proxy : A # GDBusProxy .
*
* Gets the object path @ proxy is for .
*
* Returns : A string owned by @ proxy . Do not free .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
*/
2010-05-06 20:13:59 +02:00
const gchar *
g_dbus_proxy_get_object_path ( GDBusProxy * proxy )
{
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , NULL ) ;
return proxy - > priv - > object_path ;
}
/**
* g_dbus_proxy_get_interface_name :
* @ proxy : A # GDBusProxy .
*
* Gets the D - Bus interface name @ proxy is for .
*
* Returns : A string owned by @ proxy . Do not free .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
*/
2010-05-06 20:13:59 +02:00
const gchar *
g_dbus_proxy_get_interface_name ( GDBusProxy * proxy )
{
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , NULL ) ;
return proxy - > priv - > interface_name ;
}
/**
* g_dbus_proxy_get_default_timeout :
* @ proxy : A # GDBusProxy .
*
* Gets the timeout to use if - 1 ( specifying default timeout ) is
2010-05-10 17:47:08 +02:00
* passed as @ timeout_msec in the g_dbus_proxy_call ( ) and
* g_dbus_proxy_call_sync ( ) functions .
2010-05-06 20:13:59 +02:00
*
* See the # GDBusProxy : g - default - timeout property for more details .
*
* Returns : Timeout to use for @ proxy .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
gint
g_dbus_proxy_get_default_timeout ( GDBusProxy * proxy )
{
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , - 1 ) ;
return proxy - > priv - > timeout_msec ;
}
/**
* g_dbus_proxy_set_default_timeout :
* @ proxy : A # GDBusProxy .
* @ timeout_msec : Timeout in milliseconds .
*
* Sets the timeout to use if - 1 ( specifying default timeout ) is
2010-05-10 17:47:08 +02:00
* passed as @ timeout_msec in the g_dbus_proxy_call ( ) and
* g_dbus_proxy_call_sync ( ) functions .
2010-05-06 20:13:59 +02:00
*
* See the # GDBusProxy : g - default - timeout property for more details .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
void
g_dbus_proxy_set_default_timeout ( GDBusProxy * proxy ,
gint timeout_msec )
{
g_return_if_fail ( G_IS_DBUS_PROXY ( proxy ) ) ;
g_return_if_fail ( timeout_msec = = - 1 | | timeout_msec > = 0 ) ;
/* TODO: locking? */
if ( proxy - > priv - > timeout_msec ! = timeout_msec )
{
proxy - > priv - > timeout_msec = timeout_msec ;
g_object_notify ( G_OBJECT ( proxy ) , " g-default-timeout " ) ;
}
}
/**
* g_dbus_proxy_get_interface_info :
* @ proxy : A # GDBusProxy
*
* Returns the # GDBusInterfaceInfo , if any , specifying the minimal
* interface that @ proxy conforms to .
*
* See the # GDBusProxy : g - interface - info property for more details .
*
* Returns : A # GDBusInterfaceInfo or % NULL . Do not unref the returned
* object , it is owned by @ proxy .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
GDBusInterfaceInfo *
g_dbus_proxy_get_interface_info ( GDBusProxy * proxy )
{
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , NULL ) ;
return proxy - > priv - > expected_interface ;
}
/**
* g_dbus_proxy_set_interface_info :
* @ proxy : A # GDBusProxy
2011-03-30 19:52:31 +02:00
* @ info : ( allow - none ) : Minimum interface this proxy conforms to or % NULL to unset .
2010-05-06 20:13:59 +02:00
*
* Ensure that interactions with @ proxy conform to the given
* interface . For example , when completing a method call , if the type
* signature of the message isn ' t what ' s expected , the given # GError
* is set . Signals that have a type signature mismatch are simply
* dropped .
*
* See the # GDBusProxy : g - interface - info property for more details .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
void
g_dbus_proxy_set_interface_info ( GDBusProxy * proxy ,
GDBusInterfaceInfo * info )
{
g_return_if_fail ( G_IS_DBUS_PROXY ( proxy ) ) ;
if ( proxy - > priv - > expected_interface ! = NULL )
2011-03-28 17:34:48 +02:00
{
g_dbus_interface_info_cache_release ( proxy - > priv - > expected_interface ) ;
g_dbus_interface_info_unref ( proxy - > priv - > expected_interface ) ;
}
2010-05-06 20:13:59 +02:00
proxy - > priv - > expected_interface = info ! = NULL ? g_dbus_interface_info_ref ( info ) : NULL ;
2011-03-28 17:34:48 +02:00
if ( proxy - > priv - > expected_interface ! = NULL )
g_dbus_interface_info_cache_build ( proxy - > priv - > expected_interface ) ;
2010-05-06 20:13:59 +02:00
}
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
2010-05-10 04:13:18 +02:00
maybe_split_method_name ( const gchar * method_name ,
gchar * * out_interface_name ,
const gchar * * out_method_name )
2010-05-06 20:13:59 +02:00
{
gboolean was_split ;
was_split = FALSE ;
g_assert ( out_interface_name ! = NULL ) ;
g_assert ( out_method_name ! = NULL ) ;
* out_interface_name = NULL ;
* out_method_name = NULL ;
if ( strchr ( method_name , ' . ' ) ! = NULL )
{
gchar * p ;
gchar * last_dot ;
p = g_strdup ( method_name ) ;
last_dot = strrchr ( p , ' . ' ) ;
* last_dot = ' \0 ' ;
* out_interface_name = p ;
* out_method_name = last_dot + 1 ;
was_split = TRUE ;
}
return was_split ;
}
static void
reply_cb ( GDBusConnection * connection ,
GAsyncResult * res ,
gpointer user_data )
{
GSimpleAsyncResult * simple = G_SIMPLE_ASYNC_RESULT ( user_data ) ;
GVariant * value ;
GError * error ;
error = NULL ;
2010-05-10 17:47:08 +02:00
value = g_dbus_connection_call_finish ( connection ,
res ,
& error ) ;
2010-05-06 20:13:59 +02:00
if ( error ! = NULL )
{
2010-09-23 13:02:50 +02:00
g_simple_async_result_take_error ( simple , error ) ;
2010-05-06 20:13:59 +02:00
}
else
{
g_simple_async_result_set_op_res_gpointer ( simple ,
value ,
( GDestroyNotify ) g_variant_unref ) ;
}
/* no need to complete in idle since the method GDBusConnection already does */
g_simple_async_result_complete ( simple ) ;
2010-08-03 17:14:21 +02:00
g_object_unref ( simple ) ;
2010-05-06 20:13:59 +02:00
}
static const GDBusMethodInfo *
2010-05-10 04:13:18 +02:00
lookup_method_info_or_warn ( GDBusProxy * proxy ,
const gchar * method_name )
2010-05-06 20:13:59 +02:00
{
const GDBusMethodInfo * info ;
2010-05-13 02:43:40 +02:00
if ( proxy - > priv - > expected_interface = = NULL )
2010-05-06 20:13:59 +02:00
return NULL ;
info = g_dbus_interface_info_lookup_method ( proxy - > priv - > expected_interface , method_name ) ;
2010-05-13 02:43:40 +02:00
if ( info = = NULL )
{
g_warning ( " Trying to invoke method %s which isn't in expected interface %s " ,
method_name , proxy - > priv - > expected_interface - > name ) ;
}
2010-05-06 20:13:59 +02:00
return info ;
}
2010-08-18 17:35:25 +02:00
static const gchar *
get_destination_for_call ( GDBusProxy * proxy )
{
const gchar * ret ;
ret = NULL ;
/* If proxy->priv->name is a unique name, then proxy->priv->name_owner
* is never NULL and always the same as proxy - > priv - > name . We use this
* knowledge to avoid checking if proxy - > priv - > name is a unique or
* well - known name .
*/
ret = proxy - > priv - > name_owner ;
if ( ret ! = NULL )
goto out ;
if ( proxy - > priv - > flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START )
goto out ;
ret = proxy - > priv - > name ;
out :
return ret ;
}
2010-05-06 20:13:59 +02:00
/**
2010-05-10 17:47:08 +02:00
* g_dbus_proxy_call :
2010-05-06 20:13:59 +02:00
* @ proxy : A # GDBusProxy .
* @ method_name : Name of method to invoke .
2011-03-30 19:52:31 +02:00
* @ parameters : ( allow - none ) : A # GVariant tuple with parameters for the signal or % NULL if not passing parameters .
2010-05-10 17:47:08 +02:00
* @ flags : Flags from the # GDBusCallFlags enumeration .
2010-10-28 22:14:24 +02:00
* @ timeout_msec : The timeout in milliseconds ( with % G_MAXINT meaning
* " infinite " ) or - 1 to use the proxy default timeout .
2010-05-06 20:13:59 +02:00
* @ cancellable : A # GCancellable or % NULL .
* @ callback : A # GAsyncReadyCallback to call when the request is satisfied or % NULL if you don ' t
* care about the result of the method invocation .
* @ user_data : The data to pass to @ callback .
*
* Asynchronously invokes the @ method_name method on @ proxy .
*
* If @ method_name contains any dots , then @ name is split into interface and
* method name parts . This allows using @ proxy for invoking methods on
* other interfaces .
*
* If the # GDBusConnection associated with @ proxy is closed then
* the operation will fail with % G_IO_ERROR_CLOSED . If
* @ cancellable is canceled , the operation will fail with
* % G_IO_ERROR_CANCELLED . If @ parameters contains a value not
* compatible with the D - Bus protocol , the operation fails with
* % G_IO_ERROR_INVALID_ARGUMENT .
*
2010-05-12 05:18:48 +02:00
* If the @ parameters # GVariant is floating , it is consumed . This allows
* convenient ' inline ' use of g_variant_new ( ) , e . g . :
* | [
* g_dbus_proxy_call ( proxy ,
* " TwoStrings " ,
* g_variant_new ( " (ss) " ,
* " Thing One " ,
* " Thing Two " ) ,
* G_DBUS_CALL_FLAGS_NONE ,
* - 1 ,
* NULL ,
* ( GAsyncReadyCallback ) two_strings_done ,
* & amp ; data ) ;
* ] |
*
* This is an asynchronous method . When the operation is finished ,
* @ callback will be invoked in the
2011-05-26 15:54:47 +02:00
* < link linkend = " g-main-context-push-thread-default " > thread - default main loop < / link >
* of the thread you are calling this method from .
2010-05-12 05:18:48 +02:00
* You can then call g_dbus_proxy_call_finish ( ) to get the result of
* the operation . See g_dbus_proxy_call_sync ( ) for the synchronous
* version of this method .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
void
2010-05-12 02:03:44 +02:00
g_dbus_proxy_call ( GDBusProxy * proxy ,
const gchar * method_name ,
GVariant * parameters ,
GDBusCallFlags flags ,
gint timeout_msec ,
GCancellable * cancellable ,
GAsyncReadyCallback callback ,
gpointer user_data )
2010-05-06 20:13:59 +02:00
{
GSimpleAsyncResult * simple ;
gboolean was_split ;
gchar * split_interface_name ;
const gchar * split_method_name ;
const gchar * target_method_name ;
const gchar * target_interface_name ;
2010-08-18 17:35:25 +02:00
const gchar * destination ;
2010-05-24 22:46:24 +02:00
GVariantType * reply_type ;
2010-05-06 20:13:59 +02:00
g_return_if_fail ( G_IS_DBUS_PROXY ( proxy ) ) ;
g_return_if_fail ( g_dbus_is_member_name ( method_name ) | | g_dbus_is_interface_name ( method_name ) ) ;
g_return_if_fail ( parameters = = NULL | | g_variant_is_of_type ( parameters , G_VARIANT_TYPE_TUPLE ) ) ;
g_return_if_fail ( timeout_msec = = - 1 | | timeout_msec > = 0 ) ;
2010-08-18 17:35:25 +02:00
reply_type = NULL ;
split_interface_name = NULL ;
2010-05-06 20:13:59 +02:00
simple = g_simple_async_result_new ( G_OBJECT ( proxy ) ,
callback ,
user_data ,
2010-05-10 17:47:08 +02:00
g_dbus_proxy_call ) ;
2010-05-06 20:13:59 +02:00
was_split = maybe_split_method_name ( method_name , & split_interface_name , & split_method_name ) ;
target_method_name = was_split ? split_method_name : method_name ;
target_interface_name = was_split ? split_interface_name : proxy - > priv - > interface_name ;
2010-06-22 23:48:35 +02:00
/* Warn if method is unexpected (cf. :g-interface-info) */
if ( ! was_split )
2010-08-18 17:35:25 +02:00
{
const GDBusMethodInfo * expected_method_info ;
expected_method_info = lookup_method_info_or_warn ( proxy , target_method_name ) ;
if ( expected_method_info ! = NULL )
reply_type = _g_dbus_compute_complete_signature ( expected_method_info - > out_args ) ;
}
2010-05-06 20:13:59 +02:00
2010-08-18 17:35:25 +02:00
destination = NULL ;
if ( proxy - > priv - > name ! = NULL )
{
destination = get_destination_for_call ( proxy ) ;
if ( destination = = NULL )
{
g_simple_async_result_set_error ( simple ,
G_IO_ERROR ,
G_IO_ERROR_FAILED ,
_ ( " Cannot invoke method; proxy is for a well-known name without an owner and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag " ) ) ;
goto out ;
}
}
2010-05-24 22:46:24 +02:00
2010-05-10 17:47:08 +02:00
g_dbus_connection_call ( proxy - > priv - > connection ,
2010-08-18 17:35:25 +02:00
destination ,
2010-05-10 17:47:08 +02:00
proxy - > priv - > object_path ,
target_interface_name ,
target_method_name ,
parameters ,
2010-05-24 22:46:24 +02:00
reply_type ,
2010-05-10 17:47:08 +02:00
flags ,
timeout_msec = = - 1 ? proxy - > priv - > timeout_msec : timeout_msec ,
cancellable ,
( GAsyncReadyCallback ) reply_cb ,
simple ) ;
2010-05-06 20:13:59 +02:00
2010-08-18 17:35:25 +02:00
out :
2010-05-24 22:46:24 +02:00
if ( reply_type ! = NULL )
g_variant_type_free ( reply_type ) ;
2010-05-06 20:13:59 +02:00
g_free ( split_interface_name ) ;
}
/**
2010-05-10 17:47:08 +02:00
* g_dbus_proxy_call_finish :
2010-05-06 20:13:59 +02:00
* @ proxy : A # GDBusProxy .
2010-05-10 17:47:08 +02:00
* @ res : A # GAsyncResult obtained from the # GAsyncReadyCallback passed to g_dbus_proxy_call ( ) .
2010-05-06 20:13:59 +02:00
* @ error : Return location for error or % NULL .
*
2010-05-10 17:47:08 +02:00
* Finishes an operation started with g_dbus_proxy_call ( ) .
2010-05-06 20:13:59 +02:00
*
* Returns : % NULL if @ error is set . Otherwise a # GVariant tuple with
* return values . Free with g_variant_unref ( ) .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
GVariant *
2010-05-10 17:47:08 +02:00
g_dbus_proxy_call_finish ( GDBusProxy * proxy ,
2010-05-12 02:03:44 +02:00
GAsyncResult * res ,
GError * * error )
2010-05-06 20:13:59 +02:00
{
GSimpleAsyncResult * simple = G_SIMPLE_ASYNC_RESULT ( res ) ;
GVariant * value ;
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , NULL ) ;
g_return_val_if_fail ( G_IS_ASYNC_RESULT ( res ) , NULL ) ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , NULL ) ;
2010-05-10 17:47:08 +02:00
g_warn_if_fail ( g_simple_async_result_get_source_tag ( simple ) = = g_dbus_proxy_call ) ;
2010-05-06 20:13:59 +02:00
value = NULL ;
if ( g_simple_async_result_propagate_error ( simple , error ) )
goto out ;
2010-08-30 19:45:46 +02:00
value = g_variant_ref ( g_simple_async_result_get_op_res_gpointer ( simple ) ) ;
2010-05-06 20:13:59 +02:00
out :
return value ;
}
/**
2010-05-10 17:47:08 +02:00
* g_dbus_proxy_call_sync :
2010-05-06 20:13:59 +02:00
* @ proxy : A # GDBusProxy .
* @ method_name : Name of method to invoke .
2011-03-30 19:52:31 +02:00
* @ parameters : ( allow - none ) : A # GVariant tuple with parameters for the signal
* or % NULL if not passing parameters .
2010-05-10 17:47:08 +02:00
* @ flags : Flags from the # GDBusCallFlags enumeration .
2010-10-28 22:14:24 +02:00
* @ timeout_msec : The timeout in milliseconds ( with % G_MAXINT meaning
* " infinite " ) or - 1 to use the proxy default timeout .
2010-05-06 20:13:59 +02:00
* @ cancellable : A # GCancellable or % NULL .
* @ error : Return location for error or % NULL .
*
* Synchronously invokes the @ method_name method on @ proxy .
*
* If @ method_name contains any dots , then @ name is split into interface and
* method name parts . This allows using @ proxy for invoking methods on
* other interfaces .
*
* If the # GDBusConnection associated with @ proxy is disconnected then
* the operation will fail with % G_IO_ERROR_CLOSED . If
* @ cancellable is canceled , the operation will fail with
* % G_IO_ERROR_CANCELLED . If @ parameters contains a value not
* compatible with the D - Bus protocol , the operation fails with
* % G_IO_ERROR_INVALID_ARGUMENT .
*
2010-05-12 05:18:48 +02:00
* If the @ parameters # GVariant is floating , it is consumed . This allows
* convenient ' inline ' use of g_variant_new ( ) , e . g . :
* | [
* g_dbus_proxy_call_sync ( proxy ,
* " TwoStrings " ,
* g_variant_new ( " (ss) " ,
* " Thing One " ,
* " Thing Two " ) ,
* G_DBUS_CALL_FLAGS_NONE ,
* - 1 ,
* NULL ,
* & amp ; error ) ;
* ] |
*
2010-05-06 20:13:59 +02:00
* The calling thread is blocked until a reply is received . See
2010-05-10 17:47:08 +02:00
* g_dbus_proxy_call ( ) for the asynchronous version of this
2010-05-06 20:13:59 +02:00
* method .
*
* Returns : % NULL if @ error is set . Otherwise a # GVariant tuple with
* return values . Free with g_variant_unref ( ) .
2010-05-06 22:02:08 +02:00
*
* Since : 2.26
2010-05-06 20:13:59 +02:00
*/
GVariant *
2010-05-12 02:03:44 +02:00
g_dbus_proxy_call_sync ( GDBusProxy * proxy ,
const gchar * method_name ,
GVariant * parameters ,
GDBusCallFlags flags ,
gint timeout_msec ,
GCancellable * cancellable ,
GError * * error )
2010-05-06 20:13:59 +02:00
{
GVariant * ret ;
gboolean was_split ;
gchar * split_interface_name ;
const gchar * split_method_name ;
2010-05-10 04:13:18 +02:00
const gchar * target_method_name ;
const gchar * target_interface_name ;
2010-08-18 17:35:25 +02:00
const gchar * destination ;
2010-05-24 22:46:24 +02:00
GVariantType * reply_type ;
2010-05-06 20:13:59 +02:00
g_return_val_if_fail ( G_IS_DBUS_PROXY ( proxy ) , NULL ) ;
g_return_val_if_fail ( g_dbus_is_member_name ( method_name ) | | g_dbus_is_interface_name ( method_name ) , NULL ) ;
g_return_val_if_fail ( parameters = = NULL | | g_variant_is_of_type ( parameters , G_VARIANT_TYPE_TUPLE ) , NULL ) ;
g_return_val_if_fail ( timeout_msec = = - 1 | | timeout_msec > = 0 , NULL ) ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , NULL ) ;
2010-08-18 17:35:25 +02:00
reply_type = NULL ;
2010-05-06 20:13:59 +02:00
was_split = maybe_split_method_name ( method_name , & split_interface_name , & split_method_name ) ;
target_method_name = was_split ? split_method_name : method_name ;
target_interface_name = was_split ? split_interface_name : proxy - > priv - > interface_name ;
2010-08-18 17:35:25 +02:00
/* Warn if method is unexpected (cf. :g-interface-info) */
if ( ! was_split )
2010-05-06 20:13:59 +02:00
{
2010-08-18 17:35:25 +02:00
const GDBusMethodInfo * expected_method_info ;
expected_method_info = lookup_method_info_or_warn ( proxy , target_method_name ) ;
if ( expected_method_info ! = NULL )
reply_type = _g_dbus_compute_complete_signature ( expected_method_info - > out_args ) ;
2010-05-06 20:13:59 +02:00
}
2010-08-18 17:35:25 +02:00
destination = NULL ;
if ( proxy - > priv - > name ! = NULL )
2010-05-06 20:13:59 +02:00
{
2010-08-18 17:35:25 +02:00
destination = get_destination_for_call ( proxy ) ;
if ( destination = = NULL )
{
g_set_error_literal ( error ,
G_IO_ERROR ,
G_IO_ERROR_FAILED ,
_ ( " Cannot invoke method; proxy is for a well-known name without an owner and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag " ) ) ;
2010-09-04 19:24:50 +02:00
ret = NULL ;
2010-08-18 17:35:25 +02:00
goto out ;
}
2010-05-06 20:13:59 +02:00
}
2010-05-10 17:47:08 +02:00
ret = g_dbus_connection_call_sync ( proxy - > priv - > connection ,
2010-08-18 17:35:25 +02:00
destination ,
2010-05-10 17:47:08 +02:00
proxy - > priv - > object_path ,
target_interface_name ,
target_method_name ,
parameters ,
2010-05-24 22:46:24 +02:00
reply_type ,
2010-05-10 17:47:08 +02:00
flags ,
timeout_msec = = - 1 ? proxy - > priv - > timeout_msec : timeout_msec ,
cancellable ,
error ) ;
2010-05-24 22:46:24 +02:00
2010-08-18 17:35:25 +02:00
out :
2010-05-24 22:46:24 +02:00
if ( reply_type ! = NULL )
g_variant_type_free ( reply_type ) ;
2010-05-06 20:13:59 +02:00
g_free ( split_interface_name ) ;
return ret ;
}
/* ---------------------------------------------------------------------------------------------------- */
2011-04-08 21:14:47 +02:00
static GDBusInterfaceInfo *
_g_dbus_proxy_get_info ( GDBusInterface * interface )
{
GDBusProxy * proxy = G_DBUS_PROXY ( interface ) ;
return g_dbus_proxy_get_interface_info ( proxy ) ;
}
static GDBusObject *
_g_dbus_proxy_get_object ( GDBusInterface * interface )
{
2011-04-08 22:12:33 +02:00
GDBusProxy * proxy = G_DBUS_PROXY ( interface ) ;
return proxy - > priv - > object ;
2011-04-08 21:14:47 +02:00
}
static void
_g_dbus_proxy_set_object ( GDBusInterface * interface ,
GDBusObject * object )
{
2011-04-08 22:12:33 +02:00
GDBusProxy * proxy = G_DBUS_PROXY ( interface ) ;
if ( proxy - > priv - > object ! = NULL )
g_object_remove_weak_pointer ( G_OBJECT ( proxy - > priv - > object ) , ( gpointer * ) & proxy - > priv - > object ) ;
proxy - > priv - > object = object ;
if ( proxy - > priv - > object ! = NULL )
g_object_add_weak_pointer ( G_OBJECT ( proxy - > priv - > object ) , ( gpointer * ) & proxy - > priv - > object ) ;
2011-04-08 21:14:47 +02:00
}
static void
dbus_interface_iface_init ( GDBusInterfaceIface * dbus_interface_iface )
{
dbus_interface_iface - > get_info = _g_dbus_proxy_get_info ;
dbus_interface_iface - > get_object = _g_dbus_proxy_get_object ;
dbus_interface_iface - > set_object = _g_dbus_proxy_set_object ;
}
/* ---------------------------------------------------------------------------------------------------- */