summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@collabora.co.uk>2011-11-01 09:00:48 +0100
committerStef Walter <stefw@collabora.co.uk>2011-12-13 21:45:09 +0100
commit4f19ddbf4e1f9c84594e6967584e4ad60254f828 (patch)
treefe55cc2484c0518d469e70b2b226f320fc218886
parent6f8691b7260aa1f4c9b520b75c1a0c10170fa004 (diff)
gcr: Fix dialog layout, and add dbus service
* A bunch of bug fixes and other fixes to the default prompter tool * Add support for making the dialog transient
-rw-r--r--.gitignore1
-rw-r--r--configure.ac14
-rw-r--r--gcr/Makefile.am9
-rw-r--r--gcr/gcr-dbus-constants.h2
-rw-r--r--gcr/gcr-prompter-tool.c109
-rw-r--r--gcr/gcr-system-prompt.c22
-rw-r--r--gcr/gcr-system-prompter.c46
-rw-r--r--gcr/org.gnome.keyring.Prompter.service.in3
-rw-r--r--gcr/tests/Makefile.am1
9 files changed, 186 insertions, 21 deletions
diff --git a/.gitignore b/.gitignore
index 3f5599f..eeffca7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,7 @@ frob-*
*.o
*.plist
*.pot
+*.service
*.stamp
*.tar.gz
*.typelib
diff --git a/configure.ac b/configure.ac
index eff8f86..c26d9fa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -170,6 +170,20 @@ AC_ARG_ENABLE(update-mime,
[don't run update-mime-database utility (useful for packages) ]))
AM_CONDITIONAL(WITH_UPDATE_MIME, test "$enable_update_mime" != "no")
+# ----------------------------------------------------------------------
+# DBus services
+
+AC_ARG_WITH(dbus-services,
+ [AC_HELP_STRING([--with-dbus-services=<dir>],
+ [where D-BUS session services directory is])])
+if ! test -z "$with_dbus_services" ; then
+ DBUS_SERVICES_DIR="$with_dbus_services"
+else
+ DBUS_SERVICES_DIR="$datadir/dbus-1/services"
+fi
+
+AC_SUBST(DBUS_SERVICES_DIR)
+
# --------------------------------------------------------------------
# Compilation and linking options
#
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index adeb3e6..631b62d 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -305,6 +305,13 @@ desktop_in_files = $(desktop_in_in_files:.desktop.in.in=.desktop.in)
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
@INTLTOOL_DESKTOP_RULE@
+service_in_files = org.gnome.keyring.Prompter.service.in
+servicedir = $(DBUS_SERVICES_DIR)
+service_DATA = $(service_in_files:.service.in=.service)
+
+$(service_DATA): $(service_in_files) Makefile
+ @sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
+
# ----------------------------------------------------------------
# TOOLS
@@ -413,11 +420,13 @@ EXTRA_DIST = \
$(desktop_in_in_files) \
$(desktop_in_files) \
$(desktop_DATA) \
+ $(service_in_files ) \
$(mime_DATA)
CLEANFILES = \
$(BUILT_SOURCES) \
$(pkgconfig_DATA) \
+ $(service_DATA) \
gcr-actual.abi \
gcr-actual-base.abi \
gcr-expected.abi \
diff --git a/gcr/gcr-dbus-constants.h b/gcr/gcr-dbus-constants.h
index d47c6f3..ac3787f 100644
--- a/gcr/gcr-dbus-constants.h
+++ b/gcr/gcr-dbus-constants.h
@@ -38,6 +38,8 @@ G_BEGIN_DECLS
#define GCR_DBUS_PROMPTER_METHOD_BEGIN "BeginPrompting"
#define GCR_DBUS_PROMPTER_METHOD_FINISH "FinishPrompting"
+#define GCR_DBUS_PROMPTER_SIGNAL_READY "PrompterReady"
+
#define GCR_DBUS_PROMPT_INTERFACE "org.gnome.keyring.Prompter.Prompt"
#define GCR_DBUS_PROMPT_ERROR_IN_PROGRESS "org.gnome.keyring.Prompter.InProgress"
diff --git a/gcr/gcr-prompter-tool.c b/gcr/gcr-prompter-tool.c
index aa5cebf..86ca293 100644
--- a/gcr/gcr-prompter-tool.c
+++ b/gcr/gcr-prompter-tool.c
@@ -31,6 +31,7 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
#include <pango/pango.h>
#include <locale.h>
@@ -39,6 +40,7 @@
#define LOG_ERRORS 1
#define GRAB_KEYBOARD 1
+#define QUIT_TIMEOUT 10
static GcrSystemPrompter *the_prompter = NULL;
@@ -70,6 +72,7 @@ typedef struct {
PromptMode mode;
GdkDevice *grabbed_device;
gulong grab_broken_id;
+ guint quit_timeout;
} GcrPrompterDialog;
typedef struct {
@@ -78,20 +81,47 @@ typedef struct {
G_DEFINE_TYPE (GcrPrompterDialog, gcr_prompter_dialog, GTK_TYPE_DIALOG);
+static gboolean
+on_timeout_quit ()
+{
+ gtk_main_quit ();
+ return FALSE; /* Don't run again */
+}
+
static void
-on_show_prompt (GcrSystemPrompter *prompter,
+start_timeout (GcrPrompterDialog *self)
+{
+ if (g_getenv ("GCR_PERSIST") != NULL)
+ return;
+
+ if (!self->quit_timeout)
+ self->quit_timeout = g_timeout_add_seconds (QUIT_TIMEOUT, on_timeout_quit, NULL);
+}
+
+static void
+stop_timeout (GcrPrompterDialog *self)
+{
+ if (self->quit_timeout)
+ g_source_remove (self->quit_timeout);
+ self->quit_timeout = 0;
+}
+
+static void
+on_open_prompt (GcrSystemPrompter *prompter,
gpointer user_data)
{
GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (user_data);
gtk_widget_show (GTK_WIDGET (self));
+ stop_timeout (self);
}
static void
-on_hide_prompt (GcrSystemPrompter *prompter,
- gpointer user_data)
+on_close_prompt (GcrSystemPrompter *prompter,
+ gpointer user_data)
{
GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (user_data);
gtk_widget_hide (GTK_WIDGET (self));
+ start_timeout (self);
}
static gboolean
@@ -154,6 +184,7 @@ on_responded (GcrSystemPrompter *prompter,
gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
gtk_widget_hide (GTK_WIDGET (self->image));
gtk_widget_show (GTK_WIDGET (self->spinner));
+ self->mode = PROMPT_NONE;
}
static const gchar *
@@ -370,6 +401,37 @@ handle_password_response (GcrPrompterDialog *self)
}
static void
+gcr_prompter_dialog_realize (GtkWidget *widget)
+{
+ gboolean modal = FALSE;
+ const gchar *value;
+ gulong caller_window_id;
+ GdkWindow *caller_window;
+ GdkWindow *self_window;
+ GdkDisplay *display;
+ gchar *end;
+
+ GTK_WIDGET_CLASS (gcr_prompter_dialog_parent_class)->realize (widget);
+
+ value= gcr_system_prompter_get_caller_window (the_prompter);
+ if (value) {
+ caller_window_id = strtoul (value, &end, 10);
+ if (caller_window_id && end && end[0] == '\0') {
+ display = gtk_widget_get_display (widget);
+ caller_window = gdk_x11_window_foreign_new_for_display (display, caller_window_id);
+ if (caller_window) {
+ self_window = gtk_widget_get_window (widget);
+ gdk_window_set_transient_for (self_window, caller_window);
+ g_object_unref (caller_window);
+ modal = TRUE;
+ }
+ }
+ }
+
+ gtk_window_set_modal (GTK_WINDOW (widget), modal);
+}
+
+static void
gcr_prompter_dialog_response (GtkDialog *dialog,
gint response_id)
{
@@ -395,54 +457,70 @@ gcr_prompter_dialog_init (GcrPrompterDialog *self)
GtkDialog *dialog;
GtkWidget *widget;
GtkWidget *entry;
+ GtkWidget *content;
GtkGrid *grid;
g_assert (GCR_IS_SYSTEM_PROMPTER (the_prompter));
- g_signal_connect (the_prompter, "show-prompt", G_CALLBACK (on_show_prompt), self);
+ g_signal_connect (the_prompter, "open", G_CALLBACK (on_open_prompt), self);
g_signal_connect (the_prompter, "prompt-password", G_CALLBACK (on_prompt_password), self);
g_signal_connect (the_prompter, "prompt-confirm", G_CALLBACK (on_prompt_confirm), self);
g_signal_connect (the_prompter, "responded", G_CALLBACK (on_responded), self);
- g_signal_connect (the_prompter, "hide-prompt", G_CALLBACK (on_hide_prompt), self);
+ g_signal_connect (the_prompter, "close", G_CALLBACK (on_close_prompt), self);
dialog = GTK_DIALOG (self);
gtk_dialog_add_buttons (dialog,
- _("Continue"), GTK_RESPONSE_OK,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ _("Continue"), GTK_RESPONSE_OK,
NULL);
+ content = gtk_dialog_get_content_area (dialog);
+
grid = GTK_GRID (gtk_grid_new ());
+ gtk_container_set_border_width (GTK_CONTAINER (grid), 6);
+ gtk_widget_set_hexpand (GTK_WIDGET (grid), TRUE);
+ gtk_grid_set_column_spacing (grid, 12);
+ gtk_grid_set_row_spacing (grid, 6);
/* The prompt image */
self->image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION,
- GTK_ICON_SIZE_DIALOG),
+ GTK_ICON_SIZE_DIALOG);
+ gtk_widget_set_valign (self->image, GTK_ALIGN_START);
gtk_grid_attach (grid, self->image, -1, 0, 1, 4);
gtk_widget_show (self->image);
/* The prompt spinner */
self->spinner = gtk_spinner_new ();
+ gtk_widget_set_valign (self->image, GTK_ALIGN_START);
gtk_grid_attach (grid, self->spinner, -2, -1, 1, 4);
gtk_widget_show (self->spinner);
- /* The title label */
+ /* The message label */
widget = gtk_label_new ("");
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_LARGE));
gtk_label_set_attributes (GTK_LABEL (widget), attrs);
pango_attr_list_unref (attrs);
- g_object_bind_property (the_prompter, "title", widget, "label", G_BINDING_DEFAULT);
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_widget_set_margin_bottom (widget, 8);
+ g_object_bind_property (the_prompter, "message", widget, "label", G_BINDING_DEFAULT);
gtk_grid_attach (grid, widget, 0, 0, 2, 1);
gtk_widget_show (widget);
/* The description label */
widget = gtk_label_new ("");
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_widget_set_margin_bottom (widget, 4);
g_object_bind_property (the_prompter, "description", widget, "label", G_BINDING_DEFAULT);
gtk_grid_attach (grid, widget, 0, 1, 2, 1);
gtk_widget_show (widget);
/* The password label */
widget = gtk_label_new (_("Password:"));
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
g_object_bind_property (self, "password-visible", widget, "visible", G_BINDING_DEFAULT);
gtk_grid_attach (grid, widget, 0, 2, 1, 1);
@@ -450,23 +528,27 @@ gcr_prompter_dialog_init (GcrPrompterDialog *self)
self->password_buffer = gcr_secure_entry_buffer_new ();
entry = gtk_entry_new_with_buffer (self->password_buffer);
gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
+ gtk_widget_set_hexpand (widget, TRUE);
g_object_bind_property (self, "password-visible", entry, "visible", G_BINDING_DEFAULT);
gtk_grid_attach (grid, entry, 1, 2, 1, 1);
/* The confirm label */
widget = gtk_label_new (_("Confirm:"));
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
gtk_grid_attach (grid, widget, 0, 3, 1, 1);
/* The confirm entry */
self->confirm_buffer = gcr_secure_entry_buffer_new ();
widget = gtk_entry_new_with_buffer (self->password_buffer);
+ gtk_widget_set_hexpand (widget, TRUE);
gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
gtk_grid_attach (grid, widget, 1, 3, 1, 1);
/* The quality progress bar */
widget = gtk_progress_bar_new ();
+ gtk_widget_set_hexpand (widget, TRUE);
g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
gtk_grid_attach (grid, widget, 1, 4, 1, 1);
g_signal_connect (entry, "changed", G_CALLBACK (on_password_changed), widget);
@@ -489,8 +571,7 @@ gcr_prompter_dialog_init (GcrPrompterDialog *self)
g_object_bind_property (the_prompter, "choice-chosen", widget, "active", G_BINDING_BIDIRECTIONAL);
gtk_grid_attach (grid, widget, 0, 6, 2, 1);
- gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)),
- GTK_WIDGET (grid));
+ gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid));
gtk_widget_show (GTK_WIDGET (grid));
g_signal_connect (self, "map-event", G_CALLBACK (grab_keyboard), self);
@@ -541,6 +622,9 @@ gcr_prompter_dialog_class_init (GcrPrompterDialogClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ widget_class->realize = gcr_prompter_dialog_realize;
gobject_class->finalize = gcr_prompter_dialog_finalize;
gobject_class->get_property = gcr_prompter_dialog_get_property;
@@ -577,7 +661,7 @@ on_name_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
- g_printerr ("bus name acquired");
+
}
static void
@@ -585,7 +669,6 @@ on_name_lost (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
- g_printerr ("bus name lost, quitting");
gtk_main_quit ();
}
diff --git a/gcr/gcr-system-prompt.c b/gcr/gcr-system-prompt.c
index eeb615c..165f3e3 100644
--- a/gcr/gcr-system-prompt.c
+++ b/gcr/gcr-system-prompt.c
@@ -202,6 +202,17 @@ gcr_system_prompt_get_property (GObject *obj,
}
static void
+gcr_system_prompt_constructed (GObject *obj)
+{
+ GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
+
+ G_OBJECT_CLASS (gcr_system_prompt_parent_class)->constructed (obj);
+
+ if (self->pv->prompter_bus_name == NULL)
+ self->pv->prompter_bus_name = g_strdup (GCR_DBUS_PROMPTER_BUS_NAME);
+}
+
+static void
gcr_system_prompt_dispose (GObject *obj)
{
GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
@@ -253,6 +264,7 @@ gcr_system_prompt_class_init (GcrSystemPromptClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->constructed = gcr_system_prompt_constructed;
gobject_class->get_property = gcr_system_prompt_get_property;
gobject_class->set_property = gcr_system_prompt_set_property;
gobject_class->dispose = gcr_system_prompt_dispose;
@@ -589,7 +601,7 @@ gcr_system_prompt_real_init (GInitable *initable,
G_DBUS_CALL_FLAGS_NONE,
-1, cancellable, error);
if (ret == NULL) {
- _gcr_debug ("failed to open prompt: %s",
+ _gcr_debug ("failed to open prompt %s: %s", self->pv->prompter_bus_name,
egg_error_result_message (error));
return FALSE;
}
@@ -599,7 +611,7 @@ gcr_system_prompt_real_init (GInitable *initable,
g_variant_get (ret, "(o)", &self->pv->prompt_path);
g_variant_unref (ret);
- _gcr_debug ("opened prompt: %s", self->pv->prompt_path);
+ _gcr_debug ("opened prompt %s: %s", self->pv->prompter_bus_name, self->pv->prompt_path);
}
/* 3. Create a dbus proxy */
@@ -689,13 +701,15 @@ on_prompter_begin_prompting (GObject *source,
g_variant_get (ret, "(o)", &self->pv->prompt_path);
g_variant_unref (ret);
- _gcr_debug ("opened prompt: %s", self->pv->prompt_path);
+ _gcr_debug ("opened prompt %s: %s",
+ self->pv->prompter_bus_name, self->pv->prompt_path);
g_return_if_fail (self->pv->prompt_path != NULL);
perform_init_async (self, res);
} else {
- _gcr_debug ("failed to open prompt: %s", egg_error_message (error));
+ _gcr_debug ("failed to open prompt %s: %s",
+ self->pv->prompter_bus_name, egg_error_message (error));
g_simple_async_result_take_error (res, error);
g_simple_async_result_complete (res);
diff --git a/gcr/gcr-system-prompter.c b/gcr/gcr-system-prompter.c
index 173d0ec..3f8546b 100644
--- a/gcr/gcr-system-prompter.c
+++ b/gcr/gcr-system-prompter.c
@@ -665,6 +665,25 @@ gcr_system_prompter_class_init (GcrSystemPrompterClass *klass)
}
static void
+emit_prompter_ready (GcrSystemPrompter *self)
+{
+ GError *error = NULL;
+
+ /* Now let everyone else know, we're ready! */
+ g_dbus_connection_emit_signal (self->pv->connection, NULL,
+ GCR_DBUS_PROMPTER_OBJECT_PATH,
+ GCR_DBUS_PROMPTER_INTERFACE,
+ GCR_DBUS_PROMPTER_SIGNAL_READY,
+ g_variant_new ("()"),
+ &error);
+
+ if (error != NULL) {
+ g_warning ("couldn't emit prompter ready signal: %s", egg_error_message (error));
+ g_error_free (error);
+ }
+}
+
+static void
on_owner_vanished (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
@@ -675,9 +694,7 @@ on_owner_vanished (GDBusConnection *connection,
gcr_system_prompter_respond_cancelled (self);
finish_prompting (self);
-
- /* Now let everyone else know, we're ready! */
- _gcr_prompter_emit_prompter_ready (GCR_PROMPTER (self));
+ emit_prompter_ready (self);
}
static GVariant *
@@ -769,6 +786,8 @@ prompter_method_finish_prompting (GcrSystemPrompter *self,
finish_prompting (self);
g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+
+ emit_prompter_ready (self);
}
static void
@@ -1022,16 +1041,27 @@ gcr_system_prompter_set_choice_chosen (GcrSystemPrompter *self,
prompt_emit_changed (self, GCR_DBUS_PROMPT_PROPERTY_CHOICE_CHOSEN);
}
+/**
+ * gcr_system_prompter_get_caller_window:
+ * @self: a prompter
+ *
+ * Get a string containing the callers window identifier. If the prompter
+ * supports making its prompts transient for
+ */
const gchar *
gcr_system_prompter_get_caller_window (GcrSystemPrompter *self)
{
GVariant *variant;
+ const gchar *window;
g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), NULL);
variant = g_hash_table_lookup (self->pv->properties, GCR_DBUS_PROMPT_PROPERTY_CALLER_WINDOW);
g_return_val_if_fail (variant != NULL, NULL);
- return g_variant_get_string (variant, NULL);
+ window = g_variant_get_string (variant, NULL);
+ if (!window || !window[0])
+ return NULL;
+ return window;
}
/**
@@ -1149,6 +1179,14 @@ gcr_system_prompter_respond_confirmed (GcrSystemPrompter *self)
g_signal_emit (self, signals[RESPONDED], 0);
}
+/**
+ * gcr_system_prompter_new:
+ *
+ * Create a new system prompter service. This prompter won't do anything unless
+ * you connect to its signals and show appropriate prompts.
+ *
+ * Returns: (transfer full): a new prompter service
+ */
GcrSystemPrompter *
gcr_system_prompter_new (void)
{
diff --git a/gcr/org.gnome.keyring.Prompter.service.in b/gcr/org.gnome.keyring.Prompter.service.in
new file mode 100644
index 0000000..5bf95eb
--- /dev/null
+++ b/gcr/org.gnome.keyring.Prompter.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.keyring.Prompter
+Exec=@libexecdir@/gcr-prompter
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index 165c7ec..f4a945c 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -67,6 +67,7 @@ noinst_PROGRAMS = \
frob-openpgp \
frob-parser \
frob-request \
+ frob-system-prompt \
frob-unlock \
frob-unlock-options