/*
* Copyright (C) 2010 Stefan Walter
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gcr-unlock-options-widget.h"
#include <glib/gi18n-lib.h>
/**
* SECTION:gcr-unlock-options-widget
* @title: GcrUnlockOptionsWidget
* @short_description: A widget for unlock options
*
* This widget displays a set of unlock options for the user to select. The user
* can choose between keeping caching the unlock indefinitely, or for a given
* amount of time.
*
* Each option has a different name, for example #GCR_UNLOCK_OPTION_ALWAYS. These
* names are used together with the various functions like
* gcr_unlock_options_widget_get_choice().
*/
/**
* GCR_UNLOCK_OPTION_ALWAYS:
*
* Option name for caching unlock indefinitely.
*/
/**
* GCR_UNLOCK_OPTION_IDLE:
*
* Option name for caching unlock for a certain amount of idle time.
*/
/**
* GCR_UNLOCK_OPTION_SESSION:
*
* Option name for caching unlock for the current session.
*/
/**
* GCR_UNLOCK_OPTION_TIMEOUT:
*
* Option name for caching unlock for a certain amount of time.
*/
/**
* GcrUnlockOptionsWidget:
*
* An unlock options widget.
*/
/**
* GcrUnlockOptionsWidgetClass:
*
* Class for #GcrUnlockOptionsWidget.
*/
enum {
PROP_0,
PROP_CHOICE,
PROP_TTL
};
struct _GcrUnlockOptionsWidget {
GtkBin parent;
/*< private >*/
GcrUnlockOptionsWidgetPrivate *pv;
};
struct _GcrUnlockOptionsWidgetClass {
GtkBinClass parent_class;
};
struct _GcrUnlockOptionsWidgetPrivate {
GtkBuilder *builder;
gchar *choice;
};
G_DEFINE_TYPE (GcrUnlockOptionsWidget, gcr_unlock_options_widget, GTK_TYPE_BIN);
/* -----------------------------------------------------------------------------
* INTERNAL
*/
static GtkToggleButton*
builder_get_toggle_button (GtkBuilder *builder, const gchar *name)
{
GObject *object = gtk_builder_get_object (builder, name);
g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (object), NULL);
return GTK_TOGGLE_BUTTON (object);
}
static GtkSpinButton*
builder_get_spin_button (GtkBuilder *builder, const gchar *name)
{
GObject *object = gtk_builder_get_object (builder, name);
g_return_val_if_fail (GTK_IS_SPIN_BUTTON (object), NULL);
return GTK_SPIN_BUTTON (object);
}
static const gchar*
widget_name_for_option (const gchar *option)
{
g_return_val_if_fail (option, NULL);
if (g_str_equal (option, GCR_UNLOCK_OPTION_ALWAYS))
return "lock_always_choice";
else if (g_str_equal (option, GCR_UNLOCK_OPTION_SESSION))
return "lock_session_choice";
else if (g_str_equal (option, GCR_UNLOCK_OPTION_TIMEOUT))
return "lock_timeout_choice";
else if (g_str_equal (option, GCR_UNLOCK_OPTION_IDLE))
return "lock_idle_choice";
else
return NULL;
}
static GtkToggleButton*
widget_button_for_option (GcrUnlockOptionsWidget *self, const gchar *option)
{
const gchar *name = widget_name_for_option (option);
g_return_val_if_fail (name, NULL);
return builder_get_toggle_button (self->pv->builder, name);
}
static const gchar*
widget_button_to_option (GcrUnlockOptionsWidget *self, GtkToggleButton *button)
{
const gchar *option;
g_return_val_if_fail (button, NULL);
option = g_object_get_data (G_OBJECT (button), "unlock-choice");
g_return_val_if_fail (option, NULL);
return option;
}
static void
on_choice_toggled (GtkToggleButton *button, GcrUnlockOptionsWidget *self)
{
GtkWidget *spin;
GtkToggleButton *after, *idle;
spin = GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "lock_minutes_spin"));
after = builder_get_toggle_button (self->pv->builder, "lock_timeout_choice");
idle = builder_get_toggle_button (self->pv->builder, "lock_idle_choice");
gtk_widget_set_sensitive (spin, gtk_toggle_button_get_active (after) ||
gtk_toggle_button_get_active (idle));
if (gtk_toggle_button_get_active (button)) {
g_free (self->pv->choice);
self->pv->choice = g_strdup (widget_button_to_option (self, button));
}
}
/* -----------------------------------------------------------------------------
* OBJECT
*/
static GObject*
gcr_unlock_options_widget_constructor (GType type, guint n_props, GObjectConstructParam *props)
{
GObject *obj = G_OBJECT_CLASS (gcr_unlock_options_widget_parent_class)->constructor (type, n_props, props);
GcrUnlockOptionsWidget *self = NULL;
GtkToggleButton *button;
GtkWidget *widget;
if (obj) {
self = GCR_UNLOCK_OPTIONS_WIDGET (obj);
if (!gtk_builder_add_from_resource (self->pv->builder, "/org/gnome/gcr/ui/gcr-unlock-options-widget.ui", NULL))
g_return_val_if_reached (obj);
widget = GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "unlock-options-widget"));
g_return_val_if_fail (GTK_IS_WIDGET (widget), obj);
gtk_container_add (GTK_CONTAINER (self), widget);
gtk_widget_show (widget);
button = builder_get_toggle_button (self->pv->builder, "lock_always_choice");
g_signal_connect (button, "toggled", G_CALLBACK (on_choice_toggled), self);
g_object_set_data (G_OBJECT (button), "unlock-choice", GCR_UNLOCK_OPTION_ALWAYS);
button = builder_get_toggle_button (self->pv->builder, "lock_session_choice");
g_signal_connect (button, "toggled", G_CALLBACK (on_choice_toggled), self);
g_object_set_data (G_OBJECT (button), "unlock-choice", GCR_UNLOCK_OPTION_SESSION);
on_choice_toggled (button, self);
button = builder_get_toggle_button (self->pv->builder, "lock_timeout_choice");
g_signal_connect (button, "toggled", G_CALLBACK (on_choice_toggled), self);
g_object_set_data (G_OBJECT (button), "unlock-choice", GCR_UNLOCK_OPTION_TIMEOUT);
button = builder_get_toggle_button (self->pv->builder, "lock_idle_choice");
g_signal_connect (button, "toggled", G_CALLBACK (on_choice_toggled), self);
g_object_set_data (G_OBJECT (button), "unlock-choice", GCR_UNLOCK_OPTION_IDLE);
}
return obj;
}
static void
gcr_unlock_options_widget_init (GcrUnlockOptionsWidget *self)
{
self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_UNLOCK_OPTIONS_WIDGET, GcrUnlockOptionsWidgetPrivate));
self->pv->builder = gtk_builder_new ();
}
static void
gcr_unlock_options_widget_dispose (GObject *obj)
{
GcrUnlockOptionsWidget *self = GCR_UNLOCK_OPTIONS_WIDGET (obj);
if (self->pv->builder)
g_object_unref (self->pv->builder);
self->pv->builder = NULL;
G_OBJECT_CLASS (gcr_unlock_options_widget_parent_class)->dispose (obj);
}
static void
gcr_unlock_options_widget_finalize (GObject *obj)
{
GcrUnlockOptionsWidget *self = GCR_UNLOCK_OPTIONS_WIDGET (obj);
g_assert (!self->pv->builder);
g_free (self->pv->choice);
self->pv->choice = NULL;
G_OBJECT_CLASS (gcr_unlock_options_widget_parent_class)->finalize (obj);
}
static void
gcr_unlock_options_widget_set_property (GObject *obj, guint prop_id, const GValue *value,
GParamSpec *pspec)
{
GcrUnlockOptionsWidget *self = GCR_UNLOCK_OPTIONS_WIDGET (obj);
switch (prop_id) {
case PROP_CHOICE:
gcr_unlock_options_widget_set_choice (self, g_value_get_string (value));
break;
case PROP_TTL:
gcr_unlock_options_widget_set_ttl (self, g_value_get_uint (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
}
}
static void
gcr_unlock_options_widget_get_property (GObject *obj, guint prop_id, GValue *value,
GParamSpec *pspec)
{
GcrUnlockOptionsWidget *self = GCR_UNLOCK_OPTIONS_WIDGET (obj);
switch (prop_id) {
case PROP_CHOICE:
g_value_set_string (value, gcr_unlock_options_widget_get_choice (self));
break;
case PROP_TTL:
g_value_set_uint (value, gcr_unlock_options_widget_get_ttl (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
}
}
static void
gcr_unlock_options_widget_class_init (GcrUnlockOptionsWidgetClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gcr_unlock_options_widget_parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (klass, sizeof (GcrUnlockOptionsWidgetPrivate));
gobject_class->constructor = gcr_unlock_options_widget_constructor;
gobject_class->dispose = gcr_unlock_options_widget_dispose;
gobject_class->finalize = gcr_unlock_options_widget_finalize;
gobject_class->set_property = gcr_unlock_options_widget_set_property;
gobject_class->get_property = gcr_unlock_options_widget_get_property;
g_object_class_install_property (gobject_class, PROP_CHOICE,
g_param_spec_string ("choice", "Choice", "Unlock Option Choice",
NULL, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_TTL,
g_param_spec_uint ("ttl", "TTL", "Unlock Option Timeout in Seconds",
0, G_MAXUINT, 0, G_PARAM_READWRITE));
}
/* -----------------------------------------------------------------------------
* PUBLIC
*/
/**
* gcr_unlock_options_widget_new:
*
* Create a new #GcrUnlockOptionsWidget.
*
* Returns: (transfer full) (type GcrUi.UnlockOptionsWidget): a new #GcrUnlockOptionsWidget
*/
GtkWidget *
gcr_unlock_options_widget_new (void)
{
return g_object_new (GCR_TYPE_UNLOCK_OPTIONS_WIDGET, NULL);
}
/**
* gcr_unlock_options_widget_get_choice:
* @self: The unlock options widget
*
* Get the currently selected option, like %GCR_UNLOCK_OPTION_ALWAYS.
*
* Returns: The currently selected option name.
*/
const gchar*
gcr_unlock_options_widget_get_choice (GcrUnlockOptionsWidget *self)
{
g_return_val_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self), NULL);
return self->pv->choice;
}
/**
* gcr_unlock_options_widget_set_choice:
* @self: The unlock options widget
* @option: The option name
*
* Set the currently selected option. Use an option name like
* %GCR_UNLOCK_OPTION_ALWAYS.
*/
void
gcr_unlock_options_widget_set_choice (GcrUnlockOptionsWidget *self, const gchar *option)
{
GtkToggleButton *button;
g_return_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self));
g_return_if_fail (option);
button = widget_button_for_option (self, option);
gtk_toggle_button_set_active (button, TRUE);
}
/**
* gcr_unlock_options_widget_get_ttl:
* @self: The unlock options widget
*
* Get the timeout setting set for unlock options that have a timeout.
* This will also return a valid value if the currently selected option
* does not have a timeout.
*
* Returns: The unlock timeout in seconds.
*/
guint
gcr_unlock_options_widget_get_ttl (GcrUnlockOptionsWidget *self)
{
GtkSpinButton *spin;
gint amount;
g_return_val_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self), 0);
spin = builder_get_spin_button (self->pv->builder, "lock_minutes_spin");
amount = gtk_spin_button_get_value_as_int (spin);
return amount * 60;
}
/**
* gcr_unlock_options_widget_set_ttl:
* @self: The unlock options widget
* @ttl: The timeout to set, in seconds
*
* Set the current setting for the timeout. This can be set even when the
* currently selected option does not have a timeout.
*/
void
gcr_unlock_options_widget_set_ttl (GcrUnlockOptionsWidget *self, guint ttl)
{
GtkSpinButton *spin;
guint amount;
g_return_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self));
amount = ttl / 60;
if (!amount || ttl % 60)
amount += 1;
spin = builder_get_spin_button (self->pv->builder, "lock_minutes_spin");
gtk_spin_button_set_value (spin, amount);
}
/**
* gcr_unlock_options_widget_get_label:
* @self: The unlock options widget
* @option: The option name
*
* Get the label for one of the options. Use an option name like
* %GCR_UNLOCK_OPTION_ALWAYS.
*
* Returns: The current label for the option.
*/
const gchar*
gcr_unlock_options_widget_get_label (GcrUnlockOptionsWidget *self, const gchar *option)
{
GtkToggleButton *button;
const gchar *name;
g_return_val_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self), NULL);
g_return_val_if_fail (option, NULL);
name = widget_name_for_option (option);
g_return_val_if_fail (name, NULL);
button = builder_get_toggle_button (self->pv->builder, name);
g_return_val_if_fail (button, NULL);
return gtk_button_get_label (GTK_BUTTON (button));
}
/**
* gcr_unlock_options_widget_set_label:
* @self: The unlock options widget
* @option: The option name
* @text: The new label
*
* Set the label for one of the options. Use an option name like
* %GCR_UNLOCK_OPTION_ALWAYS.
*/
void
gcr_unlock_options_widget_set_label (GcrUnlockOptionsWidget *self, const gchar *option,
const gchar *text)
{
GtkToggleButton *button;
const gchar *name;
g_return_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self));
g_return_if_fail (option);
g_return_if_fail (text);
name = widget_name_for_option (option);
g_return_if_fail (name);
button = builder_get_toggle_button (self->pv->builder, name);
g_return_if_fail (button);
gtk_button_set_label (GTK_BUTTON (button), text);
}
/**
* gcr_unlock_options_widget_get_sensitive:
* @self: The unlock options widget
* @option: The option name
*
* Get the sensitivity state for one of the options. Use an option name like
* %GCR_UNLOCK_OPTION_ALWAYS.
*
* Returns: Whether the option is sensitive or not.
*/
gboolean
gcr_unlock_options_widget_get_sensitive (GcrUnlockOptionsWidget *self, const gchar *option)
{
GtkToggleButton *button;
GtkStateType state;
g_return_val_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self), FALSE);
g_return_val_if_fail (option, FALSE);
button = widget_button_for_option (self, option);
state = gtk_widget_get_state_flags (GTK_WIDGET (button));
return (state & GTK_STATE_FLAG_INSENSITIVE) != GTK_STATE_FLAG_INSENSITIVE;
}
/**
* gcr_unlock_options_widget_set_sensitive:
* @self: The unlock options widget
* @option: The option name
* @sensitive: The sensitivity state.
* @reason: A user displayable string which contains the reason for the sensitivity.
*
* Set the sensitivity state for one of the options. Use an option name like
* %GCR_UNLOCK_OPTION_ALWAYS. The reason will be displayed as a tooltip.
*/
void
gcr_unlock_options_widget_set_sensitive (GcrUnlockOptionsWidget *self, const gchar *option,
gboolean sensitive, const gchar *reason)
{
GtkToggleButton *button;
g_return_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self));
g_return_if_fail (option);
button = widget_button_for_option (self, option);
gtk_widget_set_sensitive (GTK_WIDGET (button), sensitive);
if (!sensitive && reason)
gtk_widget_set_tooltip_text (GTK_WIDGET (button), reason);
else if (sensitive)
gtk_widget_set_has_tooltip (GTK_WIDGET (button), FALSE);
}