gnome-control-center/panels/universal-access/cc-ua-panel.c
Bastien Nocera 6c3daeaac4 universal-access: Fix possible crash when exiting panel
The gnome-settings-daemon mouse settings (double-click delay) and repeat
keys settings were both missing destroying their GSettings, meaning that
we could crash if the setting changed outside the panel, or when coming
and going to the panel.

https://bugzilla.gnome.org/show_bug.cgi?id=793322
2018-02-09 17:01:36 +01:00

1030 lines
34 KiB
C

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2010 Intel, Inc
* Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
*
* 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 2 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: Thomas Wood <thomas.wood@intel.com>
* Rodrigo Moya <rodrigo@gnome.org>
*
*/
#include <config.h>
#include <math.h>
#include <glib/gi18n-lib.h>
#include <gdesktop-enums.h>
#include "shell/list-box-helper.h"
#include "cc-ua-panel.h"
#include "cc-ua-resources.h"
#include "zoom-options.h"
#define WID(w) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, w))
#define DPI_FACTOR_LARGE 1.25
#define DPI_FACTOR_NORMAL 1.0
#define HIGH_CONTRAST_THEME "HighContrast"
/* shell settings */
#define A11Y_SETTINGS "org.gnome.desktop.a11y"
#define KEY_ALWAYS_SHOW_STATUS "always-show-universal-access-status"
/* interface settings */
#define INTERFACE_SETTINGS "org.gnome.desktop.interface"
#define KEY_TEXT_SCALING_FACTOR "text-scaling-factor"
#define KEY_GTK_THEME "gtk-theme"
#define KEY_ICON_THEME "icon-theme"
#define KEY_CURSOR_BLINKING "cursor-blink"
#define KEY_CURSOR_BLINKING_TIME "cursor-blink-time"
#define KEY_MOUSE_CURSOR_SIZE "cursor-size"
/* application settings */
#define APPLICATION_SETTINGS "org.gnome.desktop.a11y.applications"
#define KEY_SCREEN_KEYBOARD_ENABLED "screen-keyboard-enabled"
#define KEY_SCREEN_MAGNIFIER_ENABLED "screen-magnifier-enabled"
#define KEY_SCREEN_READER_ENABLED "screen-reader-enabled"
/* wm settings */
#define WM_SETTINGS "org.gnome.desktop.wm.preferences"
#define KEY_VISUAL_BELL_ENABLED "visual-bell"
#define KEY_VISUAL_BELL_TYPE "visual-bell-type"
#define KEY_WM_THEME "theme"
/* keyboard settings */
#define KEYBOARD_SETTINGS "org.gnome.desktop.a11y.keyboard"
#define KEY_KEYBOARD_TOGGLE "enable"
#define KEY_STICKYKEYS_ENABLED "stickykeys-enable"
#define KEY_STICKYKEYS_TWO_KEY_OFF "stickykeys-two-key-off"
#define KEY_STICKYKEYS_MODIFIER_BEEP "stickykeys-modifier-beep"
#define KEY_SLOWKEYS_ENABLED "slowkeys-enable"
#define KEY_SLOWKEYS_DELAY "slowkeys-delay"
#define KEY_SLOWKEYS_BEEP_PRESS "slowkeys-beep-press"
#define KEY_SLOWKEYS_BEEP_ACCEPT "slowkeys-beep-accept"
#define KEY_SLOWKEYS_BEEP_REJECT "slowkeys-beep-reject"
#define KEY_BOUNCEKEYS_ENABLED "bouncekeys-enable"
#define KEY_BOUNCEKEYS_DELAY "bouncekeys-delay"
#define KEY_BOUNCEKEYS_BEEP_REJECT "bouncekeys-beep-reject"
#define KEY_MOUSEKEYS_ENABLED "mousekeys-enable"
#define KEY_TOGGLEKEYS_ENABLED "togglekeys-enable"
/* keyboard desktop settings */
#define KEYBOARD_DESKTOP_SETTINGS "org.gnome.desktop.peripherals.keyboard"
#define KEY_REPEAT_KEYS "repeat"
/* mouse settings */
#define MOUSE_SETTINGS "org.gnome.desktop.a11y.mouse"
#define KEY_SECONDARY_CLICK_ENABLED "secondary-click-enabled"
#define KEY_SECONDARY_CLICK_TIME "secondary-click-time"
#define KEY_DWELL_CLICK_ENABLED "dwell-click-enabled"
#define KEY_DWELL_TIME "dwell-time"
#define KEY_DWELL_THRESHOLD "dwell-threshold"
/* gnome-settings-daemon settings */
#define GSD_MOUSE_SETTINGS "org.gnome.settings-daemon.peripherals.mouse"
#define KEY_DOUBLE_CLICK_DELAY "double-click"
#define SCROLL_HEIGHT 490
CC_PANEL_REGISTER (CcUaPanel, cc_ua_panel)
struct _CcUaPanelPrivate
{
GtkBuilder *builder;
GSettings *wm_settings;
GSettings *a11y_settings;
GSettings *interface_settings;
GSettings *kb_settings;
GSettings *mouse_settings;
GSettings *kb_desktop_settings;
GSettings *application_settings;
GSettings *gsd_mouse_settings;
ZoomOptions *zoom_options;
GtkAdjustment *focus_adjustment;
GList *sections;
GList *sections_reverse;
GSList *toplevels;
};
static void
cc_ua_panel_dispose (GObject *object)
{
CcUaPanelPrivate *priv = CC_UA_PANEL (object)->priv;
g_clear_object (&priv->builder);
g_slist_free_full (priv->toplevels, (GDestroyNotify)gtk_widget_destroy);
priv->toplevels = NULL;
g_clear_object (&priv->wm_settings);
g_clear_object (&priv->a11y_settings);
g_clear_object (&priv->interface_settings);
g_clear_object (&priv->kb_settings);
g_clear_object (&priv->mouse_settings);
g_clear_object (&priv->kb_desktop_settings);
g_clear_object (&priv->application_settings);
g_clear_object (&priv->gsd_mouse_settings);
g_clear_object (&priv->zoom_options);
g_clear_pointer (&priv->sections, g_list_free);
g_clear_pointer (&priv->sections_reverse, g_list_free);
G_OBJECT_CLASS (cc_ua_panel_parent_class)->dispose (object);
}
static const char *
cc_ua_panel_get_help_uri (CcPanel *panel)
{
return "help:gnome-help/a11y";
}
static void
cc_ua_panel_class_init (CcUaPanelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
g_type_class_add_private (klass, sizeof (CcUaPanelPrivate));
panel_class->get_help_uri = cc_ua_panel_get_help_uri;
object_class->dispose = cc_ua_panel_dispose;
}
/* zoom options dialog */
static void
zoom_options_launch (CcUaPanel *self)
{
if (self->priv->zoom_options == NULL)
self->priv->zoom_options = zoom_options_new ();
if (self->priv->zoom_options != NULL)
zoom_options_set_parent (self->priv->zoom_options,
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))));
}
/* cursor size dialog */
static void
cursor_size_toggled (GtkWidget *button,
CcUaPanel *self)
{
CcUaPanelPrivate *priv = self->priv;
guint cursor_size;
if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
return;
cursor_size = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (button), "cursor-size"));
g_settings_set_int (priv->interface_settings, KEY_MOUSE_CURSOR_SIZE, cursor_size);
g_debug ("Setting cursor size to %d", cursor_size);
}
static void
cursor_size_setup (CcUaPanel *self)
{
guint cursor_sizes[] = { 24, 32, 48, 64, 96 };
guint current_cursor_size, i;
CcUaPanelPrivate *priv = self->priv;
GtkWidget *grid;
GtkSizeGroup *size_group;
GtkWidget *last_radio_button = NULL;
grid = WID ("cursor_size_grid");
gtk_style_context_add_class (gtk_widget_get_style_context (grid), "linked");
current_cursor_size = g_settings_get_int (priv->interface_settings,
KEY_MOUSE_CURSOR_SIZE);
size_group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
for (i = 0; i < G_N_ELEMENTS(cursor_sizes); i++)
{
GtkWidget *image, *button;
char *cursor_image_name;
cursor_image_name = g_strdup_printf ("/org/gnome/control-center/universal-access/left_ptr_%dpx.png", cursor_sizes[i]);
image = gtk_image_new_from_resource (cursor_image_name);
g_free (cursor_image_name);
button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (last_radio_button));
last_radio_button = button;
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
g_object_set_data (G_OBJECT (button), "cursor-size", GUINT_TO_POINTER (cursor_sizes[i]));
gtk_container_add (GTK_CONTAINER (button), image);
gtk_grid_attach (GTK_GRID (grid), button, i, 0, 1, 1);
gtk_size_group_add_widget (size_group, button);
g_signal_connect (button, "toggled",
G_CALLBACK (cursor_size_toggled), self);
if (current_cursor_size == cursor_sizes[i])
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
}
gtk_widget_show_all (grid);
}
/* seeing section */
static gboolean
is_large_factor (gdouble factor)
{
return (factor > DPI_FACTOR_NORMAL);
}
static gboolean
get_large_text_mapping (GValue *value,
GVariant *variant,
gpointer user_data)
{
gdouble factor;
factor = g_variant_get_double (variant);
g_value_set_boolean (value, is_large_factor (factor));
return TRUE;
}
static GVariant *
set_large_text_mapping (const GValue *value,
const GVariantType *expected_type,
gpointer user_data)
{
gboolean large;
GSettings *settings = user_data;
GVariant *ret = NULL;
large = g_value_get_boolean (value);
if (large)
ret = g_variant_new_double (DPI_FACTOR_LARGE);
else
g_settings_reset (settings, KEY_TEXT_SCALING_FACTOR);
return ret;
}
static gboolean
get_contrast_mapping (GValue *value,
GVariant *variant,
gpointer user_data)
{
const char *theme;
gboolean hc;
theme = g_variant_get_string (variant, NULL);
hc = (g_strcmp0 (theme, HIGH_CONTRAST_THEME) == 0);
g_value_set_boolean (value, hc);
return TRUE;
}
static GVariant *
set_contrast_mapping (const GValue *value,
const GVariantType *expected_type,
gpointer user_data)
{
gboolean hc;
CcUaPanel *self = user_data;
CcUaPanelPrivate *priv = self->priv;
GVariant *ret = NULL;
hc = g_value_get_boolean (value);
if (hc)
{
ret = g_variant_new_string (HIGH_CONTRAST_THEME);
g_settings_set_string (priv->interface_settings, KEY_ICON_THEME, HIGH_CONTRAST_THEME);
g_settings_set_string (priv->wm_settings, KEY_WM_THEME, HIGH_CONTRAST_THEME);
}
else
{
g_settings_reset (priv->interface_settings, KEY_GTK_THEME);
g_settings_reset (priv->interface_settings, KEY_ICON_THEME);
g_settings_reset (priv->wm_settings, KEY_WM_THEME);
}
return ret;
}
static gboolean
on_off_label_mapping_get (GValue *value,
GVariant *variant,
gpointer user_data)
{
g_value_set_string (value, g_variant_get_boolean (variant) ? _("On") : _("Off"));
return TRUE;
}
static gboolean
cursor_size_label_mapping_get (GValue *value,
GVariant *variant,
gpointer user_data)
{
char *label;
int cursor_size;
cursor_size = g_variant_get_int32 (variant);
switch (cursor_size)
{
case 24:
/* translators: the labels will read:
* Cursor Size: Default */
label = g_strdup (C_("cursor size", "Default"));
break;
case 32:
label = g_strdup (C_("cursor size", "Medium"));
break;
case 48:
label = g_strdup (C_("cursor size", "Large"));
break;
case 64:
label = g_strdup (C_("cursor size", "Larger"));
break;
case 96:
label = g_strdup (C_("cursor size", "Largest"));
break;
default:
label = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE,
"%d pixel",
"%d pixels",
cursor_size),
cursor_size);
break;
}
g_value_take_string (value, label);
return TRUE;
}
static void
add_separators (GtkListBox *list)
{
gtk_list_box_set_header_func (list, cc_list_box_update_header_func, NULL, NULL);
}
static gboolean
keynav_failed (GtkWidget *list, GtkDirectionType direction, CcUaPanel *self)
{
CcUaPanelPrivate *priv = self->priv;
GList *item, *sections;
gdouble value, lower, upper, page;
/* Find the list in the list of GtkListBoxes */
if (direction == GTK_DIR_DOWN)
sections = priv->sections;
else
sections = priv->sections_reverse;
item = g_list_find (sections, list);
g_assert (item);
if (item->next)
{
gtk_widget_child_focus (GTK_WIDGET (item->next->data), direction);
return TRUE;
}
value = gtk_adjustment_get_value (priv->focus_adjustment);
lower = gtk_adjustment_get_lower (priv->focus_adjustment);
upper = gtk_adjustment_get_upper (priv->focus_adjustment);
page = gtk_adjustment_get_page_size (priv->focus_adjustment);
if (direction == GTK_DIR_UP && value > lower)
{
gtk_adjustment_set_value (priv->focus_adjustment, lower);
return TRUE;
}
else if (direction == GTK_DIR_DOWN && value < upper - page)
{
gtk_adjustment_set_value (priv->focus_adjustment, upper - page);
return TRUE;
}
return FALSE;
}
static void
add_section (GtkWidget *list, CcUaPanel *self)
{
CcUaPanelPrivate *priv = self->priv;
g_signal_connect (list, "keynav-failed", G_CALLBACK (keynav_failed), self);
priv->sections = g_list_append (priv->sections, list);
priv->sections_reverse = g_list_prepend (priv->sections_reverse, list);
}
static void
cc_ua_panel_init_status (CcUaPanel *self)
{
CcUaPanelPrivate *priv = self->priv;
GtkWidget *box;
box = GTK_WIDGET (gtk_builder_get_object (priv->builder, "section_status"));
priv->sections_reverse = g_list_prepend (priv->sections_reverse, box);
g_settings_bind (priv->a11y_settings, KEY_ALWAYS_SHOW_STATUS,
WID ("switch_status"), "active",
G_SETTINGS_BIND_DEFAULT);
}
static void
toggle_switch (GtkWidget *sw)
{
gboolean active;
active = gtk_switch_get_active (GTK_SWITCH (sw));
gtk_switch_set_active (GTK_SWITCH (sw), !active);
}
static void
activate_row (CcUaPanel *self, GtkListBoxRow *row)
{
GtkWidget *dialog;
const gchar *dialog_id;
const gchar *widget_name;
/* Check switches to toggle */
widget_name = gtk_buildable_get_name (GTK_BUILDABLE (row));
if (widget_name)
{
if (!g_strcmp0 (widget_name, "row_highcontrast"))
{
toggle_switch (WID ("value_highcontrast"));
return;
}
if (!g_strcmp0 (widget_name, "row_large_text"))
{
toggle_switch (WID ("value_large_text"));
return;
}
if (!g_strcmp0 (widget_name, "row_screen_keyboard"))
{
toggle_switch (WID ("screen_keyboard_switch"));
return;
}
if (!g_strcmp0 (widget_name, "row_mouse_keys"))
{
toggle_switch (WID ("mouse_keys_switch"));
return;
}
}
/* Check dialog to open */
dialog_id = (const gchar *)g_object_get_data (G_OBJECT (row), "dialog-id");
if (g_strcmp0 (dialog_id, "zoom") == 0)
{
zoom_options_launch (self);
return;
}
dialog = (GtkWidget *)g_object_get_data (G_OBJECT (row), "dialog");
if (dialog == NULL)
return;
gtk_window_set_transient_for (GTK_WINDOW (dialog),
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))));
gtk_window_present (GTK_WINDOW (dialog));
}
static void
cc_ua_panel_init_seeing (CcUaPanel *self)
{
CcUaPanelPrivate *priv = self->priv;
GtkWidget *list;
GtkWidget *dialog;
list = WID ("list_seeing");
add_section (list, self);
add_separators (GTK_LIST_BOX (list));
g_signal_connect_swapped (list, "row-activated",
G_CALLBACK (activate_row), self);
g_settings_bind_with_mapping (priv->interface_settings, KEY_GTK_THEME,
WID ("value_highcontrast"),
"active", G_SETTINGS_BIND_DEFAULT,
get_contrast_mapping,
set_contrast_mapping,
self,
NULL);
/* large text */
g_settings_bind_with_mapping (priv->interface_settings, KEY_TEXT_SCALING_FACTOR,
WID ("value_large_text"),
"active", G_SETTINGS_BIND_DEFAULT,
get_large_text_mapping,
set_large_text_mapping,
priv->interface_settings,
NULL);
/* cursor size */
cursor_size_setup (self);
g_settings_bind_with_mapping (priv->interface_settings, KEY_MOUSE_CURSOR_SIZE,
WID ("value_cursor_size"),
"label", G_SETTINGS_BIND_GET,
cursor_size_label_mapping_get,
NULL, NULL, NULL);
dialog = WID ("cursor_size_dialog");
priv->toplevels = g_slist_prepend (priv->toplevels, dialog);
g_object_set_data (G_OBJECT (WID ("row_cursor_size")), "dialog", dialog);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
/* zoom */
g_settings_bind_with_mapping (priv->application_settings, "screen-magnifier-enabled",
WID ("value_zoom"),
"label", G_SETTINGS_BIND_GET,
on_off_label_mapping_get,
NULL, NULL, NULL);
g_object_set_data (G_OBJECT (WID ("row_zoom")), "dialog-id", "zoom");
/* screen reader */
g_settings_bind_with_mapping (priv->application_settings, "screen-reader-enabled",
WID ("value_screen_reader"), "label",
G_SETTINGS_BIND_GET,
on_off_label_mapping_get,
NULL, NULL, NULL);
g_settings_bind (priv->application_settings, "screen-reader-enabled",
WID ("screen_reader_switch"), "active",
G_SETTINGS_BIND_DEFAULT);
dialog = WID ("screen_reader_dialog");
priv->toplevels = g_slist_prepend (priv->toplevels, dialog);
g_object_set_data (G_OBJECT (WID ("row_screen_reader")), "dialog", dialog);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
/* sound keys */
g_settings_bind_with_mapping (priv->kb_settings, KEY_TOGGLEKEYS_ENABLED,
WID ("value_sound_keys"), "label",
G_SETTINGS_BIND_GET,
on_off_label_mapping_get,
NULL, NULL, NULL);
g_settings_bind (priv->kb_settings, KEY_TOGGLEKEYS_ENABLED,
WID ("sound_keys_switch"), "active",
G_SETTINGS_BIND_DEFAULT);
dialog = WID ("sound_keys_dialog");
priv->toplevels = g_slist_prepend (priv->toplevels, dialog);
g_object_set_data (G_OBJECT (WID ("row_sound_keys")), "dialog", dialog);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
}
/* hearing/sound section */
static void
visual_bell_type_notify_cb (GSettings *settings,
const gchar *key,
CcUaPanel *self)
{
GtkWidget *widget;
GDesktopVisualBellType type;
type = g_settings_get_enum (self->priv->wm_settings, KEY_VISUAL_BELL_TYPE);
if (type == G_DESKTOP_VISUAL_BELL_FRAME_FLASH)
widget = WID ("visual_alerts_window_radio");
else
widget = WID ("visual_alerts_screen_radio");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
}
static void
visual_bell_type_toggle_cb (GtkWidget *button,
CcUaPanel *panel)
{
gboolean frame_flash;
GDesktopVisualBellType type;
frame_flash = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
if (frame_flash)
type = G_DESKTOP_VISUAL_BELL_FRAME_FLASH;
else
type = G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH;
g_settings_set_enum (panel->priv->wm_settings, KEY_VISUAL_BELL_TYPE, type);
}
static void
test_flash (GtkButton *button,
gpointer data)
{
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
gdk_window_beep (gtk_widget_get_window (toplevel));
}
static void
cc_ua_panel_init_hearing (CcUaPanel *self)
{
CcUaPanelPrivate *priv = self->priv;
GtkWidget *list;
GtkWidget *dialog;
list = WID ("list_hearing");
add_section (list, self);
add_separators (GTK_LIST_BOX (list));
g_signal_connect_swapped (list, "row-activated",
G_CALLBACK (activate_row), self);
/* set the initial visual bell values */
visual_bell_type_notify_cb (NULL, NULL, self);
/* and listen */
g_settings_bind (priv->wm_settings, KEY_VISUAL_BELL_ENABLED,
WID ("visual_alerts_switch"), "active",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind_with_mapping (priv->wm_settings, KEY_VISUAL_BELL_ENABLED,
WID ("value_visual_alerts"),
"label", G_SETTINGS_BIND_GET,
on_off_label_mapping_get,
NULL, NULL, NULL);
g_object_bind_property (WID ("visual_alerts_switch"), "active",
WID ("visual_alerts_window_radio"), "sensitive",
G_BINDING_SYNC_CREATE);
g_object_bind_property (WID ("visual_alerts_switch"), "active",
WID ("visual_alerts_screen_radio"), "sensitive",
G_BINDING_SYNC_CREATE);
g_signal_connect (priv->wm_settings, "changed::" KEY_VISUAL_BELL_TYPE,
G_CALLBACK (visual_bell_type_notify_cb), self);
g_signal_connect (WID ("visual_alerts_window_radio"),
"toggled", G_CALLBACK (visual_bell_type_toggle_cb), self);
dialog = WID ("visual_alerts_dialog");
priv->toplevels = g_slist_prepend (priv->toplevels, dialog);
g_object_set_data (G_OBJECT (WID ("row_visual_alerts")), "dialog", dialog);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
g_signal_connect (WID ("visual_alerts_test_button"),
"clicked", G_CALLBACK (test_flash), NULL);
}
/* typing/keyboard section */
static void
on_repeat_keys_toggled (GSettings *settings, const gchar *key, CcUaPanel *self)
{
gboolean on;
on = g_settings_get_boolean (settings, KEY_REPEAT_KEYS);
gtk_label_set_text (GTK_LABEL (WID ("value_repeat_keys")), on ? _("On") : _("Off"));
gtk_widget_set_sensitive (WID ("repeat-keys-delay-grid"), on);
gtk_widget_set_sensitive (WID ("repeat-keys-speed-grid"), on);
}
static void
on_cursor_blinking_toggled (GSettings *settings, const gchar *key, CcUaPanel *self)
{
gboolean on;
on = g_settings_get_boolean (settings, KEY_CURSOR_BLINKING);
gtk_label_set_text (GTK_LABEL (WID ("value_row_cursor_blinking")), on ? _("On") : _("Off"));
}
static void
update_accessx_label (GSettings *settings, const gchar *key, CcUaPanel *self)
{
gboolean on;
on = g_settings_get_boolean (settings, KEY_STICKYKEYS_ENABLED) ||
g_settings_get_boolean (settings, KEY_SLOWKEYS_ENABLED) ||
g_settings_get_boolean (settings, KEY_BOUNCEKEYS_ENABLED);
gtk_label_set_text (GTK_LABEL (WID ("value_accessx")), on ? _("On") : _("Off"));
}
static void
cc_ua_panel_init_keyboard (CcUaPanel *self)
{
CcUaPanelPrivate *priv = self->priv;
GtkWidget *list;
GtkWidget *w;
GtkWidget *sw;
GtkWidget *dialog;
list = WID ("list_typing");
add_section (list, self);
add_separators (GTK_LIST_BOX (list));
g_signal_connect_swapped (list, "row-activated",
G_CALLBACK (activate_row), self);
/* on-screen keyboard */
sw = WID ("screen_keyboard_switch");
g_settings_bind (priv->application_settings, KEY_SCREEN_KEYBOARD_ENABLED,
sw, "active",
G_SETTINGS_BIND_DEFAULT);
/* Repeat keys */
g_signal_connect (priv->kb_desktop_settings, "changed",
G_CALLBACK (on_repeat_keys_toggled), self);
dialog = WID ("repeat_keys_dialog");
priv->toplevels = g_slist_prepend (priv->toplevels, dialog);
g_object_set_data (G_OBJECT (WID ("row_repeat_keys")), "dialog", dialog);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
sw = WID ("repeat_keys_switch");
g_settings_bind (priv->kb_desktop_settings, KEY_REPEAT_KEYS,
sw, "active",
G_SETTINGS_BIND_DEFAULT);
on_repeat_keys_toggled (priv->kb_desktop_settings, NULL, self);
g_settings_bind (priv->kb_desktop_settings, "delay",
gtk_range_get_adjustment (GTK_RANGE (WID ("repeat_keys_delay_scale"))), "value",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (priv->kb_desktop_settings, "repeat-interval",
gtk_range_get_adjustment (GTK_RANGE (WID ("repeat_keys_speed_scale"))), "value",
G_SETTINGS_BIND_DEFAULT);
/* Cursor Blinking */
g_signal_connect (priv->interface_settings, "changed",
G_CALLBACK (on_cursor_blinking_toggled), self);
dialog = WID ("cursor_blinking_dialog");
priv->toplevels = g_slist_prepend (priv->toplevels, dialog);
g_object_set_data (G_OBJECT (WID ("row_cursor_blinking")), "dialog", dialog);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
sw = WID ("cursor_blinking_switch");
g_settings_bind (priv->interface_settings, KEY_CURSOR_BLINKING,
sw, "active",
G_SETTINGS_BIND_DEFAULT);
on_cursor_blinking_toggled (priv->interface_settings, NULL, self);
g_settings_bind (priv->interface_settings, KEY_CURSOR_BLINKING_TIME,
gtk_range_get_adjustment (GTK_RANGE (WID ("cursor_blinking_scale"))), "value",
G_SETTINGS_BIND_DEFAULT);
/* accessx */
g_signal_connect (priv->kb_settings, "changed",
G_CALLBACK (update_accessx_label), self);
update_accessx_label (priv->kb_settings, NULL, self);
/* enable shortcuts */
sw = WID ("typing_keyboard_toggle_switch");
g_settings_bind (priv->kb_settings, KEY_KEYBOARD_TOGGLE,
sw, "active",
G_SETTINGS_BIND_DEFAULT);
/* sticky keys */
sw = WID ("typing_stickykeys_switch");
g_settings_bind (priv->kb_settings, KEY_STICKYKEYS_ENABLED,
sw, "active",
G_SETTINGS_BIND_DEFAULT);
w = WID ("typing_stickykeys_disable_two_keys_check");
g_settings_bind (priv->kb_settings, KEY_STICKYKEYS_TWO_KEY_OFF,
w, "active",
G_SETTINGS_BIND_NO_SENSITIVITY);
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
w = WID ("typing_stickykeys_beep_modifier_check");
g_settings_bind (priv->kb_settings, KEY_STICKYKEYS_MODIFIER_BEEP,
w, "active",
G_SETTINGS_BIND_NO_SENSITIVITY);
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
/* slow keys */
sw = WID ("typing_slowkeys_switch");
g_settings_bind (priv->kb_settings, KEY_SLOWKEYS_ENABLED,
sw, "active",
G_SETTINGS_BIND_DEFAULT);
w = WID ("typing_slowkeys_delay_scale");
g_settings_bind (priv->kb_settings, KEY_SLOWKEYS_DELAY,
gtk_range_get_adjustment (GTK_RANGE (w)), "value",
G_SETTINGS_BIND_DEFAULT);
w = WID ("typing_slowkeys_delay_box");
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
w = WID ("typing_slowkeys_beep_pressed_check");
g_settings_bind (priv->kb_settings, KEY_SLOWKEYS_BEEP_PRESS,
w, "active",
G_SETTINGS_BIND_DEFAULT);
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
w = WID ("typing_slowkeys_beep_accepted_check");
g_settings_bind (priv->kb_settings, KEY_SLOWKEYS_BEEP_ACCEPT,
w, "active",
G_SETTINGS_BIND_DEFAULT);
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
w = WID ("typing_slowkeys_beep_rejected_check");
g_settings_bind (priv->kb_settings, KEY_SLOWKEYS_BEEP_REJECT,
w, "active",
G_SETTINGS_BIND_DEFAULT);
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
/* bounce keys */
sw = WID ("typing_bouncekeys_switch");
g_settings_bind (priv->kb_settings, KEY_BOUNCEKEYS_ENABLED,
sw, "active",
G_SETTINGS_BIND_DEFAULT);
w = WID ("typing_bouncekeys_delay_scale");
g_settings_bind (priv->kb_settings, KEY_BOUNCEKEYS_DELAY,
gtk_range_get_adjustment (GTK_RANGE (w)), "value",
G_SETTINGS_BIND_DEFAULT);
w = WID ("typing_bouncekeys_delay_box");
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
w = WID ("typing_bouncekeys_beep_rejected_check");
g_settings_bind (priv->kb_settings, KEY_BOUNCEKEYS_BEEP_REJECT,
w, "active",
G_SETTINGS_BIND_NO_SENSITIVITY);
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
dialog = WID ("typing_dialog");
priv->toplevels = g_slist_prepend (priv->toplevels, dialog);
g_object_set_data (G_OBJECT (WID ("row_accessx")), "dialog", dialog);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
}
/* mouse/pointing & clicking section */
static void
update_click_assist_label (GSettings *settings, const gchar *key, CcUaPanel *self)
{
gboolean on;
on = g_settings_get_boolean (settings, KEY_SECONDARY_CLICK_ENABLED) ||
g_settings_get_boolean (settings, KEY_DWELL_CLICK_ENABLED);
gtk_label_set_text (GTK_LABEL (WID ("value_click_assist")), on ? _("On") : _("Off"));
}
static void
cc_ua_panel_init_mouse (CcUaPanel *self)
{
CcUaPanelPrivate *priv = self->priv;
GtkWidget *list;
GtkWidget *dialog;
GtkWidget *sw;
GtkWidget *w;
list = WID ("list_pointing");
add_section (list, self);
add_separators (GTK_LIST_BOX (list));
g_signal_connect_swapped (list, "row-activated",
G_CALLBACK (activate_row), self);
g_settings_bind (priv->kb_settings, KEY_MOUSEKEYS_ENABLED,
WID ("mouse_keys_switch"), "active",
G_SETTINGS_BIND_DEFAULT);
g_signal_connect (priv->mouse_settings, "changed",
G_CALLBACK (update_click_assist_label), self);
update_click_assist_label (priv->mouse_settings, NULL, self);
/* simulated secondary click */
sw = WID ("pointing_secondary_click_switch");
g_settings_bind (priv->mouse_settings, KEY_SECONDARY_CLICK_ENABLED,
sw, "active",
G_SETTINGS_BIND_DEFAULT);
w = WID ("pointing_secondary_click_delay_scale");
g_settings_bind (priv->mouse_settings, KEY_SECONDARY_CLICK_TIME,
gtk_range_get_adjustment (GTK_RANGE (w)), "value",
G_SETTINGS_BIND_DEFAULT);
w = WID ("pointing_secondary_click_delay_box");
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
/* dwell click */
sw = WID ("pointing_hover_click_switch");
g_settings_bind (priv->mouse_settings, KEY_DWELL_CLICK_ENABLED,
sw, "active",
G_SETTINGS_BIND_DEFAULT);
w = WID ("pointing_dwell_delay_scale");
g_settings_bind (priv->mouse_settings, KEY_DWELL_TIME,
gtk_range_get_adjustment (GTK_RANGE (w)), "value",
G_SETTINGS_BIND_DEFAULT);
w = WID ("pointing_dwell_delay_box");
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
w = WID ("pointing_dwell_threshold_scale");
g_settings_bind (priv->mouse_settings, KEY_DWELL_THRESHOLD,
gtk_range_get_adjustment (GTK_RANGE (w)), "value",
G_SETTINGS_BIND_DEFAULT);
w = WID ("pointing_dwell_threshold_box");
g_object_bind_property (sw, "active", w, "sensitive", G_BINDING_SYNC_CREATE);
dialog = WID ("pointing_dialog");
priv->toplevels = g_slist_prepend (priv->toplevels, dialog);
g_object_set_data (G_OBJECT (WID ("row_click_assist")), "dialog", dialog);
g_settings_bind (priv->gsd_mouse_settings, "double-click",
gtk_range_get_adjustment (GTK_RANGE (WID ("scale_double_click_delay"))), "value",
G_SETTINGS_BIND_DEFAULT);
gtk_scale_add_mark (GTK_SCALE (WID ("scale_double_click_delay")), 400, GTK_POS_BOTTOM, NULL);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
}
static void
cc_ua_panel_init (CcUaPanel *self)
{
CcUaPanelPrivate *priv;
GtkWidget *panel;
GtkWidget *content;
priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
CC_TYPE_UA_PANEL,
CcUaPanelPrivate);
g_resources_register (cc_universal_access_get_resource ());
priv->interface_settings = g_settings_new (INTERFACE_SETTINGS);
priv->a11y_settings = g_settings_new (A11Y_SETTINGS);
priv->wm_settings = g_settings_new (WM_SETTINGS);
priv->kb_settings = g_settings_new (KEYBOARD_SETTINGS);
priv->kb_desktop_settings = g_settings_new (KEYBOARD_DESKTOP_SETTINGS);
priv->mouse_settings = g_settings_new (MOUSE_SETTINGS);
priv->gsd_mouse_settings = g_settings_new (GSD_MOUSE_SETTINGS);
priv->application_settings = g_settings_new (APPLICATION_SETTINGS);
priv->builder = gtk_builder_new ();
gtk_builder_add_from_resource (priv->builder,
"/org/gnome/control-center/universal-access/uap.ui",
NULL);
cc_ua_panel_init_status (self);
cc_ua_panel_init_seeing (self);
cc_ua_panel_init_hearing (self);
cc_ua_panel_init_keyboard (self);
cc_ua_panel_init_mouse (self);
panel = WID ("universal_access_panel");
content = WID ("universal_access_content");
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (panel), SCROLL_HEIGHT);
priv->focus_adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (panel));
gtk_container_set_focus_vadjustment (GTK_CONTAINER (content), priv->focus_adjustment);
gtk_container_add (GTK_CONTAINER (self), panel);
}