mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-29 23:42:17 +01:00 
			
		
		
		
	This fixes bug #624696.
Incorporates a more recent change from 1dc774a653 to drop the
`g_type_init()` call, and reformats the indentation a bit.
Fixes: #322
		
	
		
			
				
	
	
		
			451 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			451 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| #include <gio/gio.h>
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| /* The D-Bus interface definition we want to create a GDBusProxy-derived type for: */
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static const gchar introspection_xml[] =
 | |
|   "<node>"
 | |
|   "  <interface name='org.freedesktop.Accounts.User'>"
 | |
|   "    <method name='Frobnicate'>"
 | |
|   "      <arg name='flux' type='s' direction='in'/>"
 | |
|   "      <arg name='baz' type='s' direction='in'/>"
 | |
|   "      <arg name='result' type='s' direction='out'/>"
 | |
|   "    </method>"
 | |
|   "    <signal name='Changed'/>"
 | |
|   "    <property name='AutomaticLogin' type='b' access='readwrite'/>"
 | |
|   "    <property name='RealName' type='s' access='read'/>"
 | |
|   "    <property name='UserName' type='s' access='read'/>"
 | |
|   "  </interface>"
 | |
|   "</node>";
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| /* Definition of the AccountsUser type */
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| #define ACCOUNTS_TYPE_USER         (accounts_user_get_type ())
 | |
| #define ACCOUNTS_USER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), ACCOUNTS_TYPE_USER, AccountsUser))
 | |
| #define ACCOUNTS_USER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), ACCOUNTS_TYPE_USER, AccountsUserClass))
 | |
| #define ACCOUNTS_USER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), ACCOUNTS_TYPE_USER, AccountsUserClass))
 | |
| #define ACCOUNTS_IS_USER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ACCOUNTS_TYPE_USER))
 | |
| #define ACCOUNTS_IS_USER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), ACCOUNTS_TYPE_USER))
 | |
| 
 | |
| typedef struct _AccountsUser        AccountsUser;
 | |
| typedef struct _AccountsUserClass   AccountsUserClass;
 | |
| typedef struct _AccountsUserPrivate AccountsUserPrivate;
 | |
| 
 | |
| struct _AccountsUser
 | |
| {
 | |
|   /*< private >*/
 | |
|   GDBusProxy parent_instance;
 | |
|   AccountsUserPrivate *priv;
 | |
| };
 | |
| 
 | |
| struct _AccountsUserClass
 | |
| {
 | |
|   /*< private >*/
 | |
|   GDBusProxyClass parent_class;
 | |
|   void (*changed) (AccountsUser *user);
 | |
| };
 | |
| 
 | |
| GType        accounts_user_get_type            (void) G_GNUC_CONST;
 | |
| 
 | |
| const gchar *accounts_user_get_user_name       (AccountsUser        *user);
 | |
| const gchar *accounts_user_get_real_name       (AccountsUser        *user);
 | |
| gboolean     accounts_user_get_automatic_login (AccountsUser        *user);
 | |
| 
 | |
| void         accounts_user_frobnicate          (AccountsUser        *user,
 | |
|                                                 const gchar         *flux,
 | |
|                                                 gint                 baz,
 | |
|                                                 GCancellable        *cancellable,
 | |
|                                                 GAsyncReadyCallback  callback,
 | |
|                                                 gpointer             user_data);
 | |
| gchar       *accounts_user_frobnicate_finish   (AccountsUser        *user,
 | |
|                                                 GAsyncResult        *res,
 | |
|                                                 GError             **error);
 | |
| gchar       *accounts_user_frobnicate_sync     (AccountsUser        *user,
 | |
|                                                 const gchar         *flux,
 | |
|                                                 gint                 baz,
 | |
|                                                 GCancellable        *cancellable,
 | |
|                                                 GError             **error);
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| /* Implementation of the AccountsUser type */
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| /* A more efficient approach than parsing XML is to use const static
 | |
|  * GDBusInterfaceInfo, GDBusMethodInfo, ... structures
 | |
|  */
 | |
| static GDBusInterfaceInfo *
 | |
| accounts_user_get_interface_info (void)
 | |
| {
 | |
|   static gsize has_info = 0;
 | |
|   static GDBusInterfaceInfo *info = NULL;
 | |
|   if (g_once_init_enter (&has_info))
 | |
|     {
 | |
|       GDBusNodeInfo *introspection_data;
 | |
|       introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
 | |
|       info = introspection_data->interfaces[0];
 | |
|       g_once_init_leave (&has_info, 1);
 | |
|     }
 | |
|   return info;
 | |
| }
 | |
| 
 | |
| enum
 | |
| {
 | |
|   PROP_0,
 | |
|   PROP_USER_NAME,
 | |
|   PROP_REAL_NAME,
 | |
|   PROP_AUTOMATIC_LOGIN,
 | |
| };
 | |
| 
 | |
| enum
 | |
| {
 | |
|   CHANGED_SIGNAL,
 | |
|   LAST_SIGNAL
 | |
| };
 | |
| 
 | |
| static guint signals[LAST_SIGNAL] = {0};
 | |
| 
 | |
| G_DEFINE_TYPE (AccountsUser, accounts_user, G_TYPE_DBUS_PROXY)
 | |
| 
 | |
| static void
 | |
| accounts_user_init (AccountsUser *user)
 | |
| {
 | |
|   /* Sets the expected interface */
 | |
|   g_dbus_proxy_set_interface_info (G_DBUS_PROXY (user), accounts_user_get_interface_info ());
 | |
| }
 | |
| 
 | |
| static void
 | |
| accounts_user_get_property (GObject    *object,
 | |
|                             guint       prop_id,
 | |
|                             GValue     *value,
 | |
|                             GParamSpec *pspec)
 | |
| {
 | |
|   AccountsUser *user = ACCOUNTS_USER (object);
 | |
| 
 | |
|   switch (prop_id)
 | |
|     {
 | |
|     case PROP_USER_NAME:
 | |
|       g_value_set_string (value, accounts_user_get_user_name (user));
 | |
|       break;
 | |
| 
 | |
|     case PROP_REAL_NAME:
 | |
|       g_value_set_string (value, accounts_user_get_real_name (user));
 | |
|       break;
 | |
| 
 | |
|     case PROP_AUTOMATIC_LOGIN:
 | |
|       g_value_set_boolean (value, accounts_user_get_automatic_login (user));
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| const gchar *
 | |
| accounts_user_get_user_name (AccountsUser *user)
 | |
| {
 | |
|   GVariant *value;
 | |
|   const gchar *ret;
 | |
|   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
 | |
|   value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "UserName");
 | |
|   ret = g_variant_get_string (value, NULL);
 | |
|   g_variant_unref (value);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| const gchar *
 | |
| accounts_user_get_real_name (AccountsUser *user)
 | |
| {
 | |
|   GVariant *value;
 | |
|   const gchar *ret;
 | |
|   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
 | |
|   value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "RealName");
 | |
|   ret = g_variant_get_string (value, NULL);
 | |
|   g_variant_unref (value);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| gboolean
 | |
| accounts_user_get_automatic_login (AccountsUser *user)
 | |
| {
 | |
|   GVariant *value;
 | |
|   gboolean ret;
 | |
|   g_return_val_if_fail (ACCOUNTS_IS_USER (user), FALSE);
 | |
|   value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "AutomaticLogin");
 | |
|   ret = g_variant_get_boolean (value);
 | |
|   g_variant_unref (value);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| static void
 | |
| accounts_user_g_signal (GDBusProxy   *proxy,
 | |
|                         const gchar  *sender_name,
 | |
|                         const gchar  *signal_name,
 | |
|                         GVariant     *parameters)
 | |
| {
 | |
|   AccountsUser *user = ACCOUNTS_USER (proxy);
 | |
|   if (g_strcmp0 (signal_name, "Changed") == 0)
 | |
|     g_signal_emit (user, signals[CHANGED_SIGNAL], 0);
 | |
| }
 | |
| 
 | |
| static void
 | |
| accounts_user_g_properties_changed (GDBusProxy          *proxy,
 | |
|                                     GVariant            *changed_properties,
 | |
|                                     const gchar* const  *invalidated_properties)
 | |
| {
 | |
|   AccountsUser *user = ACCOUNTS_USER (proxy);
 | |
|   GVariantIter *iter;
 | |
|   const gchar *key;
 | |
| 
 | |
|   if (changed_properties != NULL)
 | |
|     {
 | |
|       g_variant_get (changed_properties, "a{sv}", &iter);
 | |
|       while (g_variant_iter_next (iter, "{&sv}", &key, NULL))
 | |
|         {
 | |
|           if (g_strcmp0 (key, "AutomaticLogin") == 0)
 | |
|             g_object_notify (G_OBJECT (user), "automatic-login");
 | |
|           else if (g_strcmp0 (key, "RealName") == 0)
 | |
|             g_object_notify (G_OBJECT (user), "real-name");
 | |
|           else if (g_strcmp0 (key, "UserName") == 0)
 | |
|             g_object_notify (G_OBJECT (user), "user-name");
 | |
|         }
 | |
|       g_variant_iter_free (iter);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| accounts_user_class_init (AccountsUserClass *klass)
 | |
| {
 | |
|   GObjectClass *gobject_class;
 | |
|   GDBusProxyClass *proxy_class;
 | |
| 
 | |
|   gobject_class = G_OBJECT_CLASS (klass);
 | |
|   gobject_class->get_property = accounts_user_get_property;
 | |
| 
 | |
|   proxy_class = G_DBUS_PROXY_CLASS (klass);
 | |
|   proxy_class->g_signal             = accounts_user_g_signal;
 | |
|   proxy_class->g_properties_changed = accounts_user_g_properties_changed;
 | |
| 
 | |
|   g_object_class_install_property (gobject_class,
 | |
|                                    PROP_USER_NAME,
 | |
|                                    g_param_spec_string ("user-name",
 | |
|                                                         "User Name",
 | |
|                                                         "The user name of the user",
 | |
|                                                         NULL,
 | |
|                                                         G_PARAM_READABLE |
 | |
|                                                         G_PARAM_STATIC_STRINGS));
 | |
| 
 | |
|   g_object_class_install_property (gobject_class,
 | |
|                                    PROP_REAL_NAME,
 | |
|                                    g_param_spec_string ("real-name",
 | |
|                                                         "Real Name",
 | |
|                                                         "The real name of the user",
 | |
|                                                         NULL,
 | |
|                                                         G_PARAM_READABLE |
 | |
|                                                         G_PARAM_STATIC_STRINGS));
 | |
| 
 | |
|   g_object_class_install_property (gobject_class,
 | |
|                                    PROP_AUTOMATIC_LOGIN,
 | |
|                                    g_param_spec_boolean ("automatic-login",
 | |
|                                                          "Automatic Login",
 | |
|                                                          "Whether the user is automatically logged in",
 | |
|                                                          FALSE,
 | |
|                                                          G_PARAM_READABLE |
 | |
|                                                          G_PARAM_STATIC_STRINGS));
 | |
| 
 | |
|   signals[CHANGED_SIGNAL] = g_signal_new ("changed",
 | |
|                                           ACCOUNTS_TYPE_USER,
 | |
|                                           G_SIGNAL_RUN_LAST,
 | |
|                                           G_STRUCT_OFFSET (AccountsUserClass, changed),
 | |
|                                           NULL,
 | |
|                                           NULL,
 | |
|                                           g_cclosure_marshal_VOID__VOID,
 | |
|                                           G_TYPE_NONE,
 | |
|                                           0);
 | |
| }
 | |
| 
 | |
| gchar *
 | |
| accounts_user_frobnicate_sync (AccountsUser        *user,
 | |
|                                const gchar         *flux,
 | |
|                                gint                 baz,
 | |
|                                GCancellable        *cancellable,
 | |
|                                GError             **error)
 | |
| {
 | |
|   gchar *ret;
 | |
|   GVariant *value;
 | |
| 
 | |
|   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
 | |
| 
 | |
|   ret = NULL;
 | |
| 
 | |
|   value = g_dbus_proxy_call_sync (G_DBUS_PROXY (user),
 | |
|                                   "Frobnicate",
 | |
|                                   g_variant_new ("(si)",
 | |
|                                                  flux,
 | |
|                                                  baz),
 | |
|                                   G_DBUS_CALL_FLAGS_NONE,
 | |
|                                   -1,
 | |
|                                   cancellable,
 | |
|                                   error);
 | |
|   if (value != NULL)
 | |
|     {
 | |
|       g_variant_get (value, "(s)", &ret);
 | |
|       g_variant_unref (value);
 | |
|     }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| void
 | |
| accounts_user_frobnicate (AccountsUser        *user,
 | |
|                           const gchar         *flux,
 | |
|                           gint                 baz,
 | |
|                           GCancellable        *cancellable,
 | |
|                           GAsyncReadyCallback  callback,
 | |
|                           gpointer             user_data)
 | |
| {
 | |
|   g_return_if_fail (ACCOUNTS_IS_USER (user));
 | |
|   g_dbus_proxy_call (G_DBUS_PROXY (user),
 | |
|                      "Frobnicate",
 | |
|                      g_variant_new ("(si)",
 | |
|                                     flux,
 | |
|                                     baz),
 | |
|                      G_DBUS_CALL_FLAGS_NONE,
 | |
|                      -1,
 | |
|                      cancellable,
 | |
|                      callback,
 | |
|                      user_data);
 | |
| }
 | |
| 
 | |
| 
 | |
| gchar *
 | |
| accounts_user_frobnicate_finish (AccountsUser        *user,
 | |
|                                  GAsyncResult        *res,
 | |
|                                  GError             **error)
 | |
| {
 | |
|   gchar *ret;
 | |
|   GVariant *value;
 | |
| 
 | |
|   ret = NULL;
 | |
|   value = g_dbus_proxy_call_finish (G_DBUS_PROXY (user), res, error);
 | |
|   if (value != NULL)
 | |
|     {
 | |
|       g_variant_get (value, "(s)", &ret);
 | |
|       g_variant_unref (value);
 | |
|     }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| /* Example usage of the AccountsUser type */
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static void
 | |
| print_user (AccountsUser *user)
 | |
| {
 | |
|   g_print ("  user-name       = `%s'\n", accounts_user_get_user_name (user));
 | |
|   g_print ("  real-name       = `%s'\n", accounts_user_get_real_name (user));
 | |
|   g_print ("  automatic-login = %s\n", accounts_user_get_automatic_login (user) ? "true" : "false");
 | |
| }
 | |
| 
 | |
| static void
 | |
| on_changed (AccountsUser *user,
 | |
|             gpointer      user_data)
 | |
| {
 | |
|   g_print ("+++ Received the AccountsUser::changed signal\n");
 | |
|   print_user (user);
 | |
| }
 | |
| 
 | |
| static void
 | |
| on_notify (GObject    *object,
 | |
|            GParamSpec *pspec,
 | |
|            gpointer    user_data)
 | |
| {
 | |
|   AccountsUser *user = ACCOUNTS_USER (object);
 | |
|   g_print ("+++ Received the GObject::notify signal for property `%s'\n",
 | |
|            pspec->name);
 | |
|   print_user (user);
 | |
| }
 | |
| 
 | |
| static void
 | |
| on_accounts_proxy_available (GObject      *object,
 | |
|                              GAsyncResult *result,
 | |
|                              gpointer      user_data)
 | |
| {
 | |
|   GError *error = NULL;
 | |
|   GObject *user_object;
 | |
|   AccountsUser *user;
 | |
| 
 | |
|   user_object = g_async_initable_new_finish (G_ASYNC_INITABLE (object),
 | |
|                                              result,
 | |
|                                              &error);
 | |
|   if (!user_object)
 | |
|     {
 | |
|       g_error ("Failed to create proxy: %s", error->message);
 | |
|       g_clear_error (&error);
 | |
|       return;
 | |
|     }
 | |
|   user = ACCOUNTS_USER (user_object);
 | |
| 
 | |
|   g_print ("+++ Acquired proxy for user\n");
 | |
|   print_user (user);
 | |
| 
 | |
|   g_signal_connect (user,
 | |
|                     "notify",
 | |
|                     G_CALLBACK (on_notify),
 | |
|                     NULL);
 | |
|   g_signal_connect (user,
 | |
|                     "changed",
 | |
|                     G_CALLBACK (on_changed),
 | |
|                     NULL);
 | |
| }
 | |
| 
 | |
| static void
 | |
| on_accounts_appeared (GDBusConnection *connection,
 | |
|                       const gchar     *name,
 | |
|                       const gchar     *name_owner,
 | |
|                       gpointer         user_data)
 | |
| {
 | |
|   g_async_initable_new_async (ACCOUNTS_TYPE_USER, 0, NULL,
 | |
|                               on_accounts_proxy_available,
 | |
|                               "g-flags", 0,
 | |
|                               "g-interface-info", NULL,
 | |
|                               "g-unique-bus-name", name_owner,
 | |
|                               "g-connection", connection,
 | |
|                               "g-object-path", "/org/freedesktop/Accounts/User500",
 | |
|                               "g-interface-name", "org.freedesktop.Accounts.User");
 | |
| }
 | |
| 
 | |
| static void
 | |
| on_accounts_vanished (GDBusConnection *connection,
 | |
|                       const gchar     *name,
 | |
|                       gpointer         user_data)
 | |
| {
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| gint
 | |
| main (gint argc, gchar *argv[])
 | |
| {
 | |
|   guint watcher_id;
 | |
|   GMainLoop *loop;
 | |
| 
 | |
|   watcher_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
 | |
|                                  "org.freedesktop.Accounts",
 | |
|                                  G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
 | |
|                                  on_accounts_appeared,
 | |
|                                  on_accounts_vanished,
 | |
|                                  NULL, NULL);
 | |
| 
 | |
|   loop = g_main_loop_new (NULL, FALSE);
 | |
|   g_main_loop_run (loop);
 | |
|   g_main_loop_unref (loop);
 | |
|   g_bus_unwatch_name (watcher_id);
 | |
| 
 | |
|   return 0;
 | |
| }
 |