From 873cedbc95777e7b74960a66883c48945fcecd4c Mon Sep 17 00:00:00 2001 From: monsta Date: Tue, 5 Jan 2016 17:38:52 +0300 Subject: rename mate-panel-*.{c|h} -> panel-*.{c|h} for consistency (libmate-panel-applet files are left alone since there are public header files used by all panel applets) --- .../panel-applet-container.c | 798 +++++++++++++++++++++ 1 file changed, 798 insertions(+) create mode 100644 mate-panel/libmate-panel-applet-private/panel-applet-container.c (limited to 'mate-panel/libmate-panel-applet-private/panel-applet-container.c') diff --git a/mate-panel/libmate-panel-applet-private/panel-applet-container.c b/mate-panel/libmate-panel-applet-private/panel-applet-container.c new file mode 100644 index 00000000..7aa34d6a --- /dev/null +++ b/mate-panel/libmate-panel-applet-private/panel-applet-container.c @@ -0,0 +1,798 @@ +/* + * panel-applet-container.c: a container for applets. + * + * Copyright (C) 2010 Carlos Garcia Campos + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include +#if GTK_CHECK_VERSION (3, 0, 0) +#include +#endif +#include "panel-applet-container.h" +#include "panel-marshal.h" + +struct _MatePanelAppletContainerPrivate { + GDBusProxy *applet_proxy; + + guint name_watcher_id; + gchar *bus_name; + + guint32 xid; + GtkWidget *socket; + + GHashTable *pending_ops; +}; + +enum { + APPLET_BROKEN, + APPLET_MOVE, + APPLET_REMOVE, + APPLET_LOCK, + CHILD_PROPERTY_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct { + const gchar *name; + const gchar *dbus_name; +} AppletPropertyInfo; + +static const AppletPropertyInfo applet_properties [] = { + { "prefs-path", "PrefsPath" }, + { "orient", "Orient" }, + { "size", "Size" }, + { "size-hints", "SizeHints" }, + { "background", "Background" }, + { "flags", "Flags" }, + { "locked", "Locked" }, + { "locked-down", "LockedDown" } +}; + +#define MATE_PANEL_APPLET_CONTAINER_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_APPLET_CONTAINER, MatePanelAppletContainerPrivate)) + +#define MATE_PANEL_APPLET_BUS_NAME "org.mate.panel.applet.%s" +#define MATE_PANEL_APPLET_FACTORY_INTERFACE "org.mate.panel.applet.AppletFactory" +#define MATE_PANEL_APPLET_FACTORY_OBJECT_PATH "/org/mate/panel/applet/%s" +#define MATE_PANEL_APPLET_INTERFACE "org.mate.panel.applet.Applet" + +static gboolean mate_panel_applet_container_plug_removed (MatePanelAppletContainer *container); + +G_DEFINE_TYPE (MatePanelAppletContainer, mate_panel_applet_container, GTK_TYPE_EVENT_BOX); + +GQuark mate_panel_applet_container_error_quark (void) +{ + return g_quark_from_static_string ("mate-panel-applet-container-error-quark"); +} + +static void mate_panel_applet_container_init(MatePanelAppletContainer* container) +{ + container->priv = MATE_PANEL_APPLET_CONTAINER_GET_PRIVATE (container); + + container->priv->socket = gtk_socket_new (); + g_signal_connect_swapped (container->priv->socket, "plug-removed", G_CALLBACK (mate_panel_applet_container_plug_removed), container); + + container->priv->pending_ops = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); + + gtk_container_add (GTK_CONTAINER (container), + container->priv->socket); + gtk_widget_show (container->priv->socket); +} + +static void +mate_panel_applet_container_cancel_pending_operations (MatePanelAppletContainer *container) +{ + GList *keys, *l; + + if (!container->priv->pending_ops) + return; + + keys = g_hash_table_get_keys (container->priv->pending_ops); + for (l = keys; l; l = g_list_next (l)) { + GCancellable *cancellable; + + cancellable = G_CANCELLABLE (g_hash_table_lookup (container->priv->pending_ops, l->data)); + g_cancellable_cancel (cancellable); + } + g_list_free (keys); +} + +static void +mate_panel_applet_container_dispose (GObject *object) +{ + MatePanelAppletContainer *container = MATE_PANEL_APPLET_CONTAINER (object); + + if (container->priv->pending_ops) { + mate_panel_applet_container_cancel_pending_operations (container); + g_hash_table_destroy (container->priv->pending_ops); + container->priv->pending_ops = NULL; + } + + if (container->priv->bus_name) { + g_free (container->priv->bus_name); + container->priv->bus_name = NULL; + } + + if (container->priv->name_watcher_id > 0) { + g_bus_unwatch_name (container->priv->name_watcher_id); + container->priv->name_watcher_id = 0; + } + + if (container->priv->applet_proxy) { + g_object_unref (container->priv->applet_proxy); + container->priv->applet_proxy = NULL; + } + + G_OBJECT_CLASS (mate_panel_applet_container_parent_class)->dispose (object); +} + +static void +mate_panel_applet_container_class_init (MatePanelAppletContainerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (MatePanelAppletContainerPrivate)); + + gobject_class->dispose = mate_panel_applet_container_dispose; + + signals[APPLET_BROKEN] = + g_signal_new ("applet-broken", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MatePanelAppletContainerClass, applet_broken), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals[APPLET_MOVE] = + g_signal_new ("applet-move", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MatePanelAppletContainerClass, applet_move), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals[APPLET_REMOVE] = + g_signal_new ("applet-remove", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MatePanelAppletContainerClass, applet_remove), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals[APPLET_LOCK] = + g_signal_new ("applet-lock", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MatePanelAppletContainerClass, applet_lock), + NULL, + NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, G_TYPE_BOOLEAN); + signals[CHILD_PROPERTY_CHANGED] = + g_signal_new ("child-property-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | + G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET (MatePanelAppletContainerClass, child_property_changed), + NULL, + NULL, + panel_marshal_VOID__STRING_POINTER, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_POINTER); +} + +static const AppletPropertyInfo * +mate_panel_applet_container_child_property_get_info (const gchar *property_name) +{ + gint i; + + g_assert (property_name != NULL); + + for (i = 0; i < G_N_ELEMENTS (applet_properties); i++) { + if (g_ascii_strcasecmp (applet_properties[i].name, property_name) == 0) + return &applet_properties[i]; + } + + return NULL; +} + +GtkWidget * +mate_panel_applet_container_new (void) +{ + GtkWidget *container; + + container = GTK_WIDGET (g_object_new (PANEL_TYPE_APPLET_CONTAINER, NULL)); + + return container; +} + +static gboolean +mate_panel_applet_container_plug_removed (MatePanelAppletContainer *container) +{ + if (!container->priv->applet_proxy) + return FALSE; + + mate_panel_applet_container_cancel_pending_operations (container); + + if (container->priv->name_watcher_id > 0) { + g_bus_unwatch_name (container->priv->name_watcher_id); + container->priv->name_watcher_id = 0; + } + + g_object_unref (container->priv->applet_proxy); + container->priv->applet_proxy = NULL; + + g_signal_emit (container, signals[APPLET_BROKEN], 0); + + /* Continue destroying, in case of reloading + * a new frame widget is created + */ + return FALSE; +} + +static void +mate_panel_applet_container_child_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + MatePanelAppletContainer *container) +{ + if (g_strcmp0 (signal_name, "Move") == 0) { + g_signal_emit (container, signals[APPLET_MOVE], 0); + } else if (g_strcmp0 (signal_name, "RemoveFromPanel") == 0) { + g_signal_emit (container, signals[APPLET_REMOVE], 0); + } else if (g_strcmp0 (signal_name, "Lock") == 0) { + g_signal_emit (container, signals[APPLET_LOCK], 0, TRUE); + } else if (g_strcmp0 (signal_name, "Unlock") == 0) { + g_signal_emit (container, signals[APPLET_LOCK], 0, FALSE); + } +} + +static void +on_property_changed (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + MatePanelAppletContainer *container) +{ + GVariant *props; + GVariantIter iter; + GVariant *value; + gchar *key; + + g_variant_get (parameters, "(s@a{sv}*)", NULL, &props, NULL); + + g_variant_iter_init (&iter, props); + while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) { + if (g_strcmp0 (key, "Flags") == 0) { + g_signal_emit (container, signals[CHILD_PROPERTY_CHANGED], + g_quark_from_string ("flags"), + "flags", value); + } else if (g_strcmp0 (key, "SizeHints") == 0) { + g_signal_emit (container, signals[CHILD_PROPERTY_CHANGED], + g_quark_from_string ("size-hints"), + "size-hints", value); + } + } + + g_variant_unref (props); +} + +static void +on_proxy_appeared (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + MatePanelAppletContainer *container; + GDBusProxy *proxy; + GError *error = NULL; + + proxy = g_dbus_proxy_new_finish (res, &error); + if (!proxy) { + g_simple_async_result_set_from_error (result, error); + g_error_free (error); + g_simple_async_result_complete (result); + g_object_unref (result); + + return; + } + + container = MATE_PANEL_APPLET_CONTAINER (g_async_result_get_source_object (G_ASYNC_RESULT (result))); + + container->priv->applet_proxy = proxy; + g_signal_connect (container->priv->applet_proxy, "g-signal", + G_CALLBACK (mate_panel_applet_container_child_signal), + container); + g_dbus_connection_signal_subscribe (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + g_dbus_proxy_get_object_path (proxy), + MATE_PANEL_APPLET_INTERFACE, + G_DBUS_SIGNAL_FLAGS_NONE, + (GDBusSignalCallback) on_property_changed, + container, NULL); + + g_simple_async_result_complete (result); + g_object_unref (result); + + if (container->priv->xid > 0) { + gtk_socket_add_id (GTK_SOCKET (container->priv->socket), + container->priv->xid); + } + + /* g_async_result_get_source_object returns new ref */ + g_object_unref (container); +} + +static void +get_applet_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *connection = G_DBUS_CONNECTION (source_object); + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + MatePanelAppletContainer *container; + GVariant *retvals; + const gchar *applet_path; + GError *error = NULL; + + retvals = g_dbus_connection_call_finish (connection, res, &error); + if (!retvals) { + g_simple_async_result_set_from_error (result, error); + g_error_free (error); + g_simple_async_result_complete (result); + g_object_unref (result); + + return; + } + + container = MATE_PANEL_APPLET_CONTAINER (g_async_result_get_source_object (G_ASYNC_RESULT (result))); + g_variant_get (retvals, "(&ou)", &applet_path, &container->priv->xid); + + g_dbus_proxy_new (connection, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + container->priv->bus_name, + applet_path, + MATE_PANEL_APPLET_INTERFACE, + NULL, + (GAsyncReadyCallback) on_proxy_appeared, + result); + + g_variant_unref (retvals); + + /* g_async_result_get_source_object returns new ref */ + g_object_unref (container); +} + +typedef struct { + GSimpleAsyncResult *result; + gchar *factory_id; + GVariant *parameters; + GCancellable *cancellable; +} AppletFactoryData; + +static void +applet_factory_data_free (AppletFactoryData *data) +{ + g_free (data->factory_id); + if (data->cancellable) + g_object_unref (data->cancellable); + + g_free (data); +} + +static void +on_factory_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + AppletFactoryData *data) +{ + MatePanelAppletContainer *container; + gchar *object_path; + + container = MATE_PANEL_APPLET_CONTAINER (g_async_result_get_source_object (G_ASYNC_RESULT (data->result))); + container->priv->bus_name = g_strdup (name_owner); + object_path = g_strdup_printf (MATE_PANEL_APPLET_FACTORY_OBJECT_PATH, data->factory_id); + g_dbus_connection_call (connection, + name_owner, + object_path, + MATE_PANEL_APPLET_FACTORY_INTERFACE, + "GetApplet", + data->parameters, + G_VARIANT_TYPE ("(ou)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + data->cancellable, + get_applet_cb, + data->result); + g_free (object_path); +} + +static void +mate_panel_applet_container_get_applet (MatePanelAppletContainer *container, + GdkScreen *screen, + const gchar *iid, + GVariant *props, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + AppletFactoryData *data; + gint screen_number; + gchar *bus_name; + gchar *factory_id; + gchar *applet_id; + + result = g_simple_async_result_new (G_OBJECT (container), + callback, + user_data, + mate_panel_applet_container_get_applet); + + applet_id = g_strrstr (iid, "::"); + if (!applet_id) { + g_simple_async_result_set_error (result, + MATE_PANEL_APPLET_CONTAINER_ERROR, + MATE_PANEL_APPLET_CONTAINER_INVALID_APPLET, + "Invalid applet iid: %s", iid); + g_simple_async_result_complete (result); + g_object_unref (result); + + return; + } + + factory_id = g_strndup (iid, strlen (iid) - strlen (applet_id)); + applet_id += 2; + + /* we can't use the screen of the container widget since it's not in a + * widget hierarchy yet */ + screen_number = gdk_screen_get_number (screen); + + data = g_new (AppletFactoryData, 1); + data->result = result; + data->factory_id = factory_id; + data->parameters = g_variant_new ("(si*)", applet_id, screen_number, props); + data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + bus_name = g_strdup_printf (MATE_PANEL_APPLET_BUS_NAME, factory_id); + + container->priv->name_watcher_id = + g_bus_watch_name (G_BUS_TYPE_SESSION, + bus_name, + G_BUS_NAME_WATCHER_FLAGS_AUTO_START, + (GBusNameAppearedCallback) on_factory_appeared, + NULL, + data, + (GDestroyNotify) applet_factory_data_free); + + g_free (bus_name); +} + +void +mate_panel_applet_container_add (MatePanelAppletContainer *container, + GdkScreen *screen, + const gchar *iid, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + GVariant *properties) +{ + g_return_if_fail (PANEL_IS_APPLET_CONTAINER (container)); + g_return_if_fail (iid != NULL); + + mate_panel_applet_container_cancel_pending_operations (container); + + mate_panel_applet_container_get_applet (container, screen, iid, properties, + cancellable, callback, user_data); +} + +gboolean +mate_panel_applet_container_add_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == mate_panel_applet_container_get_applet); + + return !g_simple_async_result_propagate_error (simple, error); +} + +/* Child Properties */ +static void +set_applet_property_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *connection = G_DBUS_CONNECTION (source_object); + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + MatePanelAppletContainer *container; + GVariant *retvals; + GError *error = NULL; + + retvals = g_dbus_connection_call_finish (connection, res, &error); + if (!retvals) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Error setting property: %s\n", error->message); + g_simple_async_result_set_from_error (result, error); + g_error_free (error); + } else { + g_variant_unref (retvals); + } + + container = MATE_PANEL_APPLET_CONTAINER (g_async_result_get_source_object (G_ASYNC_RESULT (result))); + g_hash_table_remove (container->priv->pending_ops, result); + g_simple_async_result_complete (result); + g_object_unref (result); + + /* g_async_result_get_source_object returns new ref */ + g_object_unref (container); +} + +void +mate_panel_applet_container_child_set (MatePanelAppletContainer *container, + const gchar *property_name, + const GVariant *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GDBusProxy *proxy = container->priv->applet_proxy; + const AppletPropertyInfo *info; + GSimpleAsyncResult *result; + + if (!proxy) + return; + + info = mate_panel_applet_container_child_property_get_info (property_name); + if (!info) { + g_simple_async_report_error_in_idle (G_OBJECT (container), + callback, user_data, + MATE_PANEL_APPLET_CONTAINER_ERROR, + MATE_PANEL_APPLET_CONTAINER_INVALID_CHILD_PROPERTY, + "%s: Applet has no child property named `%s'", + G_STRLOC, property_name); + return; + } + + result = g_simple_async_result_new (G_OBJECT (container), + callback, + user_data, + mate_panel_applet_container_child_set); + + if (cancellable) + g_object_ref (cancellable); + else + cancellable = g_cancellable_new (); + g_hash_table_insert (container->priv->pending_ops, result, cancellable); + + g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + g_dbus_proxy_get_object_path (proxy), + "org.freedesktop.DBus.Properties", + "Set", + g_variant_new ("(ssv)", + g_dbus_proxy_get_interface_name (proxy), + info->dbus_name, + value), + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, cancellable, + set_applet_property_cb, + result); +} + +gboolean +mate_panel_applet_container_child_set_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == mate_panel_applet_container_child_set); + + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +get_applet_property_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *connection = G_DBUS_CONNECTION (source_object); + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + MatePanelAppletContainer *container; + GVariant *retvals; + GError *error = NULL; + + retvals = g_dbus_connection_call_finish (connection, res, &error); + if (!retvals) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Error getting property: %s\n", error->message); + g_simple_async_result_set_from_error (result, error); + g_error_free (error); + } else { + GVariant *value, *item; + + item = g_variant_get_child_value (retvals, 0); + value = g_variant_get_variant (item); + g_variant_unref (item); + g_simple_async_result_set_op_res_gpointer (result, value, + (GDestroyNotify) g_variant_unref); + g_variant_unref (retvals); + } + + container = MATE_PANEL_APPLET_CONTAINER (g_async_result_get_source_object (G_ASYNC_RESULT (result))); + g_hash_table_remove (container->priv->pending_ops, result); + g_simple_async_result_complete (result); + g_object_unref (result); + + /* g_async_result_get_source_object returns new ref */ + g_object_unref (container); +} + +void +mate_panel_applet_container_child_get (MatePanelAppletContainer *container, + const gchar *property_name, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GDBusProxy *proxy = container->priv->applet_proxy; + const AppletPropertyInfo *info; + GSimpleAsyncResult *result; + + if (!proxy) + return; + + info = mate_panel_applet_container_child_property_get_info (property_name); + if (!info) { + g_simple_async_report_error_in_idle (G_OBJECT (container), + callback, user_data, + MATE_PANEL_APPLET_CONTAINER_ERROR, + MATE_PANEL_APPLET_CONTAINER_INVALID_CHILD_PROPERTY, + "%s: Applet has no child property named `%s'", + G_STRLOC, property_name); + return; + } + + result = g_simple_async_result_new (G_OBJECT (container), + callback, + user_data, + mate_panel_applet_container_child_get); + if (cancellable) + g_object_ref (cancellable); + else + cancellable = g_cancellable_new (); + g_hash_table_insert (container->priv->pending_ops, result, cancellable); + + g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + g_dbus_proxy_get_object_path (proxy), + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", + g_dbus_proxy_get_interface_name (proxy), + info->dbus_name), + G_VARIANT_TYPE ("(v)"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, cancellable, + get_applet_property_cb, + result); +} + +GVariant * +mate_panel_applet_container_child_get_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == mate_panel_applet_container_child_get); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + return g_variant_ref (g_simple_async_result_get_op_res_gpointer (simple)); +} + +static void +child_popup_menu_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *connection = G_DBUS_CONNECTION (source_object); + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + GVariant *retvals; + GError *error = NULL; + + retvals = g_dbus_connection_call_finish (connection, res, &error); + if (!retvals) { + g_simple_async_result_set_from_error (result, error); + g_error_free (error); + } else { + g_variant_unref (retvals); + } + + g_simple_async_result_complete (result); + g_object_unref (result); +} + +void +mate_panel_applet_container_child_popup_menu (MatePanelAppletContainer *container, + guint button, + guint32 timestamp, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + GDBusProxy *proxy = container->priv->applet_proxy; + + if (!proxy) + return; + + result = g_simple_async_result_new (G_OBJECT (container), + callback, + user_data, + mate_panel_applet_container_child_popup_menu); + + g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + g_dbus_proxy_get_object_path (proxy), + MATE_PANEL_APPLET_INTERFACE, + "PopupMenu", + g_variant_new ("(uu)", button, timestamp), + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, cancellable, + child_popup_menu_cb, + result); +} + +gboolean +mate_panel_applet_container_child_popup_menu_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == mate_panel_applet_container_child_popup_menu); + + return !g_simple_async_result_propagate_error (simple, error); +} -- cgit v1.2.1