[gcr] gcr: Fix dialog layout, and add dbus service



commit 4f19ddbf4e1f9c84594e6967584e4ad60254f828
Author: Stef Walter <stefw collabora co uk>
Date:   Tue Nov 1 09:00:48 2011 +0100

    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

 .gitignore                                |    1 +
 configure.ac                              |   14 ++++
 gcr/Makefile.am                           |    9 +++
 gcr/gcr-dbus-constants.h                  |    2 +
 gcr/gcr-prompter-tool.c                   |  109 +++++++++++++++++++++++++----
 gcr/gcr-system-prompt.c                   |   22 +++++-
 gcr/gcr-system-prompter.c                 |   46 +++++++++++-
 gcr/org.gnome.keyring.Prompter.service.in |    3 +
 gcr/tests/Makefile.am                     |    1 +
 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
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]