mountoperation: use the Shell DBus proxy if available

Make GMountOperation look for an owner of org.Gtk.MountOperationHandler
if possible, and use it instead of the GTK-based dialogs.
This allows applications to use the implementation offered by the
desktop shell, if available, through a DBus private interface:
org.Gtk.MountOperationHandler.

https://bugzilla.gnome.org/show_bug.cgi?id=674963
This commit is contained in:
Cosimo Cecchi 2012-06-20 21:36:09 -04:00
parent fb91fa2fbd
commit 44fd03eb47
3 changed files with 416 additions and 32 deletions

View File

@ -864,6 +864,15 @@ gtk_base_c_sources = \
gtk_c_sources = $(gtk_base_c_sources)
gtk_all_c_sources = $(gtk_base_c_sources)
gtk_dbus_built_sources = gtkdbusgenerated.c gtkdbusgenerated.h
$(gtk_dbus_built_sources) : Makefile.am gtkdbusinterfaces.xml
gdbus-codegen \
--interface-prefix org.Gtk. \
--c-namespace Gtk \
--generate-c-code gtkdbusgenerated \
gtkdbusinterfaces.xml
gtk_os_unix_c_sources = \
gtkcustompaperunixdialog.c \
gtkpagesetupunixdialog.c \
@ -875,7 +884,8 @@ gtk_os_unix_c_sources = \
gtkprintoperation-unix.c \
gtkprintunixdialog.c \
gtkprintbackend.c \
gtksearchenginetracker.c
gtksearchenginetracker.c \
$(gtk_dbus_built_sources)
gtk_all_c_sources += $(gtk_os_unix_c_sources)
if OS_UNIX
gtk_private_h_sources += \
@ -989,12 +999,14 @@ gtk_built_public_sources = \
# built headers that don't get installed
gtk_built_private_headers = \
gtkdbusgenerated.h \
gtkresources.h \
gtkmarshalers.h \
gtkbuiltincache.h \
gtkprivatetypebuiltins.h
gtk_built_sources = \
gtkdbusgenerated.c \
gtkresources.c \
gtktypebuiltins.c \
gtktypefuncs.c \

91
gtk/gtkdbusinterfaces.xml Normal file
View File

@ -0,0 +1,91 @@
<node>
<interface name="org.Gtk.MountOperationHandler">
<!--
AskPassword:
@id: an opaque ID identifying the object for which the operation is requested.
The ID must be unique in the context of the calling process.
@message: the message to display
@icon_name: the name of an icon to display
@default_user: the default username for display
@default_domain: the default domain for display
@flags: a set of GAskPasswordFlags
@response: a GMountOperationResult
@response_details: a dictionary containing the response details as
entered by the user. The dictionary MAY contain the following properties:
- "password" -> (s): a password to be used to complete the mount operation
- "password_save" -> (u): a GPasswordSave
The dialog will stay visible until clients call the Close() method, or
another dialog becomes visible.
Calling AskPassword again for the same id will have the effect to clear
the existing dialog and update it with a message indicating the previous
attempt went wrong.
-->
<method name="AskPassword">
<arg type="s" direction="in" name="id"/>
<arg type="s" direction="in" name="message"/>
<arg type="s" direction="in" name="icon_name"/>
<arg type="s" direction="in" name="default_user"/>
<arg type="s" direction="in" name="default_domain"/>
<arg type="u" direction="in" name="flags"/>
<arg type="u" direction="out" name="response"/>
<arg type="a{sv}" direction="out" name="response_details"/>
</method>
<!--
AskQuestion:
@id: an opaque ID identifying the object for which the operation is requested
The ID must be unique in the context of the calling process.
@message: the message to display
@icon_name: the name of an icon to display
@choices: an array of choice strings
GetResponse:
@response: a GMountOperationResult
@response_details: a dictionary containing the response details as
entered by the user. The dictionary MAY contain the following properties:
- "choice" -> (i): the chosen answer among the array of strings passed in
The dialog will stay visible until clients call the Close() method, or
another dialog becomes visible.
Calling AskQuestion again for the same id will have the effect to clear
update the dialog with the new question.
-->
<method name="AskQuestion">
<arg type="s" direction="in" name="id"/>
<arg type="s" direction="in" name="message"/>
<arg type="s" direction="in" name="icon_name"/>
<arg type="as" direction="in" name="choices"/>
<arg type="u" direction="out" name="response"/>
<arg type="a{sv}" direction="out" name="response_details"/>
</method>
<!--
ShowProcesses:
@id: an opaque ID identifying the object for which the operation is requested
The ID must be unique in the context of the calling process.
@message: the message to display
@icon_name: the name of an icon to display
@application_pids: the PIDs of the applications to display
@choices: an array of choice strings
@response: a GMountOperationResult
@response_details: a dictionary containing the response details as
entered by the user. The dictionary MAY contain the following properties:
- "choice" -> (i): the chosen answer among the array of strings passed in
The dialog will stay visible until clients call the Close() method, or
another dialog becomes visible.
Calling ShowProcesses again for the same id will have the effect to clear
the existing dialog and update it with the new message and the new list
of processes.
-->
<method name="ShowProcesses">
<arg type="s" direction="in" name="id"/>
<arg type="s" direction="in" name="message"/>
<arg type="s" direction="in" name="icon_name"/>
<arg type="ai" direction="in" name="application_pids"/>
<arg type="as" direction="in" name="choices"/>
<arg type="u" direction="out" name="response"/>
<arg type="a{sv}" direction="out" name="response_details"/>
</method>
<method name="Close"/>
</interface>
</node>

View File

@ -29,6 +29,7 @@
#include "gtkmountoperationprivate.h"
#include "gtkbox.h"
#include "gtkdbusgenerated.h"
#include "gtkentry.h"
#include "gtkbox.h"
#include "gtkintl.h"
@ -49,6 +50,8 @@
#include "gtkimagemenuitem.h"
#include "gtkmain.h"
#include <glib/gprintf.h>
/**
* SECTION:filesystem
* @short_description: Functions for working with GIO
@ -115,6 +118,11 @@ struct _GtkMountOperationPrivate {
GtkDialog *dialog;
GdkScreen *screen;
/* bus proxy */
GtkMountOperationHandler *handler;
GCancellable *cancellable;
gboolean handler_showing;
/* for the ask-password dialog */
GtkWidget *entry_container;
GtkWidget *username_entry;
@ -176,9 +184,22 @@ gtk_mount_operation_class_init (GtkMountOperationClass *klass)
static void
gtk_mount_operation_init (GtkMountOperation *operation)
{
gchar *name_owner;
operation->priv = G_TYPE_INSTANCE_GET_PRIVATE (operation,
GTK_TYPE_MOUNT_OPERATION,
GtkMountOperationPrivate);
operation->priv->handler =
gtk_mount_operation_handler_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
"org.gtk.MountOperationHandler",
"/org/gtk/MountOperationHandler",
NULL, NULL);
name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (operation->priv->handler));
if (!name_owner)
g_clear_object (&operation->priv->handler);
g_free (name_owner);
}
static void
@ -193,6 +214,9 @@ gtk_mount_operation_finalize (GObject *object)
if (priv->screen)
g_object_unref (priv->screen);
if (priv->handler)
g_object_unref (priv->handler);
G_OBJECT_CLASS (gtk_mount_operation_parent_class)->finalize (object);
}
@ -237,7 +261,7 @@ gtk_mount_operation_get_property (GObject *object,
break;
case PROP_IS_SHOWING:
g_value_set_boolean (value, priv->dialog != NULL);
g_value_set_boolean (value, priv->dialog != NULL || priv->handler_showing);
break;
case PROP_SCREEN:
@ -250,6 +274,21 @@ gtk_mount_operation_get_property (GObject *object,
}
}
static void
gtk_mount_operation_proxy_finish (GtkMountOperation *op,
GMountOperationResult result)
{
gtk_mount_operation_handler_call_close (op->priv->handler, NULL, NULL, NULL);
op->priv->handler_showing = FALSE;
g_object_notify (G_OBJECT (op), "is-showing");
g_mount_operation_reply (G_MOUNT_OPERATION (op), result);
/* drop the reference acquired when calling the proxy method */
g_object_unref (op);
}
static void
remember_button_toggled (GtkToggleButton *button,
GtkMountOperation *operation)
@ -436,13 +475,11 @@ table_add_entry (GtkWidget *table,
}
static void
gtk_mount_operation_ask_password (GMountOperation *mount_op,
const char *message,
const char *default_user,
const char *default_domain,
GAskPasswordFlags flags)
gtk_mount_operation_ask_password_do_gtk (GtkMountOperation *operation,
const gchar *message,
const gchar *default_user,
const gchar *default_domain)
{
GtkMountOperation *operation;
GtkMountOperationPrivate *priv;
GtkWidget *widget;
GtkDialog *dialog;
@ -455,11 +492,8 @@ gtk_mount_operation_ask_password (GMountOperation *mount_op,
guint rows;
const gchar *secondary;
operation = GTK_MOUNT_OPERATION (mount_op);
priv = operation->priv;
priv->ask_flags = flags;
widget = gtk_dialog_new ();
dialog = GTK_DIALOG (widget);
window = GTK_WINDOW (widget);
@ -538,7 +572,7 @@ gtk_mount_operation_ask_password (GMountOperation *mount_op,
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0);
can_anonymous = flags & G_ASK_PASSWORD_ANONYMOUS_SUPPORTED;
can_anonymous = priv->ask_flags & G_ASK_PASSWORD_ANONYMOUS_SUPPORTED;
priv->anonymous_toggle = NULL;
if (can_anonymous)
@ -570,13 +604,13 @@ gtk_mount_operation_ask_password (GMountOperation *mount_op,
rows = 0;
if (flags & G_ASK_PASSWORD_NEED_PASSWORD)
if (priv->ask_flags & G_ASK_PASSWORD_NEED_PASSWORD)
rows++;
if (flags & G_ASK_PASSWORD_NEED_USERNAME)
if (priv->ask_flags & G_ASK_PASSWORD_NEED_USERNAME)
rows++;
if (flags &G_ASK_PASSWORD_NEED_DOMAIN)
if (priv->ask_flags &G_ASK_PASSWORD_NEED_DOMAIN)
rows++;
/* The table that holds the entries */
@ -593,24 +627,25 @@ gtk_mount_operation_ask_password (GMountOperation *mount_op,
rows = 0;
priv->username_entry = NULL;
if (flags & G_ASK_PASSWORD_NEED_USERNAME)
if (priv->ask_flags & G_ASK_PASSWORD_NEED_USERNAME)
priv->username_entry = table_add_entry (table, rows++, _("_Username:"),
default_user, operation);
priv->domain_entry = NULL;
if (flags & G_ASK_PASSWORD_NEED_DOMAIN)
if (priv->ask_flags & G_ASK_PASSWORD_NEED_DOMAIN)
priv->domain_entry = table_add_entry (table, rows++, _("_Domain:"),
default_domain, operation);
priv->password_entry = NULL;
if (flags & G_ASK_PASSWORD_NEED_PASSWORD)
if (priv->ask_flags & G_ASK_PASSWORD_NEED_PASSWORD)
{
priv->password_entry = table_add_entry (table, rows++, _("_Password:"),
NULL, operation);
gtk_entry_set_visibility (GTK_ENTRY (priv->password_entry), FALSE);
}
if (flags & G_ASK_PASSWORD_SAVING_SUPPORTED)
if (priv->ask_flags & G_ASK_PASSWORD_SAVING_SUPPORTED)
{
GtkWidget *choice;
GtkWidget *remember_box;
@ -621,7 +656,7 @@ gtk_mount_operation_ask_password (GMountOperation *mount_op,
gtk_box_pack_start (GTK_BOX (vbox), remember_box,
FALSE, FALSE, 0);
password_save = g_mount_operation_get_password_save (mount_op);
password_save = g_mount_operation_get_password_save (G_MOUNT_OPERATION (operation));
choice = gtk_radio_button_new_with_mnemonic (NULL, _("Forget password _immediately"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (choice),
@ -681,6 +716,89 @@ gtk_mount_operation_ask_password (GMountOperation *mount_op,
g_object_ref (operation);
}
static void
call_password_proxy_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
GtkMountOperationHandler *proxy = GTK_MOUNT_OPERATION_HANDLER (source);
GMountOperation *op = user_data;
GMountOperationResult result;
GVariant *result_details;
GVariantIter iter;
const gchar *key;
GVariant *value;
GError *error = NULL;
if (!gtk_mount_operation_handler_call_ask_password_finish (proxy,
&result, &result_details, res, &error))
{
result = G_MOUNT_OPERATION_ABORTED;
g_warning ("Shell mount operation error: %s\n", error->message);
g_error_free (error);
goto out;
}
g_variant_iter_init (&iter, result_details);
while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
{
if (strcmp (key, "password") == 0)
g_mount_operation_set_password (op, g_variant_get_string (value, NULL));
else if (strcmp (key, "password_save") == 0)
g_mount_operation_set_password_save (op, g_variant_get_uint32 (value));
}
out:
gtk_mount_operation_proxy_finish (GTK_MOUNT_OPERATION (op), result);
}
static void
gtk_mount_operation_ask_password_do_proxy (GtkMountOperation *operation,
const char *message,
const char *default_user,
const char *default_domain)
{
gchar id[255];
g_sprintf(id, "GtkMountOperation%p", operation);
operation->priv->handler_showing = TRUE;
g_object_notify (G_OBJECT (operation), "is-showing");
/* keep a ref to the operation while the handler is showing */
g_object_ref (operation);
gtk_mount_operation_handler_call_ask_password (operation->priv->handler, id,
message, "drive-harddisk",
default_user, default_domain,
operation->priv->ask_flags, NULL,
call_password_proxy_cb, operation);
}
static void
gtk_mount_operation_ask_password (GMountOperation *mount_op,
const char *message,
const char *default_user,
const char *default_domain,
GAskPasswordFlags flags)
{
GtkMountOperation *operation;
GtkMountOperationPrivate *priv;
gboolean use_gtk;
operation = GTK_MOUNT_OPERATION (mount_op);
priv = operation->priv;
priv->ask_flags = flags;
use_gtk = (operation->priv->handler == NULL) ||
(priv->ask_flags & G_ASK_PASSWORD_NEED_DOMAIN) ||
(priv->ask_flags & G_ASK_PASSWORD_NEED_USERNAME);
if (use_gtk)
gtk_mount_operation_ask_password_do_gtk (operation, message, default_user, default_domain);
else
gtk_mount_operation_ask_password_do_proxy (operation, message, default_user, default_domain);
}
static void
question_dialog_button_clicked (GtkDialog *dialog,
gint button_number,
@ -707,9 +825,9 @@ question_dialog_button_clicked (GtkDialog *dialog,
}
static void
gtk_mount_operation_ask_question (GMountOperation *op,
const char *message,
const char *choices[])
gtk_mount_operation_ask_question_do_gtk (GtkMountOperation *op,
const char *message,
const char *choices[])
{
GtkMountOperationPrivate *priv;
GtkWidget *dialog;
@ -721,7 +839,7 @@ gtk_mount_operation_ask_question (GMountOperation *op,
g_return_if_fail (message != NULL);
g_return_if_fail (choices != NULL);
priv = GTK_MOUNT_OPERATION (op)->priv;
priv = op->priv;
primary = strstr (message, "\n");
if (primary)
@ -762,6 +880,77 @@ gtk_mount_operation_ask_question (GMountOperation *op,
g_object_ref (op);
}
static void
call_question_proxy_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
GtkMountOperationHandler *proxy = GTK_MOUNT_OPERATION_HANDLER (source);
GMountOperation *op = user_data;
GMountOperationResult result;
GVariant *result_details;
GVariantIter iter;
const gchar *key;
GVariant *value;
GError *error = NULL;
if (!gtk_mount_operation_handler_call_ask_question_finish (proxy, &result,
&result_details, res, &error))
{
result = G_MOUNT_OPERATION_ABORTED;
g_warning ("Shell mount operation error: %s\n", error->message);
g_error_free (error);
goto out;
}
g_variant_iter_init (&iter, result_details);
while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
{
if (strcmp (key, "choice") == 0)
g_mount_operation_set_choice (op, g_variant_get_int32 (value));
}
out:
gtk_mount_operation_proxy_finish (GTK_MOUNT_OPERATION (op), result);
}
static void
gtk_mount_operation_ask_question_do_proxy (GtkMountOperation *operation,
const char *message,
const char *choices[])
{
gchar id[255];
g_sprintf(id, "GtkMountOperation%p", operation);
operation->priv->handler_showing = TRUE;
g_object_notify (G_OBJECT (operation), "is-showing");
/* keep a ref to the operation while the handler is showing */
g_object_ref (operation);
gtk_mount_operation_handler_call_ask_question (operation->priv->handler, id,
message, "drive-harddisk",
choices, NULL,
call_question_proxy_cb, operation);
}
static void
gtk_mount_operation_ask_question (GMountOperation *op,
const char *message,
const char *choices[])
{
GtkMountOperation *operation;
gboolean use_gtk;
operation = GTK_MOUNT_OPERATION (op);
use_gtk = (operation->priv->handler == NULL);
if (use_gtk)
gtk_mount_operation_ask_question_do_gtk (operation, message, choices);
else
gtk_mount_operation_ask_question_do_proxy (operation, message, choices);
}
static void
show_processes_button_clicked (GtkDialog *dialog,
gint button_number,
@ -1174,7 +1363,7 @@ on_button_press_event_for_process_tree_view (GtkWidget *widget,
}
static GtkWidget *
create_show_processes_dialog (GMountOperation *op,
create_show_processes_dialog (GtkMountOperation *op,
const char *message,
const char *choices[])
{
@ -1193,7 +1382,7 @@ create_show_processes_dialog (GMountOperation *op,
GtkListStore *list_store;
gchar *s;
priv = GTK_MOUNT_OPERATION (op)->priv;
priv = op->priv;
primary = strstr (message, "\n");
if (primary)
@ -1306,10 +1495,74 @@ create_show_processes_dialog (GMountOperation *op,
}
static void
gtk_mount_operation_show_processes (GMountOperation *op,
const char *message,
GArray *processes,
const char *choices[])
call_processes_proxy_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
GtkMountOperationHandler *proxy = GTK_MOUNT_OPERATION_HANDLER (source);
GMountOperation *op = user_data;
GMountOperationResult result;
GVariant *result_details;
GVariantIter iter;
const gchar *key;
GVariant *value;
GError *error = NULL;
if (!gtk_mount_operation_handler_call_show_processes_finish (proxy,
&result, &result_details, res, &error))
{
result = G_MOUNT_OPERATION_ABORTED;
g_warning ("Shell mount operation error: %s\n", error->message);
g_error_free (error);
goto out;
}
/* If the request was unhandled it means we called the method again;
* in this case, just return and wait for the next response.
*/
if (result == G_MOUNT_OPERATION_UNHANDLED)
return;
g_variant_iter_init (&iter, result_details);
while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
{
if (strcmp (key, "choice") == 0)
g_mount_operation_set_choice (op, g_variant_get_int32 (value));
}
out:
gtk_mount_operation_proxy_finish (GTK_MOUNT_OPERATION (op), result);
}
static void
gtk_mount_operation_show_processes_do_proxy (GtkMountOperation *operation,
const char *message,
GArray *processes,
const char *choices[])
{
gchar id[255];
g_sprintf(id, "GtkMountOperation%p", operation);
operation->priv->handler_showing = TRUE;
g_object_notify (G_OBJECT (operation), "is-showing");
/* keep a ref to the operation while the handler is showing */
g_object_ref (operation);
gtk_mount_operation_handler_call_show_processes (operation->priv->handler, id,
message, "drive-harddisk",
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
processes->data, processes->len,
sizeof (GPid)),
choices, NULL,
call_processes_proxy_cb, operation);
}
static void
gtk_mount_operation_show_processes_do_gtk (GtkMountOperation *op,
const char *message,
GArray *processes,
const char *choices[])
{
GtkMountOperationPrivate *priv;
GtkWidget *dialog = NULL;
@ -1319,7 +1572,7 @@ gtk_mount_operation_show_processes (GMountOperation *op,
g_return_if_fail (processes != NULL);
g_return_if_fail (choices != NULL);
priv = GTK_MOUNT_OPERATION (op)->priv;
priv = op->priv;
if (priv->process_list_store == NULL)
{
@ -1329,7 +1582,7 @@ gtk_mount_operation_show_processes (GMountOperation *op,
/* otherwise, we're showing the dialog, assume messages+choices hasn't changed */
update_process_list_store (GTK_MOUNT_OPERATION (op),
update_process_list_store (op,
priv->process_list_store,
processes);
@ -1339,6 +1592,26 @@ gtk_mount_operation_show_processes (GMountOperation *op,
}
}
static void
gtk_mount_operation_show_processes (GMountOperation *op,
const char *message,
GArray *processes,
const char *choices[])
{
GtkMountOperation *operation;
gboolean use_gtk;
operation = GTK_MOUNT_OPERATION (op);
use_gtk = (operation->priv->handler == NULL);
if (use_gtk)
gtk_mount_operation_show_processes_do_gtk (operation, message, processes, choices);
else
gtk_mount_operation_show_processes_do_proxy (operation, message, processes, choices);
}
static void
gtk_mount_operation_aborted (GMountOperation *op)
{
@ -1353,6 +1626,14 @@ gtk_mount_operation_aborted (GMountOperation *op)
g_object_notify (G_OBJECT (op), "is-showing");
g_object_unref (op);
}
if (priv->handler != NULL)
{
gtk_mount_operation_handler_call_close (priv->handler, NULL, NULL, NULL);
priv->handler_showing = FALSE;
g_object_notify (G_OBJECT (op), "is-showing");
}
}
/**