[gnome-flashback] polkit: initial version
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] polkit: initial version
- Date: Mon, 24 Aug 2015 15:43:18 +0000 (UTC)
commit ae1f0bfa0ad0d653c31c50f98a248efaf10a7c03
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Mon Aug 24 18:30:21 2015 +0300
polkit: initial version
Origial PolicyKit-gnome:
https://git.gnome.org/browse/PolicyKit-gnome/
https://bugzilla.gnome.org/show_bug.cgi?id=739539
configure.ac | 7 +
data/org.gnome.gnome-flashback.gschema.xml.in.in | 5 +
gnome-flashback/Makefile.am | 2 +
gnome-flashback/flashback-application.c | 4 +
gnome-flashback/flashback.gresource.xml | 1 +
gnome-flashback/libpolkit/Makefile.am | 40 +
.../libpolkit/flashback-authenticator.c | 534 ++++++++++
.../libpolkit/flashback-authenticator.h | 50 +
gnome-flashback/libpolkit/flashback-listener.c | 233 +++++
gnome-flashback/libpolkit/flashback-listener.h | 58 ++
.../libpolkit/flashback-polkit-dialog.c | 1018 ++++++++++++++++++++
.../libpolkit/flashback-polkit-dialog.h | 59 ++
.../libpolkit/flashback-polkit-dialog.ui | 253 +++++
gnome-flashback/libpolkit/flashback-polkit.c | 114 +++
gnome-flashback/libpolkit/flashback-polkit.h | 33 +
po/POTFILES.in | 4 +
16 files changed, 2415 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index c064bd8..6e5fd25 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,6 +36,8 @@ LIBGNOME_DESKTOP_REQUIRED=3.12.0
CANBERRA_REQUIRED=0.13
GLIB_REQUIRED=2.44.0
GSETTINGS_DESKTOP_SCHEMAS_REQUIRED=3.12.0
+POLKIT_AGENT_REQUIRED=0.97
+POLKIT_GOBJECT_REQUIRED=0.97
PKG_CHECK_MODULES(GNOME_FLASHBACK, gtk+-3.0 >= $GTK_REQUIRED dbus-glib-1)
AC_SUBST(GNOME_FLASHBACK_CFLAGS)
@@ -61,6 +63,10 @@ PKG_CHECK_MODULES(IDLE_MONITOR, gtk+-3.0 >= $GTK_REQUIRED x11 xext)
AC_SUBST(IDLE_MONITOR_CFLAGS)
AC_SUBST(IDLE_MONITOR_LIBS)
+PKG_CHECK_MODULES(POLKIT, gtk+-3.0 >= $GTK_REQUIRED glib-2.0 >= $GLIB_REQUIRED polkit-agent-1 >=
$POLKIT_AGENT_REQUIRED polkit-gobject-1 >= $POLKIT_GOBJECT_REQUIRED)
+AC_SUBST(POLKIT_CFLAGS)
+AC_SUBST(POLKIT_LIBS)
+
PKG_CHECK_MODULES(SCREENCAST, gtk+-3.0 >= $GTK_REQUIRED)
AC_SUBST(SCREENCAST_CFLAGS)
AC_SUBST(SCREENCAST_LIBS)
@@ -95,6 +101,7 @@ gnome-flashback/libdesktop-background/Makefile
gnome-flashback/libdisplay-config/Makefile
gnome-flashback/libend-session-dialog/Makefile
gnome-flashback/libidle-monitor/Makefile
+gnome-flashback/libpolkit/Makefile
gnome-flashback/libscreencast/Makefile
gnome-flashback/libscreenshot/Makefile
gnome-flashback/libshell/Makefile
diff --git a/data/org.gnome.gnome-flashback.gschema.xml.in.in
b/data/org.gnome.gnome-flashback.gschema.xml.in.in
index 28b6bf6..da7d719 100644
--- a/data/org.gnome.gnome-flashback.gschema.xml.in.in
+++ b/data/org.gnome.gnome-flashback.gschema.xml.in.in
@@ -25,6 +25,11 @@
<_summary>Idle monitor</_summary>
<_description>If set to true, then GNOME Flashback application will be used for user
activity monitoring.</_description>
</key>
+ <key name="polkit" type="b">
+ <default>true</default>
+ <_summary>Authentication Agent for polkit</_summary>
+ <_description>This is same authentication agent that was provided by
PolicyKit-gnome.</_description>
+ </key>
<key name="screencast" type="b">
<default>true</default>
<_summary>Screencasts</_summary>
diff --git a/gnome-flashback/Makefile.am b/gnome-flashback/Makefile.am
index fc00afd..f30acae 100644
--- a/gnome-flashback/Makefile.am
+++ b/gnome-flashback/Makefile.am
@@ -6,6 +6,7 @@ SUBDIRS = \
libdisplay-config \
libend-session-dialog \
libidle-monitor \
+ libpolkit \
libscreencast \
libscreenshot \
libshell \
@@ -46,6 +47,7 @@ gnome_flashback_LDADD = \
$(top_builddir)/gnome-flashback/libdisplay-config/libdisplay-config.la \
$(top_builddir)/gnome-flashback/libend-session-dialog/libend-session-dialog.la \
$(top_builddir)/gnome-flashback/libidle-monitor/libidle-monitor.la \
+ $(top_builddir)/gnome-flashback/libpolkit/libpolkit.la \
$(top_builddir)/gnome-flashback/libscreencast/libscreencast.la \
$(top_builddir)/gnome-flashback/libscreenshot/libscreenshot.la \
$(top_builddir)/gnome-flashback/libshell/libshell.la \
diff --git a/gnome-flashback/flashback-application.c b/gnome-flashback/flashback-application.c
index a6bc6ca..4c87907 100644
--- a/gnome-flashback/flashback-application.c
+++ b/gnome-flashback/flashback-application.c
@@ -24,6 +24,7 @@
#include "libdisplay-config/flashback-display-config.h"
#include "libend-session-dialog/flashback-end-session-dialog.h"
#include "libidle-monitor/flashback-idle-monitor.h"
+#include "libpolkit/flashback-polkit.h"
#include "libscreencast/flashback-screencast.h"
#include "libscreenshot/flashback-screenshot.h"
#include "libshell/flashback-shell.h"
@@ -45,6 +46,7 @@ struct _FlashbackApplication
FlashbackDisplayConfig *config;
FlashbackEndSessionDialog *dialog;
FlashbackIdleMonitor *idle_monitor;
+ FlashbackPolkit *polkit;
FlashbackScreencast *screencast;
FlashbackScreenshot *screenshot;
FlashbackShell *shell;
@@ -133,6 +135,7 @@ settings_changed (GSettings *settings,
SETTING_CHANGED (config, "display-config", flashback_display_config_new)
SETTING_CHANGED (idle_monitor, "idle-monitor", flashback_idle_monitor_new)
SETTING_CHANGED (dialog, "end-session-dialog", flashback_end_session_dialog_new)
+ SETTING_CHANGED (polkit, "polkit", flashback_polkit_new)
SETTING_CHANGED (screencast, "screencast", flashback_screencast_new)
SETTING_CHANGED (screenshot, "screenshot", flashback_screenshot_new)
SETTING_CHANGED (shell, "shell", flashback_shell_new)
@@ -167,6 +170,7 @@ flashback_application_finalize (GObject *object)
g_clear_object (&application->config);
g_clear_object (&application->dialog);
g_clear_object (&application->idle_monitor);
+ g_clear_object (&application->polkit);
g_clear_object (&application->screencast);
g_clear_object (&application->screenshot);
g_clear_object (&application->shell);
diff --git a/gnome-flashback/flashback.gresource.xml b/gnome-flashback/flashback.gresource.xml
index 46520ef..0d6133a 100644
--- a/gnome-flashback/flashback.gresource.xml
+++ b/gnome-flashback/flashback.gresource.xml
@@ -5,5 +5,6 @@
<file>HighContrast.css</file>
<file alias="flashback-confirm-dialog.ui"
compressed="true">libdisplay-config/flashback-confirm-dialog.ui</file>
<file alias="flashback-inhibit-dialog.ui"
compressed="true">libend-session-dialog/flashback-inhibit-dialog.ui</file>
+ <file alias="flashback-polkit-dialog.ui" compressed="true">libpolkit/flashback-polkit-dialog.ui</file>
</gresource>
</gresources>
diff --git a/gnome-flashback/libpolkit/Makefile.am b/gnome-flashback/libpolkit/Makefile.am
new file mode 100644
index 0000000..c76a750
--- /dev/null
+++ b/gnome-flashback/libpolkit/Makefile.am
@@ -0,0 +1,40 @@
+NULL =
+
+noinst_LTLIBRARIES = \
+ libpolkit.la \
+ $(NULL)
+
+libpolkit_la_CFLAGS = \
+ $(POLKIT_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(AM_CFLAGS) \
+ -I$(top_builddir)/gnome-flashback/libpolkit \
+ -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DPOLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE \
+ $(NULL)
+
+libpolkit_la_SOURCES = \
+ flashback-authenticator.c \
+ flashback-authenticator.h \
+ flashback-listener.c \
+ flashback-listener.h \
+ flashback-polkit.c \
+ flashback-polkit.h \
+ flashback-polkit-dialog.c \
+ flashback-polkit-dialog.h \
+ $(NULL)
+
+libpolkit_la_LDFLAGS = \
+ $(WARN_LDFLAGS) \
+ $(AM_LDFLAGS) \
+ $(NULL)
+
+libpolkit_la_LIBADD = \
+ $(POLKIT_LIBS) \
+ $(NULL)
+
+EXTRA_DIST = \
+ flashback-polkit-dialog.ui \
+ $(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/gnome-flashback/libpolkit/flashback-authenticator.c
b/gnome-flashback/libpolkit/flashback-authenticator.c
new file mode 100644
index 0000000..081ab02
--- /dev/null
+++ b/gnome-flashback/libpolkit/flashback-authenticator.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alberts Muktupāvels <alberts muktupavels gmail com>
+ * David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <pwd.h>
+
+#include "flashback-authenticator.h"
+#include "flashback-polkit-dialog.h"
+
+struct _FlashbackAuthenticator
+{
+ GObject parent;
+
+ PolkitAuthority *authority;
+
+ gchar *action_id;
+ gchar *message;
+ gchar *icon_name;
+ PolkitDetails *details;
+ gchar *cookie;
+ GList *identities;
+
+ PolkitActionDescription *action_desc;
+ gchar **users;
+
+ GtkWidget *dialog;
+
+ gboolean gained_authorization;
+ gboolean was_cancelled;
+ gboolean new_user_selected;
+ gchar *selected_user;
+
+ PolkitAgentSession *session;
+
+ GMainLoop *loop;
+
+ gulong idle_id;
+};
+
+enum
+{
+ SIGNAL_COMPLETED,
+
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (FlashbackAuthenticator, flashback_authenticator, G_TYPE_OBJECT)
+
+static void
+session_request (PolkitAgentSession *session,
+ const char *request,
+ gboolean echo_on,
+ gpointer user_data)
+{
+ FlashbackAuthenticator *authenticator;
+ FlashbackPolkitDialog *dialog;
+ gchar *modified_request;
+ gchar *password;
+
+ authenticator = FLASHBACK_AUTHENTICATOR (user_data);
+ dialog = FLASHBACK_POLKIT_DIALOG (authenticator->dialog);
+
+ /*g_debug ("in conversation_pam_prompt, request='%s', echo_on=%d", request, echo_on);*/
+
+ /* Fix up, and localize, password prompt if it's password auth */
+ if (g_ascii_strncasecmp (request, "password:", 9) == 0)
+ {
+ if (strcmp (g_get_user_name (), authenticator->selected_user) != 0)
+ {
+ modified_request = g_strdup_printf (_("_Password for %s:"), authenticator->selected_user);
+ }
+ else
+ {
+ modified_request = g_strdup (_("_Password:"));
+ }
+ }
+ else
+ {
+ modified_request = g_strdup (request);
+ }
+
+ gtk_widget_show_all (authenticator->dialog);
+ gtk_window_present (GTK_WINDOW (dialog));
+
+ password = flashback_polkit_dialog_run_until_response_for_prompt (dialog,
+ modified_request,
+ echo_on,
+ &authenticator->was_cancelled,
+ &authenticator->new_user_selected);
+
+ g_free (modified_request);
+
+ /* cancel auth unless user provided a password */
+ if (password == NULL)
+ {
+ flashback_authenticator_cancel (authenticator);
+ return;
+ }
+
+ polkit_agent_session_response (authenticator->session, password);
+ g_free (password);
+}
+
+static void
+session_show_info (PolkitAgentSession *session,
+ const gchar *msg,
+ gpointer user_data)
+{
+ FlashbackAuthenticator *authenticator;
+ FlashbackPolkitDialog *dialog;
+ gchar *s;
+
+ authenticator = FLASHBACK_AUTHENTICATOR (user_data);
+ dialog = FLASHBACK_POLKIT_DIALOG (authenticator->dialog);
+
+ s = g_strconcat ("<b>", msg, "</b>", NULL);
+ flashback_polkit_dialog_set_info_message (dialog, s);
+ g_free (s);
+
+ gtk_widget_show_all (authenticator->dialog);
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+session_show_error (PolkitAgentSession *session,
+ const gchar *msg,
+ gpointer user_data)
+{
+ FlashbackAuthenticator *authenticator;
+ FlashbackPolkitDialog *dialog;
+ gchar *s;
+
+ authenticator = FLASHBACK_AUTHENTICATOR (user_data);
+ dialog = FLASHBACK_POLKIT_DIALOG (authenticator->dialog);
+
+ s = g_strconcat ("<b>", msg, "</b>", NULL);
+ flashback_polkit_dialog_set_info_message (dialog, s);
+ g_free (s);
+}
+
+static void
+session_completed (PolkitAgentSession *session,
+ gboolean gained_authorization,
+ gpointer user_data)
+{
+ FlashbackAuthenticator *authenticator;
+
+ authenticator = FLASHBACK_AUTHENTICATOR (user_data);
+
+ authenticator->gained_authorization = gained_authorization;
+
+ //g_debug ("in conversation_done gained=%d", gained_authorization);
+
+ g_main_loop_quit (authenticator->loop);
+}
+
+static gboolean
+do_initiate (gpointer user_data)
+{
+ FlashbackAuthenticator *authenticator;
+ FlashbackPolkitDialog *dialog;
+ gint num_tries;
+
+ authenticator = FLASHBACK_AUTHENTICATOR (user_data);
+ dialog = FLASHBACK_POLKIT_DIALOG (authenticator->dialog);
+
+ gtk_widget_show_all (authenticator->dialog);
+ gtk_window_present (GTK_WINDOW (dialog));
+
+ if (!flashback_polkit_dialog_run_until_user_is_selected (dialog))
+ {
+ authenticator->was_cancelled = TRUE;
+
+ g_signal_emit_by_name (authenticator, "completed",
+ authenticator->gained_authorization,
+ authenticator->was_cancelled);
+
+ authenticator->idle_id = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ authenticator->loop = g_main_loop_new (NULL, TRUE);
+
+ num_tries = 0;
+ while (num_tries < 3)
+ {
+ PolkitIdentity *identity;
+
+ g_free (authenticator->selected_user);
+ authenticator->selected_user = flashback_polkit_dialog_get_selected_user (dialog);
+
+ /*g_warning ("Authenticating user %s", authenticator->selected_user);*/
+ identity = polkit_unix_user_new_for_name (authenticator->selected_user, NULL);
+
+ authenticator->session = polkit_agent_session_new (identity, authenticator->cookie);
+ g_object_unref (identity);
+
+ g_signal_connect (authenticator->session, "request",
+ G_CALLBACK (session_request), authenticator);
+ g_signal_connect (authenticator->session, "show-info",
+ G_CALLBACK (session_show_info), authenticator);
+ g_signal_connect (authenticator->session, "show-error",
+ G_CALLBACK (session_show_error), authenticator);
+ g_signal_connect (authenticator->session, "completed",
+ G_CALLBACK (session_completed), authenticator);
+
+ polkit_agent_session_initiate (authenticator->session);
+ g_main_loop_run (authenticator->loop);
+
+ /*g_warning ("gained_authorization=%d was_cancelled=%d new_user_selected=%d.",
+ authenticator->gained_authorization, authenticator->was_cancelled,
+ authenticator->new_user_selected);*/
+
+ if (authenticator->new_user_selected)
+ {
+ /*g_warning ("New user selected");*/
+ authenticator->new_user_selected = FALSE;
+ g_clear_object (&authenticator->session);
+
+ continue;
+ }
+
+ num_tries++;
+
+ if (!authenticator->gained_authorization && !authenticator->was_cancelled)
+ {
+ if (authenticator->dialog != NULL)
+ {
+ gchar *s;
+
+ s = g_strconcat ("<b>", _("Authentication Failure"), "</b>", NULL);
+ flashback_polkit_dialog_set_info_message (dialog, s);
+ g_free (s);
+
+ gtk_widget_queue_draw (authenticator->dialog);
+
+ /* shake the dialog to indicate error */
+ flashback_polkit_dialog_indicate_error (dialog);
+
+ g_clear_object (&authenticator->session);
+
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ g_signal_emit_by_name (authenticator, "completed",
+ authenticator->gained_authorization,
+ authenticator->was_cancelled);
+
+ authenticator->idle_id = 0;
+ return G_SOURCE_REMOVE;
+}
+
+static void
+delete_event_cb (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ FlashbackAuthenticator *authenticator;
+
+ authenticator = FLASHBACK_AUTHENTICATOR (user_data);
+
+ flashback_authenticator_cancel (authenticator);
+}
+
+static void
+selected_user_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ FlashbackAuthenticator *authenticator;
+ FlashbackPolkitDialog *dialog;
+
+ authenticator = FLASHBACK_AUTHENTICATOR (user_data);
+
+ dialog = FLASHBACK_POLKIT_DIALOG (authenticator->dialog);
+ flashback_polkit_dialog_set_info_message (dialog, "");
+
+ flashback_authenticator_cancel (authenticator);
+ authenticator->new_user_selected = TRUE;
+}
+
+static PolkitActionDescription *
+get_desc_for_action (FlashbackAuthenticator *authenticator)
+{
+ PolkitActionDescription *result;
+ GList *descs;
+ GList *l;
+
+ result = NULL;
+ descs = polkit_authority_enumerate_actions_sync (authenticator->authority,
+ NULL, NULL);
+
+ for (l = descs; l != NULL; l = l->next)
+ {
+ PolkitActionDescription *action_desc;
+ const gchar *action_id;
+
+ action_desc = POLKIT_ACTION_DESCRIPTION (l->data);
+ action_id = polkit_action_description_get_action_id (action_desc);
+
+ if (g_strcmp0 (action_id, authenticator->action_id) == 0)
+ {
+ result = g_object_ref (action_desc);
+ break;
+ }
+ }
+
+ g_list_foreach (descs, (GFunc) g_object_unref, NULL);
+ g_list_free (descs);
+
+ return result;
+}
+
+static void
+flashback_authenticator_dispose (GObject *object)
+{
+ FlashbackAuthenticator *authenticator;
+
+ authenticator = FLASHBACK_AUTHENTICATOR (object);
+
+ if (authenticator->idle_id > 0)
+ {
+ g_source_remove (authenticator->idle_id);
+ authenticator->idle_id = 0;
+ }
+
+ g_clear_object (&authenticator->authority);
+ g_clear_object (&authenticator->details);
+ g_clear_object (&authenticator->action_desc);
+
+ if (authenticator->dialog != NULL)
+ {
+ gtk_widget_destroy (authenticator->dialog);
+ authenticator->dialog = NULL;
+ }
+
+ g_clear_object (&authenticator->session);
+
+ if (authenticator->loop != NULL)
+ {
+ g_main_loop_unref (authenticator->loop);
+ authenticator->loop = NULL;
+ }
+
+ G_OBJECT_CLASS (flashback_authenticator_parent_class)->dispose (object);
+}
+
+static void
+flashback_authenticator_finalize (GObject *object)
+{
+ FlashbackAuthenticator *authenticator;
+
+ authenticator = FLASHBACK_AUTHENTICATOR (object);
+
+ g_free (authenticator->action_id);
+ g_free (authenticator->message);
+ g_free (authenticator->icon_name);
+ g_free (authenticator->cookie);
+
+ g_list_foreach (authenticator->identities, (GFunc) g_object_unref, NULL);
+ g_list_free (authenticator->identities);
+
+ g_strfreev (authenticator->users);
+
+ g_free (authenticator->selected_user);
+
+ G_OBJECT_CLASS (flashback_authenticator_parent_class)->finalize (object);
+}
+
+static void
+flashback_authenticator_class_init (FlashbackAuthenticatorClass *authenticator_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (authenticator_class);
+
+ object_class->dispose = flashback_authenticator_dispose;
+ object_class->finalize = flashback_authenticator_finalize;
+
+ /**
+ * FlashbackAuthenticator::completed
+ * @authenticator: A #PolkitGnomeAuthenticator.
+ * @gained_authorization: Whether the authorization was gained.
+ * @dismissed: Whether the dialog was dismissed.
+ *
+ * Emitted when the authentication is completed. The user is supposed to
+ * dispose of @authenticator upon receiving this signal.
+ */
+ signals[SIGNAL_COMPLETED] =
+ g_signal_new ("completed",
+ G_OBJECT_CLASS_TYPE (authenticator_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
+}
+
+static void
+flashback_authenticator_init (FlashbackAuthenticator *authenticator)
+{
+}
+
+FlashbackAuthenticator *
+flashback_authenticator_new (const gchar *action_id,
+ const gchar *message,
+ const gchar *icon_name,
+ PolkitDetails *details,
+ const gchar *cookie,
+ GList *identities)
+{
+ FlashbackAuthenticator *authenticator;
+ GError *error;
+ gint users;
+ gint i;
+ GList *l;
+ const gchar *vendor;
+ const gchar *vendor_url;
+
+ authenticator = g_object_new (FLASHBACK_TYPE_AUTHENTICATOR, NULL);
+
+ error = NULL;
+ authenticator->authority = polkit_authority_get_sync (NULL, &error);
+
+ if (error != NULL)
+ {
+ g_critical ("Error getting authority: %s", error->message);
+ g_error_free (error);
+
+ g_object_unref (authenticator);
+ return NULL;
+ }
+
+ authenticator->action_id = g_strdup (action_id);
+ authenticator->message = g_strdup (message);
+ authenticator->icon_name = g_strdup (icon_name);
+ authenticator->details = details != NULL ? g_object_ref (details) : NULL;
+ authenticator->cookie = g_strdup (cookie);
+ authenticator->identities = g_list_copy (identities);
+ g_list_foreach (authenticator->identities, (GFunc) g_object_ref, NULL);
+
+ authenticator->action_desc = get_desc_for_action (authenticator);
+
+ if (authenticator->action_desc == NULL)
+ {
+ g_object_unref (authenticator);
+ return NULL;
+ }
+
+ users = g_list_length (authenticator->identities);
+ authenticator->users = g_new0 (gchar *, users + 1);
+
+ for (l = authenticator->identities, i = 0; l != NULL; l = l->next, i++)
+ {
+ PolkitUnixUser *user;
+ uid_t uid;
+ struct passwd *passwd;
+
+ user = POLKIT_UNIX_USER (l->data);
+ uid = polkit_unix_user_get_uid (user);
+ passwd = getpwuid (uid);
+ authenticator->users[i] = g_strdup (passwd->pw_name);
+ }
+
+ vendor = polkit_action_description_get_vendor_name (authenticator->action_desc);
+ vendor_url = polkit_action_description_get_vendor_url (authenticator->action_desc);
+
+ authenticator->dialog = flashback_polkit_dialog_new (authenticator->action_id,
+ vendor, vendor_url,
+ authenticator->icon_name,
+ authenticator->message,
+ authenticator->details,
+ authenticator->users);
+
+ g_signal_connect (authenticator->dialog, "delete-event",
+ G_CALLBACK (delete_event_cb), authenticator);
+ g_signal_connect (authenticator->dialog, "notify::selected-user",
+ G_CALLBACK (selected_user_cb), authenticator);
+
+ return authenticator;
+}
+
+void
+flashback_authenticator_initiate (FlashbackAuthenticator *authenticator)
+{
+ authenticator->idle_id = g_idle_add (do_initiate, authenticator);
+ g_source_set_name_by_id (authenticator->idle_id, "[gnome-flashback] do_initiate");
+}
+
+void
+flashback_authenticator_cancel (FlashbackAuthenticator *authenticator)
+{
+ FlashbackPolkitDialog *dialog;
+
+ dialog = FLASHBACK_POLKIT_DIALOG (authenticator->dialog);
+ flashback_polkit_dialog_cancel (dialog);
+
+ authenticator->was_cancelled = TRUE;
+
+ if (authenticator->session != NULL)
+ polkit_agent_session_cancel (authenticator->session);
+}
+
+const gchar *
+flashback_authenticator_get_cookie (FlashbackAuthenticator *authenticator)
+{
+ return authenticator->cookie;
+}
diff --git a/gnome-flashback/libpolkit/flashback-authenticator.h
b/gnome-flashback/libpolkit/flashback-authenticator.h
new file mode 100644
index 0000000..359e42c
--- /dev/null
+++ b/gnome-flashback/libpolkit/flashback-authenticator.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alberts Muktupāvels <alberts muktupavels gmail com>
+ * David Zeuthen <davidz redhat com>
+ */
+
+#ifndef FLASHBACK_AUTHENTICATOR_H
+#define FLASHBACK_AUTHENTICATOR_H
+
+#include <glib-object.h>
+#include <polkitagent/polkitagent.h>
+
+G_BEGIN_DECLS
+
+#define FLASHBACK_TYPE_AUTHENTICATOR flashback_authenticator_get_type ()
+G_DECLARE_FINAL_TYPE (FlashbackAuthenticator, flashback_authenticator,
+ FLASHBACK, AUTHENTICATOR, GObject)
+
+FlashbackAuthenticator *flashback_authenticator_new (const gchar *action_id,
+ const gchar *message,
+ const gchar *icon_name,
+ PolkitDetails *details,
+ const gchar *cookie,
+ GList *identities);
+
+void flashback_authenticator_initiate (FlashbackAuthenticator *authenticator);
+void flashback_authenticator_cancel (FlashbackAuthenticator *authenticator);
+const gchar *flashback_authenticator_get_cookie (FlashbackAuthenticator *authenticator);
+
+
+
+G_END_DECLS
+
+#endif
diff --git a/gnome-flashback/libpolkit/flashback-listener.c b/gnome-flashback/libpolkit/flashback-listener.c
new file mode 100644
index 0000000..65a9e65
--- /dev/null
+++ b/gnome-flashback/libpolkit/flashback-listener.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alberts Muktupāvels <alberts muktupavels gmail com>
+ * David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "flashback-authenticator.h"
+#include "flashback-listener.h"
+
+struct _FlashbackListener
+{
+ PolkitAgentListener parent;
+
+ GList *authenticators;
+ FlashbackAuthenticator *active;
+};
+
+typedef struct
+{
+ FlashbackListener *listener;
+ FlashbackAuthenticator *authenticator;
+
+ GTask *task;
+
+ GCancellable *cancellable;
+ gulong cancel_id;
+} AuthData;
+
+G_DEFINE_TYPE (FlashbackListener, flashback_listener, POLKIT_AGENT_TYPE_LISTENER)
+
+static void
+flashback_listener_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (flashback_listener_parent_class)->dispose (object);
+}
+
+static void
+maybe_initiate_next_authenticator (FlashbackListener *listener)
+{
+ FlashbackAuthenticator *authenticator;
+
+ if (listener->authenticators == NULL)
+ return;
+
+ if (listener->active != NULL)
+ return;
+
+ authenticator = FLASHBACK_AUTHENTICATOR (listener->authenticators->data);
+
+ flashback_authenticator_initiate (authenticator);
+ listener->active = authenticator;
+}
+
+static AuthData *
+auth_data_new (FlashbackListener *listener,
+ FlashbackAuthenticator *authenticator,
+ GTask *task,
+ GCancellable *cancellable)
+{
+ AuthData *data;
+
+ data = g_new0 (AuthData, 1);
+
+ data->listener = g_object_ref (listener);
+ data->authenticator = g_object_ref (authenticator);
+ data->task = g_object_ref (task);
+ data->cancellable = g_object_ref (cancellable);
+
+ return data;
+}
+
+static void
+auth_data_free (AuthData *data)
+{
+ g_object_unref (data->listener);
+ g_object_unref (data->authenticator);
+ g_object_unref (data->task);
+
+ if (data->cancellable != NULL)
+ {
+ if (data->cancel_id > 0)
+ g_signal_handler_disconnect (data->cancellable, data->cancel_id);
+ g_object_unref (data->cancellable);
+ }
+
+ g_free (data);
+}
+
+static void
+cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
+{
+ AuthData *data;
+
+ data = (AuthData *) user_data;
+
+ flashback_authenticator_cancel (data->authenticator);
+}
+
+static void
+completed_cb (FlashbackAuthenticator *authenticator,
+ gboolean gained_authorization,
+ gboolean dismissed,
+ gpointer user_data)
+{
+ AuthData *data;
+
+ data = (AuthData *) user_data;
+
+ data->listener->authenticators = g_list_remove (data->listener->authenticators, authenticator);
+ if (authenticator == data->listener->active)
+ data->listener->active = NULL;
+
+ g_object_unref (authenticator);
+
+ if (dismissed)
+ {
+ g_task_return_new_error (data->task, POLKIT_ERROR, POLKIT_ERROR_CANCELLED,
+ _("Authentication dialog was dismissed by the user"));
+ }
+ else
+ {
+ g_task_return_boolean (data->task, TRUE);
+ }
+
+ g_object_unref (data->task);
+
+ maybe_initiate_next_authenticator (data->listener);
+ auth_data_free (data);
+}
+
+static void
+flashback_listener_initiate_authentication (PolkitAgentListener *agent_listener,
+ const gchar *action_id,
+ const gchar *message,
+ const gchar *icon_name,
+ PolkitDetails *details,
+ const gchar *cookie,
+ GList *identities,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ FlashbackListener *listener;
+ GTask *task;
+ FlashbackAuthenticator *authenticator;
+ AuthData *data;
+
+ listener = FLASHBACK_LISTENER (agent_listener);
+
+ authenticator = flashback_authenticator_new (action_id, message, icon_name,
+ details, cookie, identities);
+
+ task = g_task_new (listener, cancellable, callback, user_data);
+
+ if (authenticator == NULL)
+ {
+ g_task_return_new_error (task, POLKIT_ERROR, POLKIT_ERROR_FAILED,
+ "Error creating authentication object");
+ g_object_unref (task);
+
+ return;
+ }
+
+ data = auth_data_new (listener, authenticator, task, cancellable);
+
+ if (cancellable != NULL)
+ data->cancel_id = g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (cancelled_cb), data);
+
+ g_signal_connect (authenticator, "completed",
+ G_CALLBACK (completed_cb), data);
+
+ listener->authenticators = g_list_append (listener->authenticators, authenticator);
+
+ maybe_initiate_next_authenticator (listener);
+}
+
+static gboolean
+flashback_listener_initiate_authentication_finish (PolkitAgentListener *listener,
+ GAsyncResult *res,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (res, listener), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+flashback_listener_class_init (FlashbackListenerClass *listener_class)
+{
+ GObjectClass *object_class;
+ PolkitAgentListenerClass *agent_class;
+
+ object_class = G_OBJECT_CLASS (listener_class);
+ agent_class = POLKIT_AGENT_LISTENER_CLASS (listener_class);
+
+ object_class->dispose = flashback_listener_dispose;
+
+ agent_class->initiate_authentication = flashback_listener_initiate_authentication;
+ agent_class->initiate_authentication_finish = flashback_listener_initiate_authentication_finish;
+}
+
+static void
+flashback_listener_init (FlashbackListener *listener)
+{
+}
+
+PolkitAgentListener *
+flashback_listener_new (void)
+{
+ return g_object_new (FLASHBACK_TYPE_LISTENER, NULL);
+}
diff --git a/gnome-flashback/libpolkit/flashback-listener.h b/gnome-flashback/libpolkit/flashback-listener.h
new file mode 100644
index 0000000..1846242
--- /dev/null
+++ b/gnome-flashback/libpolkit/flashback-listener.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alberts Muktupāvels <alberts muktupavels gmail com>
+ * David Zeuthen <davidz redhat com>
+ */
+
+#ifndef FLASHBACK_LISTENER_H
+#define FLASHBACK_LISTENER_H
+
+#include <polkitagent/polkitagent.h>
+
+G_BEGIN_DECLS
+
+#define FLASHBACK_TYPE_LISTENER (flashback_listener_get_type())
+#define FLASHBACK_LISTENER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), \
+ FLASHBACK_TYPE_LISTENER, \
+ FlashbackListener))
+#define FLASHBACK_IS_LISTENER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
+ FLASHBACK_TYPE_LISTENER))
+#define FLASHBACK_LISTENER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), \
+ FLASHBACK_TYPE_LISTENER, \
+ FlashbackListenerClass))
+#define FLASHBACK_IS_LISTENER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), \
+ FLASHBACK_TYPE_LISTENER))
+#define FLASHBACK_LISTENER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), \
+ FLASHBACK_TYPE_LISTENER, \
+ FlashbackListenerClass))
+
+typedef struct _FlashbackListener FlashbackListener;
+typedef struct _FlashbackListenerClass FlashbackListenerClass;
+
+struct _FlashbackListenerClass
+{
+ PolkitAgentListenerClass parent_class;
+};
+
+GType flashback_listener_get_type (void) G_GNUC_CONST;
+PolkitAgentListener *flashback_listener_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/gnome-flashback/libpolkit/flashback-polkit-dialog.c
b/gnome-flashback/libpolkit/flashback-polkit-dialog.c
new file mode 100644
index 0000000..92b5d7c
--- /dev/null
+++ b/gnome-flashback/libpolkit/flashback-polkit-dialog.c
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alberts Muktupāvels <alberts muktupavels gmail com>
+ * David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <glib/gi18n-lib.h>
+#include <pwd.h>
+
+#include "flashback-polkit-dialog.h"
+
+#define RESPONSE_USER_SELECTED 1001
+
+struct _FlashbackPolkitDialog
+{
+ GtkWindow parent;
+
+ GtkWidget *image;
+ GtkWidget *main_message_label;
+ GtkWidget *secondary_message_label;
+ GtkWidget *users_combobox;
+ GtkWidget *entry_box;
+ GtkWidget *prompt_label;
+ GtkWidget *password_entry;
+ GtkWidget *info_label;
+ GtkWidget *details_grid;
+ GtkWidget *auth_button;
+
+ GtkListStore *users_store;
+
+ gchar *action_id;
+ gchar *vendor;
+ gchar *vendor_url;
+ gchar *icon_name;
+ gchar *message;
+ PolkitDetails *details;
+ gchar **users;
+
+ gchar *selected_user;
+
+ gint response;
+
+ gboolean is_running;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_ACTION_ID,
+ PROP_VENDOR,
+ PROP_VENDOR_URL,
+ PROP_ICON_NAME,
+ PROP_MESSAGE,
+ PROP_DETAILS,
+ PROP_USERS,
+
+ PROP_SELECTED_USER,
+
+ LAST_PROP
+};
+
+static GParamSpec *properties[LAST_PROP] = { NULL };
+
+enum
+{
+ SIGNAL_CLOSE,
+
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum
+{
+ COLUMN_PIXBUF,
+ COLUMN_TEXT,
+ COLUMN_USERNAME,
+
+ N_COLUMNS
+};
+
+G_DEFINE_TYPE (FlashbackPolkitDialog, flashback_polkit_dialog, GTK_TYPE_WINDOW)
+
+static void
+cancel_button_clicked_cb (GtkButton *button,
+ FlashbackPolkitDialog *dialog)
+{
+ dialog->response = GTK_RESPONSE_CANCEL;
+
+ if (dialog->is_running == TRUE)
+ gtk_main_quit ();
+
+ gtk_window_close (GTK_WINDOW (dialog));
+}
+
+static void
+auth_button_clicked_cb (GtkButton *button,
+ FlashbackPolkitDialog *dialog)
+{
+ dialog->response = GTK_RESPONSE_OK;
+
+ if (dialog->is_running == TRUE)
+ gtk_main_quit ();
+}
+
+static void
+setup_image (FlashbackPolkitDialog *dialog)
+{
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *vendor;
+ GdkPixbuf *password;
+ GdkPixbuf *copy;
+
+ if (dialog->icon_name == NULL || strlen (dialog->icon_name) == 0)
+ return;
+
+ icon_theme = gtk_icon_theme_get_default ();
+ vendor = gtk_icon_theme_load_icon (icon_theme, dialog->icon_name, 48, 0, NULL);
+
+ if (vendor == NULL)
+ {
+ g_warning ("No icon for themed icon with name '%s'", dialog->icon_name);
+
+ return;
+ }
+
+ password = gtk_icon_theme_load_icon (icon_theme, "dialog-password", 48, 0, NULL);
+
+ if (password == NULL)
+ {
+ g_warning ("Unable to get a pixbuf for icon with name 'dialog-password' at size 48");
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (dialog->image), vendor);
+ g_object_unref (vendor);
+
+ return;
+ }
+
+ copy = gdk_pixbuf_copy (password);
+
+ if (copy == NULL)
+ {
+ g_object_unref (vendor);
+ g_object_unref (password);
+
+ return;
+ }
+
+ gdk_pixbuf_composite (vendor, copy, 24, 24, 24, 24, 24, 24, 0.5, 0.5,
+ GDK_INTERP_BILINEAR, 255);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (dialog->image), copy);
+
+ g_object_unref (vendor);
+ g_object_unref (password);
+ g_object_unref (copy);
+}
+
+static void
+setup_main_message_label (FlashbackPolkitDialog *dialog)
+{
+ gchar *message;
+
+ message = g_strdup_printf ("<big><b>%s</b></big>", dialog->message);
+
+ gtk_label_set_markup (GTK_LABEL (dialog->main_message_label), message);
+ gtk_label_set_xalign (GTK_LABEL (dialog->main_message_label), 0);
+
+ g_free (message);
+}
+
+static void
+setup_secondary_message_label (FlashbackPolkitDialog *dialog)
+{
+ const gchar *message;
+ const gchar *user_name1;
+ const gchar *user_name2;
+
+ if (dialog->users != NULL && g_strv_length (dialog->users) > 1)
+ {
+ message = _("An application is attempting to perform an action that requires privileges. "
+ "Authentication as one of the users below is required to perform this action.");
+ }
+ else
+ {
+ user_name1 = g_get_user_name ();
+ user_name2 = dialog->users != NULL ? dialog->users[0] : NULL;
+
+ if (g_strcmp0 (user_name1, user_name2) == 0)
+ {
+ message = _("An application is attempting to perform an action that requires privileges. "
+ "Authentication is required to perform this action.");
+ }
+ else
+ {
+ message = _("An application is attempting to perform an action that requires privileges. "
+ "Authentication as the super user is required to perform this action.");
+ }
+ }
+
+ gtk_label_set_markup (GTK_LABEL (dialog->secondary_message_label), message);
+ gtk_label_set_xalign (GTK_LABEL (dialog->secondary_message_label), 0);
+}
+
+static void
+combobox_set_sensitive (GtkCellLayout *cell_layout,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ GtkTreePath *path;
+ gint *indices;
+
+ path = gtk_tree_model_get_path (tree_model, iter);
+ indices = gtk_tree_path_get_indices (path);
+
+ g_object_set (cell, "sensitive", indices[0] == 0 ? FALSE : TRUE, NULL);
+ gtk_tree_path_free (path);
+}
+
+static void
+users_combobox_changed_cb (GtkComboBox *combobox,
+ gpointer user_data)
+{
+ FlashbackPolkitDialog *dialog;
+ GtkTreeIter iter;
+ gchar *user_name;
+
+ dialog = FLASHBACK_POLKIT_DIALOG (user_data);
+
+ if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combobox), &iter))
+ return;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (dialog->users_store), &iter,
+ COLUMN_USERNAME, &user_name,
+ -1);
+
+ g_free (dialog->selected_user);
+ dialog->selected_user = user_name;
+
+ g_object_notify (G_OBJECT (dialog), "selected-user");
+
+ dialog->response = RESPONSE_USER_SELECTED;
+
+ gtk_widget_set_sensitive (dialog->prompt_label, TRUE);
+ gtk_widget_set_sensitive (dialog->password_entry, TRUE);
+ gtk_widget_set_sensitive (dialog->auth_button, TRUE);
+}
+
+static void
+setup_users_store (FlashbackPolkitDialog *dialog)
+{
+ GtkTreeIter iter;
+ gint i;
+ GtkComboBox *combobox;
+ GtkCellRenderer *renderer;
+
+ if (dialog->users_store != NULL)
+ return;
+
+ dialog->users_store = gtk_list_store_new (N_COLUMNS, GDK_TYPE_PIXBUF,
+ G_TYPE_STRING, G_TYPE_STRING);
+
+ gtk_list_store_append (dialog->users_store, &iter);
+ gtk_list_store_set (dialog->users_store, &iter,
+ COLUMN_PIXBUF, NULL,
+ COLUMN_TEXT, _("Select user..."),
+ COLUMN_USERNAME, NULL,
+ -1);
+
+ for (i = 0; dialog->users[i] != NULL; i++)
+ {
+ gchar *gecos;
+ gchar *real_name;
+ GdkPixbuf *pixbuf;
+ struct passwd *passwd;
+
+ errno = 0;
+ passwd = getpwnam (dialog->users[i]);
+
+ if (passwd == NULL)
+ {
+ g_warning ("Error doing getpwnam(\"%s\"): %s", dialog->users[i], strerror (errno));
+ continue;
+ }
+
+ if (passwd->pw_gecos != NULL)
+ gecos = g_locale_to_utf8 (passwd->pw_gecos, -1, NULL, NULL, NULL);
+ else
+ gecos = NULL;
+
+ if (gecos != NULL && strlen (gecos) > 0)
+ {
+ gchar *first_comma;
+
+ first_comma = strchr (gecos, ',');
+
+ if (first_comma != NULL)
+ *first_comma = '\0';
+ }
+
+ if (g_strcmp0 (gecos, dialog->users[i]) != 0)
+ real_name = g_strdup_printf (_("%s (%s)"), gecos, dialog->users[i]);
+ else
+ real_name = g_strdup (dialog->users[i]);
+
+ g_free (gecos);
+
+ pixbuf = NULL;
+ if (passwd->pw_dir != NULL)
+ {
+ gchar *path;
+
+ path = g_strdup_printf ("%s/.face", passwd->pw_dir);
+ pixbuf = gdk_pixbuf_new_from_file_at_scale (path, 16, 16, TRUE, NULL);
+
+ g_free (path);
+ }
+
+ if (pixbuf == NULL)
+ {
+ GtkIconTheme *icon_theme;
+
+ icon_theme = gtk_icon_theme_get_default ();
+ pixbuf = gtk_icon_theme_load_icon (icon_theme, "avatar-default",
+ GTK_ICON_SIZE_MENU, 0, NULL);
+ }
+
+ gtk_list_store_append (dialog->users_store, &iter);
+ gtk_list_store_set (dialog->users_store, &iter,
+ COLUMN_PIXBUF, pixbuf,
+ COLUMN_TEXT, real_name,
+ COLUMN_USERNAME, dialog->users[i],
+ -1);
+
+ g_free (real_name);
+ g_object_unref (pixbuf);
+ }
+
+ combobox = GTK_COMBO_BOX (dialog->users_combobox);
+ gtk_combo_box_set_model (combobox, GTK_TREE_MODEL (dialog->users_store));
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
+ "pixbuf", COLUMN_PIXBUF, NULL);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combobox), renderer,
+ (GtkCellLayoutDataFunc) combobox_set_sensitive,
+ NULL, NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
+ "text", COLUMN_TEXT, NULL);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combobox), renderer,
+ (GtkCellLayoutDataFunc) combobox_set_sensitive,
+ NULL, NULL);
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0);
+
+ g_signal_connect (dialog->users_combobox, "changed",
+ G_CALLBACK (users_combobox_changed_cb), dialog);
+
+ gtk_widget_show (dialog->users_combobox);
+}
+
+static void
+setup_users_combobox (FlashbackPolkitDialog *dialog)
+{
+ gtk_widget_hide (dialog->users_combobox);
+
+ if (dialog->users == NULL)
+ return;
+
+ if (g_strv_length (dialog->users) > 1)
+ {
+ setup_users_store (dialog);
+
+ gtk_widget_set_sensitive (dialog->prompt_label, FALSE);
+ gtk_widget_set_sensitive (dialog->password_entry, FALSE);
+ gtk_widget_set_sensitive (dialog->auth_button, FALSE);
+ }
+ else
+ {
+ dialog->selected_user = g_strdup (dialog->users[0]);
+ }
+}
+
+static void
+setup_entry_box (FlashbackPolkitDialog *dialog)
+{
+ gtk_entry_set_visibility (GTK_ENTRY (dialog->password_entry), FALSE);
+
+ gtk_widget_hide (dialog->entry_box);
+ gtk_widget_set_no_show_all (dialog->entry_box, TRUE);
+
+ gtk_widget_hide (dialog->info_label);
+}
+
+static void
+add_row (FlashbackPolkitDialog *dialog,
+ gint row,
+ const gchar *text1,
+ const gchar *text2,
+ const gchar *tooltip)
+{
+ GtkGrid *grid;
+ GtkWidget *label1;
+ GtkWidget *label2;
+
+ grid = GTK_GRID (dialog->details_grid);
+
+ label1 = gtk_label_new_with_mnemonic (text1);
+ gtk_label_set_use_markup (GTK_LABEL (label1), TRUE);
+ gtk_label_set_xalign (GTK_LABEL (label1), 1.0);
+
+ label2 = gtk_label_new_with_mnemonic (text2);
+ gtk_label_set_use_markup (GTK_LABEL (label2), TRUE);
+ gtk_label_set_xalign (GTK_LABEL (label2), 0.0);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label1), label2);
+
+ gtk_grid_attach (grid, label1, 0, row, 1, 1);
+ gtk_grid_attach (grid, label2, 1, row, 1, 1);
+
+ if (tooltip != NULL)
+ gtk_widget_set_tooltip_markup (label2,tooltip);
+ gtk_widget_set_hexpand (label2, TRUE);
+}
+
+static void
+setup_details (FlashbackPolkitDialog *dialog)
+{
+ gint row;
+ gchar *s1;
+ gchar *s2;
+ gchar *tooltip;
+
+ row = 0;
+
+ if (dialog->details != NULL)
+ {
+ gchar **keys;
+ gint i;
+
+ keys = polkit_details_get_keys (dialog->details);
+
+ for (i = 0; keys[i] != NULL; i++)
+ {
+ const gchar *key;
+ const gchar *value;
+
+ key = keys[i];
+ if (g_str_has_prefix (key, "polkit."))
+ continue;
+
+ value = polkit_details_lookup (dialog->details, key);
+
+ s1 = g_strdup_printf ("<small><b>%s:</b></small>", key);
+ s2 = g_strdup_printf ("<small>%s</small>", value);
+
+ add_row (dialog, row, s1, s2, NULL);
+
+ g_free (s1);
+ g_free (s2);
+
+ row++;
+ }
+
+ g_strfreev (keys);
+ }
+
+ s1 = g_strdup_printf ("<small><b>%s</b></small>", _("Action:"));
+ s2 = g_strdup_printf ("<small><a href=\"%s\">%s</a></small>",
+ dialog->action_id, dialog->action_id);
+ tooltip = g_strdup_printf (_("Click to edit %s"), dialog->action_id);
+
+ add_row (dialog, row++, s1, s2, tooltip);
+
+ g_free (s1);
+ g_free (s2);
+ g_free (tooltip);
+
+ s1 = g_strdup_printf ("<small><b>%s</b></small>", _("Vendor:"));
+ s2 = g_strdup_printf ("<small><a href=\"%s\">%s</a></small>",
+ dialog->vendor_url, dialog->vendor);
+ tooltip = g_strdup_printf (_("Click to open %s"), dialog->vendor_url);
+
+ add_row (dialog, row++, s1, s2, tooltip);
+
+ g_free (s1);
+ g_free (s2);
+ g_free (tooltip);
+}
+
+static void
+flashback_polkit_dialog_constructed (GObject *object)
+{
+ FlashbackPolkitDialog *dialog;
+
+ dialog = FLASHBACK_POLKIT_DIALOG (object);
+
+ G_OBJECT_CLASS (flashback_polkit_dialog_parent_class)->constructed (object);
+
+ dialog->response = GTK_RESPONSE_OK;
+
+ setup_image (dialog);
+ setup_main_message_label (dialog);
+ setup_secondary_message_label (dialog);
+ setup_users_combobox (dialog);
+ setup_entry_box (dialog);
+ setup_details (dialog);
+}
+
+static void
+flashback_polkit_dialog_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ FlashbackPolkitDialog *dialog;
+
+ dialog = FLASHBACK_POLKIT_DIALOG (object);
+
+ switch (property_id)
+ {
+ case PROP_ACTION_ID:
+ g_value_set_string (value, dialog->action_id);
+ break;
+
+ case PROP_VENDOR:
+ g_value_set_string (value, dialog->vendor);
+ break;
+
+ case PROP_VENDOR_URL:
+ g_value_set_string (value, dialog->vendor_url);
+ break;
+
+ case PROP_ICON_NAME:
+ g_value_set_string (value, dialog->icon_name);
+ break;
+
+ case PROP_MESSAGE:
+ g_value_set_string (value, dialog->message);
+ break;
+
+ case PROP_DETAILS:
+ g_value_set_object (value, dialog->details);
+ break;
+
+ case PROP_USERS:
+ g_value_set_boxed (value, dialog->users);
+ break;
+
+ case PROP_SELECTED_USER:
+ g_value_set_string (value, dialog->selected_user);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+flashback_polkit_dialog_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ FlashbackPolkitDialog *dialog;
+
+ dialog = FLASHBACK_POLKIT_DIALOG (object);
+
+ switch (property_id)
+ {
+ case PROP_ACTION_ID:
+ dialog->action_id = g_value_dup_string (value);
+ break;
+
+ case PROP_VENDOR:
+ dialog->vendor = g_value_dup_string (value);
+ break;
+
+ case PROP_VENDOR_URL:
+ dialog->vendor_url = g_value_dup_string (value);
+ break;
+
+ case PROP_ICON_NAME:
+ dialog->icon_name = g_value_dup_string (value);
+ break;
+
+ case PROP_MESSAGE:
+ dialog->message = g_value_dup_string (value);
+ break;
+
+ case PROP_DETAILS:
+ dialog->details = g_value_dup_object (value);
+ break;
+
+ case PROP_USERS:
+ dialog->users = g_value_dup_boxed (value);
+ break;
+
+ case PROP_SELECTED_USER:
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+flashback_polkit_dialog_dispose (GObject *object)
+{
+ FlashbackPolkitDialog *dialog;
+
+ dialog = FLASHBACK_POLKIT_DIALOG (object);
+
+ g_clear_object (&dialog->details);
+ g_clear_object (&dialog->users_store);
+
+ G_OBJECT_CLASS (flashback_polkit_dialog_parent_class)->dispose (object);
+}
+
+static void
+flashback_polkit_dialog_finalize (GObject *object)
+{
+ FlashbackPolkitDialog *dialog;
+
+ dialog = FLASHBACK_POLKIT_DIALOG (object);
+
+ g_free (dialog->action_id);
+ g_free (dialog->vendor);
+ g_free (dialog->vendor_url);
+ g_free (dialog->icon_name);
+ g_free (dialog->message);
+
+ g_strfreev (dialog->users);
+
+ g_free (dialog->selected_user);
+
+ G_OBJECT_CLASS (flashback_polkit_dialog_parent_class)->finalize (object);
+}
+
+static void
+flashback_polkit_dialog_class_init (FlashbackPolkitDialogClass *dialog_class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkBindingSet *binding_set;
+ const gchar *resource;
+
+ object_class = G_OBJECT_CLASS (dialog_class);
+ widget_class = GTK_WIDGET_CLASS (dialog_class);
+
+ object_class->constructed = flashback_polkit_dialog_constructed;
+ object_class->get_property = flashback_polkit_dialog_get_property;
+ object_class->set_property = flashback_polkit_dialog_set_property;
+ object_class->dispose = flashback_polkit_dialog_dispose;
+ object_class->finalize = flashback_polkit_dialog_finalize;
+
+ /**
+ * FlashbackPolkitDialog:action-id
+ */
+ properties[PROP_ACTION_ID] =
+ g_param_spec_string ("action-id", "action-id", "action-id",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ /**
+ * FlashbackPolkitDialog:vendor
+ */
+ properties[PROP_VENDOR] =
+ g_param_spec_string ("vendor", "vendor", "vendor",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ /**
+ * FlashbackPolkitDialog:vendor-url
+ */
+ properties[PROP_VENDOR_URL] =
+ g_param_spec_string ("vendor-url", "vendor-url", "vendor-url",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ /**
+ * FlashbackPolkitDialog:icon-name
+ */
+ properties[PROP_ICON_NAME] =
+ g_param_spec_string ("icon-name", "icon-name", "icon-name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ /**
+ * FlashbackPolkitDialog:message
+ */
+ properties[PROP_MESSAGE] =
+ g_param_spec_string ("message", "message", "message",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ /**
+ * FlashbackPolkitDialog:details
+ */
+ properties[PROP_DETAILS] =
+ g_param_spec_object ("details", "details", "details",
+ POLKIT_TYPE_DETAILS,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ /**
+ * FlashbackPolkitDialog:users
+ */
+ properties[PROP_USERS] =
+ g_param_spec_boxed ("users", "users", "users",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ /**
+ * FlashbackPolkitDialog:selected-user
+ */
+ properties[PROP_SELECTED_USER] =
+ g_param_spec_string ("selected-user", "selected-user", "selected-user",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, properties);
+
+ /**
+ * FlashbackPolkitDialog::close
+ */
+ signals[SIGNAL_CLOSE] =
+ g_signal_new ("close",
+ G_OBJECT_CLASS_TYPE (dialog_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ binding_set = gtk_binding_set_by_class (dialog_class);
+ gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "close", 0);
+
+ resource = "/org/gnome/gnome-flashback/flashback-polkit-dialog.ui";
+ gtk_widget_class_set_template_from_resource (widget_class, resource);
+
+ gtk_widget_class_bind_template_child (widget_class, FlashbackPolkitDialog, image);
+ gtk_widget_class_bind_template_child (widget_class, FlashbackPolkitDialog, main_message_label);
+ gtk_widget_class_bind_template_child (widget_class, FlashbackPolkitDialog, secondary_message_label);
+ gtk_widget_class_bind_template_child (widget_class, FlashbackPolkitDialog, users_combobox);
+ gtk_widget_class_bind_template_child (widget_class, FlashbackPolkitDialog, entry_box);
+ gtk_widget_class_bind_template_child (widget_class, FlashbackPolkitDialog, prompt_label);
+ gtk_widget_class_bind_template_child (widget_class, FlashbackPolkitDialog, password_entry);
+ gtk_widget_class_bind_template_child (widget_class, FlashbackPolkitDialog, info_label);
+ gtk_widget_class_bind_template_child (widget_class, FlashbackPolkitDialog, details_grid);
+ gtk_widget_class_bind_template_child (widget_class, FlashbackPolkitDialog, auth_button);
+
+ gtk_widget_class_bind_template_callback (widget_class, cancel_button_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, auth_button_clicked_cb);
+}
+
+static void
+flashback_polkit_dialog_close (FlashbackPolkitDialog *dialog,
+ gpointer user_data)
+{
+ dialog->response = GTK_RESPONSE_CANCEL;
+
+ if (dialog->is_running == TRUE)
+ gtk_main_quit ();
+
+ gtk_window_close (GTK_WINDOW (dialog));
+}
+
+static void
+flashback_polkit_dialog_init (FlashbackPolkitDialog *dialog)
+{
+ GtkWindow *window;
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (dialog);
+ window = GTK_WINDOW (dialog);
+
+ gtk_widget_init_template (widget);
+
+ gtk_window_set_keep_above (window, TRUE);
+
+ g_signal_connect (dialog, "close",
+ G_CALLBACK (flashback_polkit_dialog_close),
+ NULL);
+}
+
+/**
+ * flashback_polkit_dialog_new:
+ * @action_id:
+ * @vendor:
+ * @vendor_url:
+ * @icon_name:
+ * @message_markup:
+ * @details:
+ * @users:
+ *
+ * Creates a new #FlashbackPolkitDialog.
+ *
+ * Returns: (transfer full): a newly created #FlashbackPolkitDialog.
+ **/
+GtkWidget *
+flashback_polkit_dialog_new (const gchar *action_id,
+ const gchar *vendor,
+ const gchar *vendor_url,
+ const gchar *icon_name,
+ const gchar *message_markup,
+ PolkitDetails *details,
+ gchar **users)
+{
+ return g_object_new (FLASHBACK_TYPE_POLKIT_DIALOG,
+ "action-id", action_id,
+ "vendor", vendor,
+ "vendor-url", vendor_url,
+ "icon-name", icon_name,
+ "message", message_markup,
+ "details", details,
+ "users", users,
+ NULL);
+}
+
+/**
+ * flashback_polkit_dialog_get_selected_user:
+ * @dialog: a #FlashbackPolkitDialog
+ *
+ * Gets the currently selected user.
+ *
+ * Returns: The currently selected user (free with g_free()) or %NULL if no
+ * user is currently selected.
+ **/
+gchar *
+flashback_polkit_dialog_get_selected_user (FlashbackPolkitDialog *dialog)
+{
+ return g_strdup (dialog->selected_user);
+}
+
+/**
+ * flashback_polkit_dialog_run_until_user_is_selected:
+ * @dialog: a #FlashbackPolkitDialog
+ *
+ * Runs @dialog in a recursive main loop until a user have been selected.
+ *
+ * If there is only one element in the the users array (which is set upon
+ * construction) or an user has already been selected, this function returns
+ * immediately with the return value %TRUE.
+ *
+ * Returns: %TRUE if a user is selected or %FALSE if the dialog was cancelled.
+ **/
+gboolean
+flashback_polkit_dialog_run_until_user_is_selected (FlashbackPolkitDialog *dialog)
+{
+ if (dialog->selected_user != NULL)
+ return TRUE;
+
+ dialog->is_running = TRUE;
+
+ gtk_main ();
+
+ dialog->is_running = FALSE;
+
+ if (dialog->response == RESPONSE_USER_SELECTED)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * flashback_polkit_dialog_run_until_response_for_prompt:
+ * @dialog: a #FlashbackPolkitDialog
+ * @prompt: the prompt to present the user with
+ * @echo_chars: whether characters should be echoed in the password entry box
+ * @was_cancelled: set to %TRUE if the dialog was cancelled
+ * @new_user_selected: set to %TRUE if another user was selected
+ *
+ * Runs @dialog in a recursive main loop until a response to @prompt have been
+ * obtained from the user.
+ *
+ * Returns: The response (free with g_free()) or %NULL if one of
+ * @was_cancelled or @new_user_selected has been set to %TRUE.
+ **/
+gchar *
+flashback_polkit_dialog_run_until_response_for_prompt (FlashbackPolkitDialog *dialog,
+ const gchar *prompt,
+ gboolean echo_chars,
+ gboolean *was_cancelled,
+ gboolean *new_user_selected)
+{
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (dialog->prompt_label), prompt);
+ gtk_entry_set_visibility (GTK_ENTRY (dialog->password_entry), echo_chars);
+ gtk_entry_set_text (GTK_ENTRY (dialog->password_entry), "");
+ gtk_widget_grab_focus (dialog->password_entry);
+
+ if (was_cancelled != NULL)
+ *was_cancelled = FALSE;
+
+ if (new_user_selected != NULL)
+ *new_user_selected = FALSE;
+
+ dialog->is_running = TRUE;
+
+ gtk_widget_set_no_show_all (dialog->entry_box, FALSE);
+ gtk_widget_show_all (dialog->entry_box);
+
+ gtk_main ();
+
+ gtk_widget_hide (dialog->entry_box);
+ gtk_widget_set_no_show_all (dialog->entry_box, TRUE);
+
+ dialog->is_running = FALSE;
+
+ if (dialog->response == GTK_RESPONSE_OK)
+ {
+ return g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->password_entry)));
+ }
+ else if (dialog->response == RESPONSE_USER_SELECTED)
+ {
+ if (new_user_selected != NULL)
+ *new_user_selected = TRUE;
+ }
+ else
+ {
+ if (was_cancelled != NULL)
+ *was_cancelled = TRUE;
+ }
+
+ return NULL;
+}
+
+/**
+ * flashback_polkit_dialog_cancel:
+ * @dialog: a #FlashbackPolkitDialog
+ *
+ * Cancels the dialog if it is currenlty running.
+ *
+ * Returns: %TRUE if the dialog was running.
+ **/
+gboolean
+flashback_polkit_dialog_cancel (FlashbackPolkitDialog *dialog)
+{
+ if (!dialog->is_running)
+ return FALSE;
+
+ dialog->response = GTK_RESPONSE_CANCEL;
+ gtk_main_quit ();
+
+ return TRUE;
+}
+
+/**
+ * flashback_polkit_dialog_indicate_error:
+ * @dialog: a #FlashbackPolkitDialog
+ *
+ * Call this function to indicate an authentication error; typically shakes
+ * the window.
+ **/
+void
+flashback_polkit_dialog_indicate_error (FlashbackPolkitDialog *dialog)
+{
+ GtkWindow *window;
+ gint x;
+ gint y;
+ gint n;
+
+ window = GTK_WINDOW (dialog);
+
+ gtk_window_get_position (window, &x, &y);
+
+ for (n = 0; n < 10; n++)
+ {
+ gtk_window_move (window, x + (n % 2 == 0 ? -15 : 15), y);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ g_usleep (10000);
+ }
+
+ gtk_window_move (window, x, y);
+}
+
+void
+flashback_polkit_dialog_set_info_message (FlashbackPolkitDialog *dialog,
+ const gchar *info_markup)
+{
+ gtk_label_set_markup (GTK_LABEL (dialog->info_label), info_markup);
+}
diff --git a/gnome-flashback/libpolkit/flashback-polkit-dialog.h
b/gnome-flashback/libpolkit/flashback-polkit-dialog.h
new file mode 100644
index 0000000..1a4c87b
--- /dev/null
+++ b/gnome-flashback/libpolkit/flashback-polkit-dialog.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alberts Muktupāvels <alberts muktupavels gmail com>
+ * David Zeuthen <davidz redhat com>
+ */
+
+#ifndef FLASHBACK_POLKIT_DIALOG_H
+#define FLASHBACK_POLKIT_DIALOG_H
+
+#include <gtk/gtk.h>
+#include <polkit/polkit.h>
+
+G_BEGIN_DECLS
+
+#define FLASHBACK_TYPE_POLKIT_DIALOG flashback_polkit_dialog_get_type ()
+G_DECLARE_FINAL_TYPE (FlashbackPolkitDialog, flashback_polkit_dialog,
+ FLASHBACK, POLKIT_DIALOG, GtkWindow)
+
+GtkWidget *flashback_polkit_dialog_new (const gchar *action_id,
+ const gchar *vendor,
+ const gchar *vendor_url,
+ const gchar *icon_name,
+ const gchar *message_markup,
+ PolkitDetails *details,
+ gchar **users);
+
+gchar *flashback_polkit_dialog_get_selected_user (FlashbackPolkitDialog *dialog);
+
+gboolean flashback_polkit_dialog_run_until_user_is_selected (FlashbackPolkitDialog *dialog);
+gchar *flashback_polkit_dialog_run_until_response_for_prompt (FlashbackPolkitDialog *dialog,
+ const gchar *prompt,
+ gboolean echo_chars,
+ gboolean *was_cancelled,
+ gboolean *new_user_selected);
+
+gboolean flashback_polkit_dialog_cancel (FlashbackPolkitDialog *dialog);
+void flashback_polkit_dialog_indicate_error (FlashbackPolkitDialog *dialog);
+void flashback_polkit_dialog_set_info_message (FlashbackPolkitDialog *dialog,
+ const gchar *info_markup);
+
+G_END_DECLS
+
+#endif
diff --git a/gnome-flashback/libpolkit/flashback-polkit-dialog.ui
b/gnome-flashback/libpolkit/flashback-polkit-dialog.ui
new file mode 100644
index 0000000..036ffbe
--- /dev/null
+++ b/gnome-flashback/libpolkit/flashback-polkit-dialog.ui
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.19.0 -->
+<interface>
+ <requires lib="gtk+" version="3.16"/>
+ <template class="FlashbackPolkitDialog" parent="GtkWindow">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Authenticate</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="window_position">center</property>
+ <property name="icon_name">dialog-password</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <object class="GtkBox" id="dialog_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">2</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkBox" id="content_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ <property name="pixel_size">48</property>
+ <property name="icon_name">dialog-password</property>
+ <property name="icon_size">6</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="main_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkLabel" id="main_message_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label"
translatable="yes"><big><b>Title</b></big></property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">70</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="secondary_message_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">An application is attempting to perform an
action that requires privileges. Authentication is required to perform this action.</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">70</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="users_combobox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="entry_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="prompt_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Password:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">password_entry</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="password_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="info_label">
+ <property name="can_focus">False</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkExpander" id="details_expander">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkBox" id="details_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkGrid" id="details_grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="expander_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label"
translatable="yes"><small><b>_Details</b></small></property>
+ <property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButtonBox" id="action_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label" translatable="yes">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cancel_button_clicked_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="auth_button">
+ <property name="label" translatable="yes">_Authenticate</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="auth_button_clicked_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/gnome-flashback/libpolkit/flashback-polkit.c b/gnome-flashback/libpolkit/flashback-polkit.c
new file mode 100644
index 0000000..654ce23
--- /dev/null
+++ b/gnome-flashback/libpolkit/flashback-polkit.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "flashback-polkit.h"
+#include "flashback-listener.h"
+
+struct _FlashbackPolkit
+{
+ GObject parent;
+
+ PolkitSubject *session;
+ PolkitAgentListener *listener;
+
+ gpointer handle;
+};
+
+G_DEFINE_TYPE (FlashbackPolkit, flashback_polkit, G_TYPE_OBJECT)
+
+static void
+unix_session_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ FlashbackPolkit *polkit;
+ GError *error;
+
+ polkit = FLASHBACK_POLKIT (user_data);
+
+ error = NULL;
+ polkit->session = polkit_unix_session_new_for_process_finish (res, &error);
+
+ if (error != NULL)
+ {
+ g_warning ("Unable to determine the session we are in: %s", error->message);
+ g_error_free (error);
+
+ return;
+ }
+
+ polkit->listener = flashback_listener_new ();
+
+ error = NULL;
+ polkit->handle = polkit_agent_listener_register (polkit->listener,
+ POLKIT_AGENT_REGISTER_FLAGS_NONE,
+ polkit->session,
+ "/org/gnome/PolicyKit1/AuthenticationAgent",
+ NULL, /* GCancellable */
+ &error);
+
+ if (error != NULL)
+ {
+ g_warning ("Cannot register authentication agent: %s", error->message);
+ g_error_free (error);
+
+ return;
+ }
+}
+
+static void
+flashback_polkit_dispose (GObject *object)
+{
+ FlashbackPolkit *polkit;
+
+ polkit = FLASHBACK_POLKIT (object);
+
+ if (polkit->handle != NULL)
+ {
+ polkit_agent_listener_unregister (polkit->handle);
+ polkit->handle = NULL;
+ }
+
+ g_clear_object (&polkit->session);
+ g_clear_object (&polkit->listener);
+
+ G_OBJECT_CLASS (flashback_polkit_parent_class)->dispose (object);
+}
+
+static void
+flashback_polkit_class_init (FlashbackPolkitClass *polkit_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (polkit_class);
+
+ object_class->dispose = flashback_polkit_dispose;
+}
+
+static void
+flashback_polkit_init (FlashbackPolkit *polkit)
+{
+ polkit_unix_session_new_for_process (getpid (), NULL, unix_session_cb, polkit);
+}
+
+FlashbackPolkit *
+flashback_polkit_new (void)
+{
+ return g_object_new (FLASHBACK_TYPE_POLKIT, NULL);
+}
diff --git a/gnome-flashback/libpolkit/flashback-polkit.h b/gnome-flashback/libpolkit/flashback-polkit.h
new file mode 100644
index 0000000..01d01c3
--- /dev/null
+++ b/gnome-flashback/libpolkit/flashback-polkit.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FLASHBACK_POLKIT_H
+#define FLASHBACK_POLKIT_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define FLASHBACK_TYPE_POLKIT flashback_polkit_get_type ()
+G_DECLARE_FINAL_TYPE (FlashbackPolkit, flashback_polkit,
+ FLASHBACK, POLKIT, GObject)
+
+FlashbackPolkit *flashback_polkit_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c0a9703..320716b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -15,6 +15,10 @@ gnome-flashback/libdisplay-config/flashback-display-config.c
[type: gettext/glade]gnome-flashback/libdisplay-config/flashback-confirm-dialog.ui
gnome-flashback/libend-session-dialog/flashback-inhibit-dialog.c
[type: gettext/glade]gnome-flashback/libend-session-dialog/flashback-inhibit-dialog.ui
+gnome-flashback/libpolkit/flashback-authenticator.c
+gnome-flashback/libpolkit/flashback-listener.c
+gnome-flashback/libpolkit/flashback-polkit-dialog.c
+[type: gettext/glade]gnome-flashback/libpolkit/flashback-polkit-dialog.ui
gnome-flashback/libsound-applet/gvc-applet.c
gnome-flashback/libsound-applet/gvc-channel-bar.c
gnome-flashback/libsound-applet/gvc/gvc-mixer-control.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]