gnome-control-center/capplets/accessibility/keyboard/accessibility-keyboard.c
Jody Goldberg b4995826e8 http://bugzilla.gnome.org/show_bug.cgi?id=85397
2002-06-15  Jody Goldberg <jody@gnome.org>

	http://bugzilla.gnome.org/show_bug.cgi?id=85397
	http://bugzilla.gnome.org/show_bug.cgi?id=84545
	* mime-types-model.c (mime_types_model_get_value) :
	  gtk_tree_view_search_equal_func does not like NULL.
	(IS_CATEGORY) : check for NULL.
	* file-types-capplet.c (create_dialog) : search the description not
	  the mime type.

2002-06-08  Jody Goldberg <jody@gnome.org>

	* mime-types-model.c (IS_CATEGORY) : test for null in case we are
	  stupid.

2002-06-07  Jody Goldberg <jody@gnome.org>

	* file-types-capplet.c (dialog_done_cb) : no need to save things
	  again.  The only caller had already done that.

	* mime-type-info.c (mime_type_info_save) : Don't mess with the
	  application here, it should already be setup.  However, be really
	  really anal about verifying it because I do not trust the
	  surrounding code or know it well enough to trust it.  Make sure that
	  the assigned app is on the short list of associated apps.

	* mime-category-edit-dialog.c (store_data) : Use
	  mime_edit_dialog_get_app.
	* mime-edit-dialog.c (store_data) : Use it here too.
	(mime_edit_dialog_get_app) : new.  split some duplicated code out of
	  the type and category dialogs and move it here.  Then make it
	  readable and less stupid about creating copies of existing
	  applications.  While we're at it have it handle the creation of new
	  applications, merging commands with existing applications and other
	  useful stuff.

2002-06-07  Jody Goldberg <jody@gnome.org>

	* mime-category-edit-dialog.c (store_data) : clarify and remove the
	  custom flag.

	* mime-type-info.c (mime_category_info_using_custom_app) : delete.
	(mime_type_info_using_custom_app) : delete.

	* mime-edit-dialog.c (validate_data) : correct the warning about
	  invalid type, we would _not_ create one for the user :-(
	  Allow a user to optionally overwrite an existing mime type.
	  This is useful when editing.
	* mime-edit-dialog.c (store_data) : clarify and remove the custom flag.


2002-06-10  Jody Goldberg <jody@gnome.org>

	* accessibility-keyboard.c : tweak the layout as requested and adjust
	  the max slowkey delay to 500 to avoid losing the keyboard due to some
	  sort of an X problem.

2002-06-13  Jody Goldberg <jody@gnome.org>

	* gnome-keyboard-properties.c (accessibility_button_clicked) : produce
	  a better warning for failure to launch the keyboard accessibility
	  capplet.
2002-06-18 18:55:14 +00:00

463 lines
14 KiB
C

/* -*- mode: c; style: linux -*- */
/* accessibility-keyboard.c
* Copyright (C) 2002 Ximian, Inc.
*
* Written by: Jody Goldberg <jody@gnome.org>
*
* 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, 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.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gnome.h>
#include <gconf/gconf-client.h>
#include <glade/glade.h>
#include <X11/Xlib.h>
#include <X11/Xresource.h>
#include <math.h>
#include "capplet-util.h"
#include "gconf-property-editor.h"
#include "activate-settings-daemon.h"
#define IDIR GNOMECC_DATA_DIR "/pixmaps/"
#define CONFIG_ROOT "/desktop/gnome/accessibility/keyboard"
static struct {
char const * const checkbox;
char const * const image;
char const * const image_file;
char const * const gconf_key;
char const * const content [3];
} const features [] = {
{ "bouncekeys_enable", "bouncekeys_image", IDIR "accessibility-keyboard-bouncekey.png",
CONFIG_ROOT "/bouncekeys_enable",
{ "bouncekey_table", NULL, NULL } },
{ "slowkeys_enable", "slowkeys_image", IDIR "accessibility-keyboard-slowkey.png",
CONFIG_ROOT "/slowkeys_enable",
{ "slowkeys_table", NULL, NULL } },
{ "mousekeys_enable", "mousekeys_image", IDIR "accessibility-keyboard-mousekey.png",
CONFIG_ROOT "/mousekeys_enable",
{ "mousekeys_table", NULL, NULL } },
{ "stickykeys_enable", "stickykeys_image", IDIR "accessibility-keyboard-stickykey.png",
CONFIG_ROOT "/stickykeys_enable",
{ "stickeykeys_table", NULL, NULL } },
{ "togglekeys_enable", "togglekeys_image", IDIR "accessibility-keyboard-togglekey.png",
CONFIG_ROOT "/togglekeys_enable",
{ NULL, NULL, NULL } },
{ "timeout_enable", NULL, NULL,
CONFIG_ROOT "/timeout_enable",
{ "timeout_slide", "timeout_spin", "timeout_label" } }
};
static struct {
char const * const slide;
char const * const spin;
int default_val;
int min_val;
int max_val;
int step_size;
char const * const gconf_key;
} const ranges [] = {
{ "bouncekeys_delay_slide", "bouncekeys_delay_spin", 300, 10, 900, 10,
CONFIG_ROOT "/bouncekeys_delay" },
{ "slowkeys_delay_slide", "slowkeys_delay_spin", 300, 10, 900, 10,
CONFIG_ROOT "/slowkeys_delay" },
/* WARNING anything larger than approx 512 seems to loose all keyboard input */
{ "mousekeys_max_speed_slide", "mousekeys_max_speed_spin", 300, 10, 500, 20,
CONFIG_ROOT "/mousekeys_max_speed" },
{ "mousekeys_accel_time_slide", "mousekeys_accel_time_spin", 300, 10, 3000, 100,
CONFIG_ROOT "/mousekeys_accel_time" },
{ "mousekeys_init_delay_slide", "mousekeys_init_delay_spin", 300, 10, 5000, 100,
CONFIG_ROOT "/mousekeys_init_delay" },
{ "timeout_slide", "timeout_spin", 200, 10, 500, 10,
CONFIG_ROOT "/timeout" },
};
static void
set_sensitive (GladeXML *dialog, char const *name, gboolean state)
{
if (name != NULL)
gtk_widget_set_sensitive (WID (name), state);
}
/**
* cb_feature_toggled :
*
* NOTE : for this to work the toggle MUST be initialized to active in the
* glade file. That way if the gconf setting is FALSE the toggle will fire.
*/
static void
cb_feature_toggled (GtkToggleButton *btn, gpointer feature_index)
{
gboolean const state = gtk_toggle_button_get_active (btn);
GladeXML *dialog = g_object_get_data (G_OBJECT (btn), "dialog");
int feature, i;
g_return_if_fail (dialog != NULL);
feature = GPOINTER_TO_INT (feature_index);
if (features [feature].image != NULL)
set_sensitive (dialog, features [feature].image, state);
for (i = G_N_ELEMENTS (features [feature].content) ; i-- > 0 ; )
set_sensitive (dialog, features [feature].content [i], state);
}
static void
setup_toggles (GladeXML *dialog, GConfChangeSet *changeset)
{
GObject *peditor;
GtkWidget *checkbox;
int i = G_N_ELEMENTS (features);
while (i-- > 0) {
checkbox = WID (features [i].checkbox);
g_return_if_fail (checkbox != NULL);
g_object_set_data (G_OBJECT (checkbox), "dialog", dialog);
g_signal_connect (G_OBJECT (checkbox),
"toggled",
G_CALLBACK (cb_feature_toggled), GINT_TO_POINTER (i));
peditor = gconf_peditor_new_boolean (changeset,
(gchar *)features [i].gconf_key, checkbox, NULL);
}
}
static void
setup_simple_toggles (GladeXML *dialog, GConfChangeSet *changeset)
{
static struct {
char const *gconf_key;
char const *checkbox;
} const simple_toggles [] = {
{ CONFIG_ROOT "/feature_state_change_beep","feature_state_change_beep" },
{ CONFIG_ROOT "/bouncekeys_beep_reject", "bouncekeys_beep_reject" },
{ CONFIG_ROOT "/slowkeys_beep_press", "slowkeys_beep_press" },
{ CONFIG_ROOT "/slowkeys_beep_accept", "slowkeys_beep_accept" },
{ CONFIG_ROOT "/slowkeys_beep_reject", "slowkeys_beep_reject" },
{ CONFIG_ROOT "/stickykeys_two_key_off", "stickykeys_two_key_off" },
{ CONFIG_ROOT "/stickykeys_modifier_beep", "stickykeys_modifier_beep" },
};
int i = G_N_ELEMENTS (simple_toggles);
while (i-- > 0) {
GtkWidget *w = WID (simple_toggles [i].checkbox);
g_return_if_fail (w != NULL);
gconf_peditor_new_boolean (changeset,
(gchar *) simple_toggles [i].gconf_key,
w, NULL);
}
}
static GConfValue*
cb_to_widget (GConfPropertyEditor *peditor, const GConfValue *value)
{
return gconf_value_int_to_float (value);
}
static GConfValue*
cb_from_widget (GConfPropertyEditor *peditor, const GConfValue *value)
{
return gconf_value_float_to_int (value);
}
static void
setup_ranges (GladeXML *dialog, GConfChangeSet *changeset)
{
GObject *peditor;
GtkWidget *slide, *spin;
GtkAdjustment *adjustment;
int i = G_N_ELEMENTS (ranges);
while (i-- > 0) {
slide = WID (ranges [i].slide);
spin = WID (ranges [i].spin);
g_return_if_fail (slide != NULL);
g_return_if_fail (spin != NULL);
adjustment = gtk_range_get_adjustment (GTK_RANGE (slide));
g_return_if_fail (adjustment != NULL);
adjustment->value = ranges [i].default_val;
adjustment->lower = ranges [i].min_val;
adjustment->upper = ranges [i].max_val + ranges [i].step_size;
adjustment->step_increment = ranges [i].step_size;
adjustment->page_increment = ranges [i].step_size;
adjustment->page_size = ranges [i].step_size;
gtk_adjustment_changed (adjustment);
gtk_spin_button_configure (GTK_SPIN_BUTTON (spin), adjustment,
ranges [i].step_size, 0);
peditor = gconf_peditor_new_numeric_range (changeset,
(gchar *)ranges [i].gconf_key, slide,
"conv-to-widget-cb", cb_to_widget,
"conv-from-widget-cb", cb_from_widget,
NULL);
}
}
static void
setup_images (GladeXML *dialog)
{
int i = G_N_ELEMENTS (features);
while (i-- > 0)
if (features [i].image != NULL)
gtk_image_set_from_file (GTK_IMAGE (WID (features [i].image)),
features [i].image_file);
}
static void
cb_launch_keyboard_capplet (GtkButton *button, GtkWidget *dialog)
{
GError *err = NULL;
if (!g_spawn_command_line_async ("gnome-keyboard-properties", &err))
capplet_error_dialog (GTK_WINDOW (gtk_widget_get_toplevel (dialog)),
_("There was an error launching the keyboard capplet : %s"),
err);
}
static void
setup_dialog (GladeXML *dialog, GConfChangeSet *changeset)
{
setup_images (dialog);
setup_ranges (dialog, changeset);
setup_toggles (dialog, changeset);
setup_simple_toggles (dialog, changeset);
}
/*******************************************************************************/
static void
xrm_get_bool (GConfClient *client, XrmDatabase *db, char const *gconf_key,
char const *res_str, char const *class_str)
{
XrmValue resourceValue;
char *res;
if (XrmGetResource (*db, res_str, class_str, &res, &resourceValue))
gconf_client_set_bool (client, gconf_key,
!g_ascii_strcasecmp (resourceValue.addr, "True"), NULL);
}
static void
xrm_get_int (GConfClient *client, XrmDatabase *db, char const *gconf_key,
char const *res_str, char const *class_str)
{
XrmValue resourceValue;
char *res;
int value;
char resource [256];
snprintf (resource, sizeof (resource), "%s.value", res_str);
if (!XrmGetResource (*db, resource, class_str, &res, &resourceValue))
return;
value = atoi (resourceValue.addr);
#if 0
{
int decimal;
snprintf (resource, sizeof (resource), "%s.decimalPoints", res_str);
if (!XrmGetResource (*db, resource, class_str, &res, &resourceValue))
return;
decimal = atoi (resourceValue.addr);
}
#endif
gconf_client_set_int (client, gconf_key, value, NULL);
}
/* This loads the current users XKB settings from their file */
static gboolean
load_CDE_file (GtkFileSelection *fsel)
{
char const *file = gtk_file_selection_get_filename (fsel);
GConfClient *client;
XrmDatabase db;
if (!(db = XrmGetFileDatabase (file))) {
GtkWidget *warn = gtk_message_dialog_new (
gtk_window_get_transient_for (GTK_WINDOW (fsel)),
GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
_("Unable to import AccessX settings from file '%s'"),
file);
g_signal_connect (warn,
"response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (warn);
return FALSE;
}
client = gconf_client_get_default ();
xrm_get_bool (client, &db, CONFIG_ROOT "/enable",
"*EnableAccessXToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/feature_state_change_beep",
"*SoundOnOffToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/timeout_enable",
"*TimeOutToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/stickykeys_enable",
"*StickyKeysToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/mousekeys_enable",
"*MouseKeysToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/togglekeys_enable",
"*ToggleKeysToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/slowkeys_enable",
"*SlowKeysToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/bouncekeys_enable",
"*BounceKeysToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/stickykeys_modifier_beep",
"*StickyModSoundToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/stickykeys_two_key_off",
"*StickyTwoKeysToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/slowkeys_beep_press",
"*SlowKeysOnPressToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_bool (client, &db, CONFIG_ROOT "/slowkeys_beep_accept",
"*SlowKeysOnAcceptToggle.set", "AccessX*ToggleButtonGadget.XmCSet");
xrm_get_int (client, &db, CONFIG_ROOT "/timeout",
"*TimeOutScale", "AccessX*XmScale");
xrm_get_int (client, &db, CONFIG_ROOT "/mousekeys_max_speed",
"*MouseMaxSpeedScale", "AccessX*XmScale");
xrm_get_int (client, &db, CONFIG_ROOT "/mousekeys_accel_time",
"*MouseAccelScale", "AccessX*XmScale");
xrm_get_int (client, &db, CONFIG_ROOT "/mousekeys_init_delay",
"*MouseDelayScale", "AccessX*XmScale");
xrm_get_int (client, &db, CONFIG_ROOT "/slowkeys_delay",
"*KRGSlowKeysDelayScale", "AccessX*XmScale");
xrm_get_int (client, &db, CONFIG_ROOT "/bouncekeys_delay",
"*KRGDebounceScale", "AccessX*XmScale");
return TRUE;
}
static void
fsel_dialog_finish (GtkWidget *fsel)
{
gtk_widget_hide_all (fsel);
}
static void
fsel_handle_ok (GtkWidget *widget, GtkFileSelection *fsel)
{
gchar const *file_name;
file_name = gtk_file_selection_get_filename (fsel);
/* Change into directory if that's what user selected */
if (g_file_test (file_name, G_FILE_TEST_IS_DIR)) {
gint name_len;
gchar *dir_name;
name_len = strlen (file_name);
if (name_len < 1 || file_name [name_len - 1] != '/') {
/* The file selector needs a '/' at the end of a directory name */
dir_name = g_strconcat (file_name, "/", NULL);
} else {
dir_name = g_strdup (file_name);
}
gtk_file_selection_set_filename (fsel, dir_name);
g_free (dir_name);
} else if (load_CDE_file (fsel))
fsel_dialog_finish (GTK_WIDGET (fsel));
}
static void
fsel_handle_cancel (GtkWidget *widget, GtkFileSelection *fsel)
{
fsel_dialog_finish (GTK_WIDGET (fsel));
}
static gint
fsel_delete_event (GtkWidget *fsel, GdkEventAny *event)
{
fsel_dialog_finish (fsel);
return TRUE;
}
static gint
fsel_key_event (GtkWidget *fsel, GdkEventKey *event, gpointer user_data)
{
if (event->keyval == GDK_Escape) {
gtk_signal_emit_stop_by_name (GTK_OBJECT (fsel), "key_press_event");
fsel_dialog_finish (fsel);
return TRUE;
}
return FALSE;
}
static GtkFileSelection *fsel = NULL;
static void
cb_load_CDE_file (GtkButton *button, GtkWidget *dialog)
{
if (fsel == NULL) {
fsel = GTK_FILE_SELECTION (
gtk_file_selection_new (_("Select CDE AccessX file")));
gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (fsel));
gtk_file_selection_set_select_multiple (GTK_FILE_SELECTION (fsel), FALSE);
gtk_window_set_modal (GTK_WINDOW (fsel), TRUE);
gtk_window_set_transient_for (GTK_WINDOW (fsel),
GTK_WINDOW (gtk_widget_get_toplevel (dialog)));
g_signal_connect (G_OBJECT (fsel->ok_button),
"clicked",
G_CALLBACK (fsel_handle_ok), fsel);
g_signal_connect (G_OBJECT (fsel->cancel_button),
"clicked",
G_CALLBACK (fsel_handle_cancel), fsel);
g_signal_connect (G_OBJECT (fsel),
"key_press_event",
G_CALLBACK (fsel_key_event), NULL);
g_signal_connect (G_OBJECT (fsel),
"delete_event",
G_CALLBACK (fsel_delete_event), NULL);
}
gtk_widget_show_all (GTK_WIDGET (fsel));
}
/*******************************************************************************/
GtkWidget *
setup_accessX_dialog (GConfChangeSet *changeset)
{
GConfClient *client;
char const *toplevel_name = "accessX_dialog";
GladeXML *dialog = glade_xml_new (GNOMECC_DATA_DIR
"/interfaces/gnome-accessibility-keyboard-properties.glade",
toplevel_name, NULL);
GtkWidget *toplevel = WID (toplevel_name);
client = gconf_client_get_default ();
gconf_client_add_dir (client, CONFIG_ROOT, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
setup_dialog (dialog, changeset);
g_signal_connect (G_OBJECT (WID ("load_CDE_file")),
"clicked",
G_CALLBACK (cb_load_CDE_file), toplevel);
g_signal_connect (G_OBJECT (WID ("launch_repeat_button")),
"clicked",
G_CALLBACK (cb_launch_keyboard_capplet), toplevel);
return toplevel;
}