diff options
author | Stef Walter <stefw@collabora.co.uk> | 2011-11-01 09:00:48 +0100 |
---|---|---|
committer | Stef Walter <stefw@collabora.co.uk> | 2011-12-13 21:45:09 +0100 |
commit | 4f19ddbf4e1f9c84594e6967584e4ad60254f828 (patch) | |
tree | fe55cc2484c0518d469e70b2b226f320fc218886 | |
parent | 6f8691b7260aa1f4c9b520b75c1a0c10170fa004 (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-- | .gitignore | 1 | ||||
-rw-r--r-- | configure.ac | 14 | ||||
-rw-r--r-- | gcr/Makefile.am | 9 | ||||
-rw-r--r-- | gcr/gcr-dbus-constants.h | 2 | ||||
-rw-r--r-- | gcr/gcr-prompter-tool.c | 109 | ||||
-rw-r--r-- | gcr/gcr-system-prompt.c | 22 | ||||
-rw-r--r-- | gcr/gcr-system-prompter.c | 46 | ||||
-rw-r--r-- | gcr/org.gnome.keyring.Prompter.service.in | 3 | ||||
-rw-r--r-- | gcr/tests/Makefile.am | 1 |
9 files changed, 186 insertions, 21 deletions
@@ -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 |