aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/control3
-rw-r--r--po/CMakeLists.txt2
-rw-r--r--src/backend-dbus/actions.c314
-rw-r--r--tests/backend-dbus/test-actions.cc74
4 files changed, 313 insertions, 80 deletions
diff --git a/debian/control b/debian/control
index a0dfdb1..522eeb1 100644
--- a/debian/control
+++ b/debian/control
@@ -26,7 +26,8 @@ Depends: ${shlibs:Depends},
gnome-settings-daemon,
Recommends: indicator-applet (>= 0.2) | indicator-renderer,
gnome-screensaver
-Suggests: lightdm
+Suggests: lightdm,
+ zenity
Description: indicator showing session management, status and user switching
This indicator is designed to be placed on the right side of a panel and
give the user easy control for changing their instant message status.
diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt
index 8325f6e..c47d584 100644
--- a/po/CMakeLists.txt
+++ b/po/CMakeLists.txt
@@ -1,3 +1,3 @@
include (Translations)
add_translations_directory ("${GETTEXT_PACKAGE}")
-add_translations_catalog ("${GETTEXT_PACKAGE}" ../src/)
+add_translations_catalog ("${GETTEXT_PACKAGE}" ../src/ ../src/dbus-backend)
diff --git a/src/backend-dbus/actions.c b/src/backend-dbus/actions.c
index c095896..ed1e708 100644
--- a/src/backend-dbus/actions.c
+++ b/src/backend-dbus/actions.c
@@ -18,6 +18,7 @@
*/
#include <glib.h>
+#include <glib/gi18n.h>
#include "dbus-end-session-dialog.h"
#include "dbus-login1-manager.h"
@@ -39,6 +40,7 @@ struct _IndicatorSessionActionsDbusPriv
GCancellable * cancellable;
GSettings * lockdown_settings;
+ GSettings * indicator_settings;
GnomeScreenSaver * screen_saver;
GnomeSessionManager * session_manager;
Login1Manager * login1_manager;
@@ -48,6 +50,7 @@ struct _IndicatorSessionActionsDbusPriv
GCancellable * dm_seat_cancellable;
Webcredentials * webcredentials;
EndSessionDialog * end_session_dialog;
+ char * zenity;
gboolean can_suspend;
gboolean can_hibernate;
@@ -80,6 +83,44 @@ log_and_clear_error (GError ** err, const char * loc, const char * func)
****
***/
+typedef enum
+{
+ PROMPT_NONE,
+ PROMPT_WITH_ZENITY,
+ PROMPT_WITH_UNITY
+}
+prompt_status_t;
+
+static prompt_status_t
+get_prompt_status (IndicatorSessionActionsDbus * self)
+{
+ prompt_status_t prompt = PROMPT_NONE;
+ const priv_t * p = self->priv;
+
+ if (!g_settings_get_boolean (p->indicator_settings, "suppress-logout-restart-shutdown"))
+ {
+ /* can we use the Unity prompt? */
+ if ((prompt == PROMPT_NONE) && p && p->end_session_dialog)
+ {
+ GDBusProxy * proxy = G_DBUS_PROXY (p->end_session_dialog);
+ char * name = g_dbus_proxy_get_name_owner (proxy);
+ if (name != NULL)
+ prompt = PROMPT_WITH_UNITY;
+ g_free (name);
+ }
+
+ /* can we use zenity? */
+ if ((prompt == PROMPT_NONE) && p && p->zenity)
+ prompt = PROMPT_WITH_ZENITY;
+ }
+
+ return prompt;
+}
+
+/***
+****
+***/
+
static void
on_seat_notify_multi_session (IndicatorSessionActionsDbus * self)
{
@@ -288,6 +329,7 @@ on_end_session_dialog_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res
INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv->end_session_dialog = end_session_dialog;
indicator_session_actions_notify_can_prompt (INDICATOR_SESSION_ACTIONS(gself));
+ indicator_session_actions_notify_can_reboot (INDICATOR_SESSION_ACTIONS(gself));
}
log_and_clear_error (&err, G_STRLOC, G_STRFUNC);
@@ -310,7 +352,31 @@ my_can_logout (IndicatorSessionActions * self)
{
priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv;
- return !g_settings_get_boolean (p->lockdown_settings, "disable-log-out");
+ if (g_settings_get_boolean (p->indicator_settings, "suppress-logout-menuitem"))
+ return FALSE;
+
+ if (g_settings_get_boolean (p->lockdown_settings, "disable-log-out"))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+my_can_reboot (IndicatorSessionActions * actions)
+{
+ IndicatorSessionActionsDbus * self = INDICATOR_SESSION_ACTIONS_DBUS(actions);
+ priv_t * p = self->priv;
+
+ if (g_settings_get_boolean (p->indicator_settings, "suppress-restart-menuitem"))
+ return FALSE;
+
+ /* Shutdown and Restart are the same dialog prompt in Unity,
+ so disable the redundant 'Restart' menuitem in that mode */
+ if (!g_settings_get_boolean (p->indicator_settings, "suppress-shutdown-menuitem"))
+ if (get_prompt_status(self) == PROMPT_WITH_UNITY)
+ return FALSE;
+
+ return TRUE;
}
static gboolean
@@ -341,18 +407,7 @@ my_can_hibernate (IndicatorSessionActions * self)
static gboolean
my_can_prompt (IndicatorSessionActions * self)
{
- gboolean can_prompt = FALSE;
- const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv;
-
- if (p && p->end_session_dialog)
- {
- GDBusProxy * proxy = G_DBUS_PROXY (p->end_session_dialog);
- char * name = g_dbus_proxy_get_name_owner (proxy);
- can_prompt = name != NULL;
- g_free (name);
- }
-
- return can_prompt;
+ return get_prompt_status(INDICATOR_SESSION_ACTIONS_DBUS(self)) != PROMPT_NONE;
}
static gboolean
@@ -396,50 +451,51 @@ my_hibernate (IndicatorSessionActions * self)
***/
static void
-logout_now (IndicatorSessionActions * self, gboolean try_to_prompt)
+logout_now (IndicatorSessionActionsDbus * self)
{
- priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv;
- const int type = try_to_prompt ? 0 : 1;
+ priv_t * p = self->priv;
g_return_if_fail (p->session_manager != NULL);
gnome_session_manager_call_logout (p->session_manager,
- type,
+ 1, /* don't prompt */
p->cancellable,
NULL,
NULL);
}
static void
-logout_now_with_prompt (IndicatorSessionActions * self)
+on_reboot_response (GObject * o,
+ GAsyncResult * res,
+ gpointer unused G_GNUC_UNUSED)
{
- logout_now (self, TRUE);
-}
-
-static void
-logout_now_quietly (IndicatorSessionActions * self)
-{
- logout_now (self, FALSE);
+ GError * err = NULL;
+ login1_manager_call_reboot_finish (LOGIN1_MANAGER(o), res, &err);
+ if (err != NULL)
+ {
+ g_warning ("Unable to reboot: %s", err->message);
+ g_error_free (err);
+ }
}
static void
-reboot_now (IndicatorSessionActions * self)
+reboot_now (IndicatorSessionActionsDbus * self)
{
- priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv;
+ priv_t * p = self->priv;
g_return_if_fail (p->login1_manager != NULL);
login1_manager_call_reboot (p->login1_manager,
FALSE,
p->login1_manager_cancellable,
- NULL,
+ on_reboot_response,
NULL);
}
static void
-power_off_now (IndicatorSessionActions * self)
+power_off_now (IndicatorSessionActionsDbus * self)
{
- priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv;
+ priv_t * p = self->priv;
g_return_if_fail (p->login1_manager != NULL);
@@ -477,7 +533,7 @@ on_open_end_session_dialog_ready (GObject * o,
}
static void
-show_end_session_dialog (IndicatorSessionActionsDbus * self, int type)
+show_unity_end_session_dialog (IndicatorSessionActionsDbus * self, int type)
{
priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv;
gpointer o = p->end_session_dialog;
@@ -485,7 +541,7 @@ show_end_session_dialog (IndicatorSessionActionsDbus * self, int type)
g_assert (o != NULL);
- g_signal_connect_swapped (o, "confirmed-logout", G_CALLBACK(logout_now_quietly), self);
+ g_signal_connect_swapped (o, "confirmed-logout", G_CALLBACK(logout_now), self);
g_signal_connect_swapped (o, "confirmed-reboot", G_CALLBACK(reboot_now), self);
g_signal_connect_swapped (o, "confirmed-shutdown", G_CALLBACK(power_off_now), self);
g_signal_connect_swapped (o, "canceled", G_CALLBACK(on_end_session_dialog_canceled), self);
@@ -497,34 +553,140 @@ show_end_session_dialog (IndicatorSessionActionsDbus * self, int type)
self);
}
-static void
-my_logout (IndicatorSessionActions * self)
-{
- if (my_can_prompt (self))
- show_end_session_dialog (INDICATOR_SESSION_ACTIONS_DBUS(self), END_SESSION_TYPE_LOGOUT);
+static gboolean
+zenity_question (IndicatorSessionActionsDbus * self,
+ const char * icon_name,
+ const char * title,
+ const char * text,
+ const char * ok_label,
+ const char * cancel_label)
+{
+ char * command_line;
+ int exit_status;
+ gboolean confirmed;
+
+ command_line = g_strdup_printf ("%s"
+ " --question"
+ " --icon-name=\"%s\""
+ " --title=\"%s\""
+ " --text=\"%s\""
+ " --ok-label=\"%s\""
+ " --cancel-label=\"%s\""
+ " --no-wrap",
+ self->priv->zenity,
+ icon_name,
+ title,
+ text,
+ ok_label,
+ cancel_label);
+
+ exit_status = -1;
+ if (!g_spawn_command_line_sync (command_line, NULL, NULL, &exit_status, NULL))
+ {
+ /* Treat failure-to-prompt as user confirmation.
+ Otherwise how will the user ever log out? */
+ confirmed = TRUE;
+ }
else
- logout_now_with_prompt (self);
+ {
+ confirmed = exit_status == 0;
+ }
+
+ g_free (command_line);
+ return confirmed;
}
+static void
+my_logout (IndicatorSessionActions * actions)
+{
+ IndicatorSessionActionsDbus * self = INDICATOR_SESSION_ACTIONS_DBUS (actions);
+
+ switch (get_prompt_status (self))
+ {
+ case PROMPT_WITH_UNITY:
+ show_unity_end_session_dialog (self, END_SESSION_TYPE_LOGOUT);
+ break;
+
+ case PROMPT_NONE:
+ logout_now (self);
+ break;
+
+ case PROMPT_WITH_ZENITY:
+ {
+ const char * primary = _("Are you sure you want to close all programs and log out?");
+ const char * secondary = _("Some software updates won't be applied until the computer next restarts.");
+ char * text = g_strdup_printf ("<big><b>%s</b></big>\n \n%s", primary, secondary);
+
+ gboolean confirmed = zenity_question (self,
+ "system-log-out",
+ _("Log Out"),
+ text,
+ _("Log Out"),
+ _("Cancel"));
+
+ g_free (text);
+
+ if (confirmed)
+ logout_now (self);
+ break;
+ }
+ }
+}
static void
-my_reboot (IndicatorSessionActions * self)
+my_reboot (IndicatorSessionActions * actions)
{
- if (my_can_prompt (self))
- show_end_session_dialog (INDICATOR_SESSION_ACTIONS_DBUS(self), END_SESSION_TYPE_REBOOT);
- else
- reboot_now (self);
+ IndicatorSessionActionsDbus * self = INDICATOR_SESSION_ACTIONS_DBUS (actions);
+
+ switch (get_prompt_status (self))
+ {
+ case PROMPT_WITH_UNITY:
+ show_unity_end_session_dialog (self, END_SESSION_TYPE_REBOOT);
+ break;
+
+ case PROMPT_NONE:
+ reboot_now (self);
+ break;
+
+ case PROMPT_WITH_ZENITY:
+ if (zenity_question (self,
+ "system-restart",
+ _("Restart"),
+ _("Are you sure you want to close all programs and restart the computer?"),
+ _("Restart"),
+ _("Cancel")))
+ reboot_now (self);
+ break;
+ }
}
static void
-my_power_off (IndicatorSessionActions * self)
+my_power_off (IndicatorSessionActions * actions)
{
- /* NB: TYPE_REBOOT instead of TYPE_SHUTDOWN because
- the latter adds lock & logout options in Unity... */
- if (my_can_prompt (self))
- show_end_session_dialog (INDICATOR_SESSION_ACTIONS_DBUS(self), END_SESSION_TYPE_REBOOT);
- else
- power_off_now (self);
+ IndicatorSessionActionsDbus * self = INDICATOR_SESSION_ACTIONS_DBUS (actions);
+
+ switch (get_prompt_status (self))
+ {
+ case PROMPT_WITH_UNITY:
+ /* NB: TYPE_REBOOT instead of TYPE_SHUTDOWN because
+ the latter adds lock & logout options in Unity... */
+ show_unity_end_session_dialog (self, END_SESSION_TYPE_REBOOT);
+ break;
+
+ case PROMPT_WITH_ZENITY:
+ if (zenity_question (self,
+ "system-shutdown",
+ _("Shut Down"),
+ _("Are you sure you want to close all programs and shut down the computer?"),
+ _("Shut Down"),
+ _("Cancel")))
+ power_off_now (self);
+ break;
+
+ case PROMPT_NONE:
+ power_off_now (self);
+ break;
+ }
}
/***
@@ -620,11 +782,32 @@ my_dispose (GObject * o)
g_clear_object (&p->cancellable);
}
- g_clear_object (&p->lockdown_settings);
+ if (p->indicator_settings != NULL)
+ {
+ g_signal_handlers_disconnect_by_data (p->indicator_settings, self);
+ g_clear_object (&p->indicator_settings);
+ }
+
+ if (p->lockdown_settings != NULL)
+ {
+ g_signal_handlers_disconnect_by_data (p->lockdown_settings, self);
+ g_clear_object (&p->lockdown_settings);
+ }
+
+ if (p->webcredentials != NULL)
+ {
+ g_signal_handlers_disconnect_by_data (p->webcredentials, self);
+ g_clear_object (&p->webcredentials);
+ }
+
+ if (p->end_session_dialog != NULL)
+ {
+ stop_listening_to_dialog (self);
+ g_clear_object (&p->end_session_dialog);
+ }
+
g_clear_object (&p->screen_saver);
g_clear_object (&p->session_manager);
- g_clear_object (&p->webcredentials);
- g_clear_object (&p->end_session_dialog);
set_dm_seat (self, NULL);
set_login1_manager (self, NULL);
set_login1_seat (self, NULL);
@@ -632,6 +815,16 @@ my_dispose (GObject * o)
G_OBJECT_CLASS (indicator_session_actions_dbus_parent_class)->dispose (o);
}
+static void
+my_finalize (GObject * o)
+{
+ IndicatorSessionActionsDbus * self = INDICATOR_SESSION_ACTIONS_DBUS (o);
+ priv_t * p = self->priv;
+
+ g_free (p->zenity);
+}
+
+
/***
**** GObject Boilerplate
***/
@@ -645,10 +838,12 @@ indicator_session_actions_dbus_class_init (IndicatorSessionActionsDbusClass * kl
object_class = G_OBJECT_CLASS (klass);
object_class->dispose = my_dispose;
+ object_class->finalize = my_finalize;
actions_class = INDICATOR_SESSION_ACTIONS_CLASS (klass);
actions_class->can_lock = my_can_lock;
actions_class->can_logout = my_can_logout;
+ actions_class->can_reboot = my_can_reboot;
actions_class->can_switch = my_can_switch;
actions_class->can_suspend = my_can_suspend;
actions_class->can_hibernate = my_can_hibernate;
@@ -684,6 +879,8 @@ indicator_session_actions_dbus_init (IndicatorSessionActionsDbus * self)
p->seat_allows_activation = TRUE;
self->priv = p;
+ p->zenity = g_find_program_in_path ("zenity");
+
s = g_settings_new ("org.gnome.desktop.lockdown");
g_signal_connect_swapped (s, "changed::disable-lock-screen",
G_CALLBACK(indicator_session_actions_notify_can_lock), self);
@@ -693,6 +890,17 @@ indicator_session_actions_dbus_init (IndicatorSessionActionsDbus * self)
G_CALLBACK(indicator_session_actions_notify_can_switch), self);
p->lockdown_settings = s;
+ s = g_settings_new ("com.canonical.indicator.session");
+ g_signal_connect_swapped (s, "changed::suppress-logout-restart-shutdown",
+ G_CALLBACK(indicator_session_actions_notify_can_prompt), self);
+ g_signal_connect_swapped (s, "changed::suppress-logout-restart-shutdown",
+ G_CALLBACK(indicator_session_actions_notify_can_reboot), self);
+ g_signal_connect_swapped (s, "changed::suppress-restart-menuitem",
+ G_CALLBACK(indicator_session_actions_notify_can_reboot), self);
+ g_signal_connect_swapped (s, "changed::suppress-shutdown-menuitem",
+ G_CALLBACK(indicator_session_actions_notify_can_reboot), self);
+ p->indicator_settings = s;
+
gnome_screen_saver_proxy_new_for_bus (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
"org.gnome.ScreenSaver",
diff --git a/tests/backend-dbus/test-actions.cc b/tests/backend-dbus/test-actions.cc
index a7e7a5f..c0f8517 100644
--- a/tests/backend-dbus/test-actions.cc
+++ b/tests/backend-dbus/test-actions.cc
@@ -22,6 +22,8 @@
#include "backend.h"
#include "backend-dbus/backend-dbus.h"
+#define SUPPRESS_KEY "suppress-logout-restart-shutdown"
+
/***
****
***/
@@ -36,12 +38,14 @@ class Actions: public GTestMockDBusFixture
GCancellable * cancellable;
IndicatorSessionActions * actions;
+ GSettings * indicator_settings;
virtual void SetUp ()
{
super :: SetUp ();
// init 'actions'
+ indicator_settings = g_settings_new ("com.canonical.indicator.session");
cancellable = g_cancellable_new ();
actions = 0;
backend_get (cancellable, &actions, NULL, NULL);
@@ -52,6 +56,7 @@ class Actions: public GTestMockDBusFixture
virtual void TearDown ()
{
g_cancellable_cancel (cancellable);
+ g_clear_object (&indicator_settings);
g_clear_object (&cancellable);
g_clear_object (&actions);
@@ -187,6 +192,7 @@ TEST_F (Actions, CanHibernate)
TEST_F (Actions, Reboot)
{
ASSERT_TRUE (login1_manager->last_action().empty());
+ ASSERT_FALSE (g_settings_get_boolean (indicator_settings, SUPPRESS_KEY));
// confirm that user is prompted
// and that no action is taken when the user cancels the dialog
@@ -207,15 +213,18 @@ TEST_F (Actions, Reboot)
ASSERT_EQ (login1_manager->last_action(), "reboot");
// confirm that we try to reboot w/o prompting
- // if the EndSessionDialog isn't available
- delete end_session_dialog;
- end_session_dialog = 0;
+ // if prompting is disabled
login1_manager->clear_last_action ();
+ ASSERT_EQ ("", login1_manager->last_action());
+ g_settings_set_boolean (indicator_settings, SUPPRESS_KEY, TRUE);
+ wait_msec (50);
ASSERT_TRUE (login1_manager->last_action().empty());
wait_msec (50);
indicator_session_actions_reboot (actions);
wait_msec (50);
- ASSERT_EQ (login1_manager->last_action(), "reboot");
+ ASSERT_EQ ("reboot", login1_manager->last_action());
+
+ g_settings_reset (indicator_settings, SUPPRESS_KEY);
}
TEST_F (Actions, PowerOff)
@@ -242,13 +251,16 @@ TEST_F (Actions, PowerOff)
// confirm that we try to shutdown w/o prompting
// if the EndSessionDialog isn't available
- delete end_session_dialog;
- end_session_dialog = 0;
+ // if prompting is disabled
login1_manager->clear_last_action ();
+ ASSERT_EQ ("", login1_manager->last_action());
+ g_settings_set_boolean (indicator_settings, SUPPRESS_KEY, TRUE);
wait_msec (50);
indicator_session_actions_power_off (actions);
wait_msec (50);
ASSERT_EQ (login1_manager->last_action(), "power-off");
+
+ g_settings_reset (indicator_settings, SUPPRESS_KEY);
}
TEST_F (Actions, Logout)
@@ -273,14 +285,17 @@ TEST_F (Actions, Logout)
wait_msec (100);
ASSERT_EQ (MockSessionManager::LogoutQuiet, session_manager->last_action ());
- // confirm that we try to call SessionManager::LogoutNormal
- // if the EndSessionDialog isn't available
- delete end_session_dialog;
- end_session_dialog = 0;
+ // confirm that we try to call SessionManager::LogoutQuet
+ // when prompts are disabled
+ login1_manager->clear_last_action ();
+ ASSERT_EQ ("", login1_manager->last_action());
+ g_settings_set_boolean (indicator_settings, SUPPRESS_KEY, TRUE);
wait_msec (50);
indicator_session_actions_logout (actions);
wait_msec (50);
- ASSERT_EQ (MockSessionManager::LogoutNormal, session_manager->last_action ());
+ ASSERT_EQ (MockSessionManager::LogoutQuiet, session_manager->last_action ());
+
+ g_settings_reset (indicator_settings, SUPPRESS_KEY);
}
TEST_F (Actions, Suspend)
@@ -389,22 +404,31 @@ TEST_F (Actions, HasOnlineAccountError)
ASSERT_EQ (b, gb);
}
-TEST_F (Actions, CanPrompt)
+namespace
{
- gboolean b;
+ static gboolean toggle_suppress (gpointer settings)
+ {
+ const char * key = SUPPRESS_KEY;
+ gboolean b = g_settings_get_boolean (G_SETTINGS(settings), key);
+ g_settings_set_boolean (G_SETTINGS(settings), key, !b);
+ return G_SOURCE_REMOVE;
+ }
+}
- ASSERT_TRUE (indicator_session_actions_can_prompt (actions));
+TEST_F (Actions, SuppressPrompts)
+{
+ for (int i=0; i<3; ++i)
+ {
+ bool b;
+ gboolean b2;
- delete end_session_dialog;
- end_session_dialog = 0;
- wait_msec (50);
- ASSERT_FALSE (indicator_session_actions_can_prompt (actions));
- g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT, &b, NULL);
- ASSERT_FALSE (b);
+ b = indicator_session_actions_can_prompt (actions);
+ b2 = !g_settings_get_boolean (indicator_settings, SUPPRESS_KEY);
+ ASSERT_EQ (b, b2);
+
+ g_idle_add (toggle_suppress, indicator_settings);
+ wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT);
+ }
- end_session_dialog = new MockEndSessionDialog (loop, conn);
- wait_msec (50);
- ASSERT_TRUE (indicator_session_actions_can_prompt (actions));
- g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT, &b, NULL);
- ASSERT_TRUE (b);
+ g_settings_reset (indicator_settings, SUPPRESS_KEY);
}