gnome-control-center/panels/user-accounts/um-login-options.c
Matthias Clasen 1607beaea2 Listen for permission changes
Since the lockbutton doesn't have a changed signal, connecting to
it doesn't help... directly listen for changes of the permission
object instead.
2010-11-15 14:04:14 -05:00

436 lines
14 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright 2009-2010 Red Hat, Inc,
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Written by: Matthias Clasen <mclasen@redhat.com>
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <gconf/gconf-client.h>
#include <gconf/gconf-value.h>
#include <polkit/polkit.h>
#include "um-login-options.h"
#include "um-lockbutton.h"
#include "um-user-manager.h"
#include "um-user.h"
struct _UmLoginOptions {
GtkWidget *autologin_combo;
GtkWidget *userlist_check;
GtkWidget *power_check;
GtkWidget *hints_check;
GtkWidget *guest_check;
GtkWidget *lock_button;
GPermission *permission;
UmUserManager *manager;
DBusGProxy *proxy;
DBusGConnection *connection;
};
enum {
AUTOLOGIN_NAME_COL,
AUTOLOGIN_USER_COL,
NUM_AUTOLOGIN_COLS
};
static gint
sort_login_users (GtkTreeModel *model,
GtkTreeIter *a,
GtkTreeIter *b,
gpointer data)
{
UmUser *ua, *ub;
gint result;
gtk_tree_model_get (model, a, AUTOLOGIN_USER_COL, &ua, -1);
gtk_tree_model_get (model, b, AUTOLOGIN_USER_COL, &ub, -1);
if (ua == NULL)
result = -1;
else if (ub == NULL)
result = 1;
else if (um_user_get_uid (ua) == getuid ())
result = -1;
else if (um_user_get_uid (ub) == getuid ())
result = 1;
else
result = um_user_collate (ua, ub);
if (ua)
g_object_unref (ua);
if (ub)
g_object_unref (ub);
return result;
}
static void
user_added (UmUserManager *um, UmUser *user, UmLoginOptions *d)
{
GtkComboBox *combo;
GtkListStore *store;
GtkTreeIter iter;
g_debug ("adding user '%s', %d", um_user_get_user_name (user), um_user_get_automatic_login (user));
combo = GTK_COMBO_BOX (d->autologin_combo);
store = (GtkListStore*)gtk_combo_box_get_model (combo);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
AUTOLOGIN_NAME_COL, um_user_get_display_name (user),
AUTOLOGIN_USER_COL, user,
-1);
if (um_user_get_automatic_login (user)) {
gtk_combo_box_set_active_iter (combo, &iter);
}
}
static void
user_removed (UmUserManager *um, UmUser *user, UmLoginOptions *d)
{
GtkComboBox *combo;
GtkTreeModel *model;
GtkListStore *store;
GtkTreeIter iter;
UmUser *u;
combo = GTK_COMBO_BOX (d->autologin_combo);
model = gtk_combo_box_get_model (combo);
store = (GtkListStore*)model;
gtk_combo_box_get_active_iter (combo, &iter);
gtk_tree_model_get (model, &iter, AUTOLOGIN_USER_COL, &u, -1);
if (u != NULL) {
if (um_user_get_uid (user) == um_user_get_uid (u)) {
/* autologin user got removed, set back to Disabled */
gtk_list_store_remove (store, &iter);
gtk_combo_box_set_active (combo, 0);
g_object_unref (u);
return;
}
g_object_unref (u);
}
if (gtk_tree_model_get_iter_first (model, &iter)) {
do {
gtk_tree_model_get (model, &iter, AUTOLOGIN_USER_COL, &u, -1);
if (u != NULL) {
if (um_user_get_uid (user) == um_user_get_uid (u)) {
gtk_list_store_remove (store, &iter);
g_object_unref (u);
return;
}
g_object_unref (u);
}
} while (gtk_tree_model_iter_next (model, &iter));
}
}
static void
user_changed (UmUserManager *manager,
UmUser *user,
UmLoginOptions *d)
{
/* FIXME */
}
static void
users_loaded (UmUserManager *manager,
UmLoginOptions *d)
{
GSList *list, *l;
UmUser *user;
list = um_user_manager_list_users (manager);
for (l = list; l; l = l->next) {
user = l->data;
user_added (manager, user, d);
}
g_slist_free (list);
g_signal_connect (manager, "user-added", G_CALLBACK (user_added), d);
g_signal_connect (manager, "user-removed", G_CALLBACK (user_removed), d);
g_signal_connect (manager, "user-changed", G_CALLBACK (user_changed), d);
}
static void update_login_options (GtkWidget *widget, UmLoginOptions *d);
static void
update_boolean_from_gconf (GtkWidget *widget,
UmLoginOptions *d)
{
gchar *cmdline;
gboolean value;
gchar *std_out;
gchar *std_err;
gint status;
GError *error;
const gchar *key;
key = g_object_get_data (G_OBJECT (widget), "gconf-key");
/* GConf fail.
* gconfd does not pick up any changes in the default or mandatory
* databases at runtime. Even a SIGHUP doesn't seem to help. So we
* have to use gconftool to go get the current mandatory values.
*/
cmdline = g_strdup_printf ("gconftool-2 --direct --config-source=\"xml:readonly:/etc/gconf/gconf.xml.defaults;xml:readonly:/etc/gconf/gconf.xml.mandatory\" --get %s", key);
error = NULL;
std_out = NULL;
std_err = NULL;
if (!g_spawn_command_line_sync (cmdline, &std_out, &std_err, &status, &error)) {
g_warning ("Failed to run '%s': %s", cmdline, error->message);
g_error_free (error);
g_free (cmdline);
g_free (std_out);
g_free (std_err);
return;
}
if (WEXITSTATUS (status) != 0) {
g_warning ("Failed to run '%s': %s", cmdline, std_err);
g_free (cmdline);
g_free (std_out);
g_free (std_err);
return;
}
if (std_out[strlen (std_out) - 1] == '\n') {
std_out[strlen (std_out) - 1] = 0;
}
if (g_strcmp0 (std_out, "true") == 0) {
value = TRUE;
}
else {
value = FALSE;
}
g_signal_handlers_block_by_func (widget, update_login_options, d);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), !value);
g_signal_handlers_unblock_by_func (widget, update_login_options, d);
g_free (cmdline);
g_free (std_out);
g_free (std_err);
}
static void
update_login_options (GtkWidget *widget,
UmLoginOptions *d)
{
GError *error;
gboolean active;
GConfValue *value;
const gchar *key = NULL;
gchar *value_string;
if (widget == d->userlist_check ||
widget == d->power_check) {
active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
key = g_object_get_data (G_OBJECT (widget), "gconf-key");
}
else {
g_warning ("unhandled option in update_login_options");
return;
}
error = NULL;
value = gconf_value_new (GCONF_VALUE_BOOL);
gconf_value_set_bool (value, !active);
value_string = gconf_value_encode (value);
if (!dbus_g_proxy_call (d->proxy, "SetMandatoryValue",
&error,
G_TYPE_STRING, key,
G_TYPE_STRING, value_string,
G_TYPE_INVALID,
G_TYPE_INVALID)) {
g_warning ("error calling SetMandatoryValue: %s\n", error->message);
g_error_free (error);
}
g_free (value_string);
gconf_value_free (value);
update_boolean_from_gconf (widget, d);
}
static void
update_autologin (GtkWidget *widget,
UmLoginOptions *d)
{
GtkComboBox *combo = GTK_COMBO_BOX (widget);
GtkTreeModel *model;
GtkTreeIter iter;
UmUser *user;
gboolean enabled;
if (!gtk_widget_is_sensitive (widget))
return;
model = gtk_combo_box_get_model (combo);
gtk_combo_box_get_active_iter (combo, &iter);
gtk_tree_model_get (model, &iter, AUTOLOGIN_USER_COL, &user, -1);
if (user) {
enabled = TRUE;
}
else {
enabled = FALSE;
user = um_user_manager_get_user_by_id (d->manager, getuid ());
g_object_ref (user);
}
um_user_set_automatic_login (user, enabled);
g_object_unref (user);
}
static void
on_permission_changed (GPermission *permission,
GParamSpec *spec,
gpointer data)
{
UmLoginOptions *d = data;
gboolean authorized;
authorized = g_permission_get_allowed (G_PERMISSION (d->permission));
gtk_widget_set_sensitive (d->autologin_combo, authorized);
gtk_widget_set_sensitive (d->userlist_check, authorized);
gtk_widget_set_sensitive (d->power_check, authorized);
gtk_widget_set_sensitive (d->hints_check, authorized);
gtk_widget_set_sensitive (d->guest_check, authorized);
}
UmLoginOptions *
um_login_options_new (GtkBuilder *builder)
{
GtkWidget *widget;
GtkWidget *box;
GtkListStore *store;
GtkTreeIter iter;
GError *error;
UmLoginOptions *um;
/* TODO: get actual login screen options */
um = g_new0 (UmLoginOptions, 1);
um->manager = um_user_manager_ref_default ();
g_signal_connect (um->manager, "users-loaded",
G_CALLBACK (users_loaded), um);
widget = (GtkWidget *) gtk_builder_get_object (builder, "dm-automatic-login-combobox");
um->autologin_combo = widget;
store = gtk_list_store_new (2, G_TYPE_STRING, UM_TYPE_USER);
gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
AUTOLOGIN_NAME_COL, _("Disabled"),
AUTOLOGIN_USER_COL, NULL,
-1);
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store), sort_login_users, NULL, NULL);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
g_signal_connect (widget, "changed",
G_CALLBACK (update_autologin), um);
widget = (GtkWidget *) gtk_builder_get_object (builder, "dm-show-user-list-checkbutton");
um->userlist_check = widget;
g_signal_connect (widget, "toggled",
G_CALLBACK (update_login_options), um);
g_object_set_data (G_OBJECT (widget), "gconf-key",
"/apps/gdm/simple-greeter/disable_user_list");
update_boolean_from_gconf (widget, um);
widget = (GtkWidget *) gtk_builder_get_object (builder, "dm-show-power-buttons-checkbutton");
um->power_check = widget;
g_signal_connect(widget, "toggled",
G_CALLBACK (update_login_options), um);
g_object_set_data (G_OBJECT (widget), "gconf-key",
"/apps/gdm/simple-greeter/disable_restart_buttons");
update_boolean_from_gconf (widget, um);
widget = (GtkWidget *) gtk_builder_get_object (builder, "dm-show-password-hints-checkbutton");
um->hints_check = widget;
g_signal_connect (widget, "toggled",
G_CALLBACK (update_login_options), um);
widget = (GtkWidget *) gtk_builder_get_object (builder, "dm-allow-guest-login-checkbutton");
um->guest_check = widget;
g_signal_connect (widget, "toggled",
G_CALLBACK (update_login_options), um);
um->permission = polkit_permission_new_sync ("org.freedesktop.accounts.set-login-option", NULL, NULL, NULL);
if (um->permission != NULL) {
widget = um_lock_button_new (um->permission);
gtk_widget_show (widget);
box = (GtkWidget *)gtk_builder_get_object (builder, "lockbutton-alignment");
gtk_container_add (GTK_CONTAINER (box), widget);
g_signal_connect (um->permission, "notify",
G_CALLBACK (on_permission_changed), um);
on_permission_changed (um->permission, NULL, um);
um->lock_button = widget;
}
error = NULL;
um->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
if (error != NULL) {
g_warning ("Failed to get system bus connection: %s", error->message);
g_error_free (error);
}
um->proxy = dbus_g_proxy_new_for_name (um->connection,
"org.gnome.GConf.Defaults",
"/",
"org.gnome.GConf.Defaults");
if (um->proxy == NULL) {
g_warning ("Cannot connect to GConf defaults mechanism");
}
return um;
}
void
um_login_options_free (UmLoginOptions *um)
{
if (um->manager)
g_object_unref (um->manager);
if (um->proxy)
g_object_unref (um->proxy);
if (um->connection)
dbus_g_connection_unref (um->connection);
g_free (um);
}