Index: plugins/a11y-keyboard/gsd-a11y-preferences-dialog.c
===================================================================
--- plugins/a11y-keyboard/gsd-a11y-preferences-dialog.c	(revision 0)
+++ plugins/a11y-keyboard/gsd-a11y-preferences-dialog.c	(revision 0)
@@ -0,0 +1,858 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include <glade/glade-xml.h>
+#include <gconf/gconf-client.h>
+
+#include "gsd-a11y-preferences-dialog.h"
+
+#define GSD_A11Y_PREFERENCES_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_A11Y_PREFERENCES_DIALOG, GsdA11yPreferencesDialogPrivate))
+
+#define GLADE_XML_FILE "gsd-a11y-preferences-dialog.glade"
+
+#define KEY_A11Y_DIR              "/desktop/gnome/accessibility"
+#define KEY_STICKY_KEYS_ENABLED   KEY_A11Y_DIR "/keyboard/stickykeys_enable"
+#define KEY_BOUNCE_KEYS_ENABLED   KEY_A11Y_DIR "/keyboard/bouncekeys_enable"
+#define KEY_SLOW_KEYS_ENABLED     KEY_A11Y_DIR "/keyboard/slowkeys_enable"
+#define KEY_MOUSE_KEYS_ENABLED    KEY_A11Y_DIR "/keyboard/mousekeys_enable"
+
+#define KEY_AT_DIR                "/desktop/gnome/applications/at"
+#define KEY_AT_SCREEN_KEYBOARD_ENABLED  KEY_AT_DIR "/screen_keyboard_enabled"
+#define KEY_AT_SCREEN_MAGNIFIER_ENABLED KEY_AT_DIR "/screen_magnifier_enabled"
+#define KEY_AT_SCREEN_READER_ENABLED    KEY_AT_DIR "/screen_reader_enabled"
+
+#define KEY_GTK_THEME          "/desktop/gnome/interface/gtk_theme"
+#define KEY_COLOR_SCHEME       "/desktop/gnome/interface/gtk_color_scheme"
+#define KEY_METACITY_THEME     "/apps/metacity/general/theme"
+#define KEY_ICON_THEME         "/desktop/gnome/interface/icon_theme"
+
+#define KEY_GTK_FONT           "/desktop/gnome/interface/font_name"
+
+#define HIGH_CONTRAST_THEME    "HighContrast"
+#define DEFAULT_LARGE_FONT             "Sans 18"
+
+struct GsdA11yPreferencesDialogPrivate
+{
+        GladeXML *xml;
+        guint     a11y_dir_cnxn;
+        guint     gsd_a11y_dir_cnxn;
+};
+
+enum {
+        PROP_0,
+};
+
+static void     gsd_a11y_preferences_dialog_class_init  (GsdA11yPreferencesDialogClass *klass);
+static void     gsd_a11y_preferences_dialog_init        (GsdA11yPreferencesDialog      *a11y_preferences_dialog);
+static void     gsd_a11y_preferences_dialog_finalize    (GObject                       *object);
+
+G_DEFINE_TYPE (GsdA11yPreferencesDialog, gsd_a11y_preferences_dialog, GTK_TYPE_DIALOG)
+
+static void
+gsd_a11y_preferences_dialog_set_property (GObject        *object,
+                                          guint           prop_id,
+                                          const GValue   *value,
+                                          GParamSpec     *pspec)
+{
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gsd_a11y_preferences_dialog_get_property (GObject        *object,
+                                          guint           prop_id,
+                                          GValue         *value,
+                                          GParamSpec     *pspec)
+{
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static GObject *
+gsd_a11y_preferences_dialog_constructor (GType                  type,
+                                         guint                  n_construct_properties,
+                                         GObjectConstructParam *construct_properties)
+{
+        GsdA11yPreferencesDialog      *a11y_preferences_dialog;
+
+        a11y_preferences_dialog = GSD_A11Y_PREFERENCES_DIALOG (G_OBJECT_CLASS (gsd_a11y_preferences_dialog_parent_class)->constructor (type,
+                                                                                                                           n_construct_properties,
+                                                                                                                           construct_properties));
+
+        return G_OBJECT (a11y_preferences_dialog);
+}
+
+static void
+gsd_a11y_preferences_dialog_dispose (GObject *object)
+{
+        G_OBJECT_CLASS (gsd_a11y_preferences_dialog_parent_class)->dispose (object);
+}
+
+static void
+gsd_a11y_preferences_dialog_class_init (GsdA11yPreferencesDialogClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->get_property = gsd_a11y_preferences_dialog_get_property;
+        object_class->set_property = gsd_a11y_preferences_dialog_set_property;
+        object_class->constructor = gsd_a11y_preferences_dialog_constructor;
+        object_class->dispose = gsd_a11y_preferences_dialog_dispose;
+        object_class->finalize = gsd_a11y_preferences_dialog_finalize;
+
+        g_type_class_add_private (klass, sizeof (GsdA11yPreferencesDialogPrivate));
+}
+
+static void
+on_response (GsdA11yPreferencesDialog *dialog,
+             gint                      response_id)
+{
+        switch (response_id) {
+        default:
+                break;
+        }
+}
+
+static char *
+config_get_string (const char *key,
+                   gboolean   *is_writable)
+{
+        char        *str;
+        GConfClient *client;
+
+        client = gconf_client_get_default ();
+
+        if (is_writable) {
+                *is_writable = gconf_client_key_is_writable (client,
+                                                             key,
+                                                             NULL);
+        }
+
+        str = gconf_client_get_string (client, key, NULL);
+
+        g_object_unref (client);
+
+        return str;
+}
+
+static gboolean
+config_get_bool (const char *key,
+                 gboolean   *is_writable)
+{
+        int          enabled;
+        GConfClient *client;
+
+        client = gconf_client_get_default ();
+
+        if (is_writable) {
+                *is_writable = gconf_client_key_is_writable (client,
+                                                             key,
+                                                             NULL);
+        }
+
+        enabled = gconf_client_get_bool (client, key, NULL);
+
+        g_object_unref (client);
+
+        return enabled;
+}
+
+static char *
+get_large_font (GConfClient *client)
+{
+        char                 *default_font;
+        double                new_size;
+        char                 *new_font;
+        PangoFontDescription *pfd;
+        GConfValue           *value;
+        new_font = NULL;
+
+        default_font = NULL;
+        value = gconf_client_get_default_from_schema (client,
+                                                      KEY_GTK_FONT,
+                                                      NULL);
+        if (value != NULL) {
+                default_font = g_strdup (gconf_value_get_string (value));
+                gconf_value_free (value);
+        }
+        if (default_font == NULL) {
+                default_font = g_strdup (DEFAULT_LARGE_FONT);
+        }
+
+        pfd = pango_font_description_from_string (default_font);
+        if (pfd == NULL) {
+                goto out;
+        }
+
+        if ((pango_font_description_get_set_fields (pfd) & PANGO_FONT_MASK_SIZE)) {
+                new_size = pango_font_description_get_size (pfd) / (double)PANGO_SCALE;
+                new_size *= PANGO_SCALE_XX_LARGE;
+        } else {
+                new_size = 18.0;
+        }
+
+        pango_font_description_set_size (pfd, new_size * PANGO_SCALE);
+        new_font = pango_font_description_to_string (pfd);
+        pango_font_description_free (pfd);
+
+ out:
+        g_free (default_font);
+
+        return new_font;
+}
+
+static gboolean
+config_get_large_print (gboolean *is_writable)
+{
+        gboolean     ret;
+        char        *font;
+        char        *large_font;
+        GConfClient *client;
+
+        ret = FALSE;
+
+        font = config_get_string (KEY_GTK_FONT, is_writable);
+
+        client = gconf_client_get_default ();
+        large_font = get_large_font (client);
+        g_object_unref (client);
+
+        if (large_font != NULL && font != NULL && strcmp (large_font, font) == 0) {
+                ret = TRUE;
+        }
+
+        g_free (large_font);
+        g_free (font);
+
+        return ret;
+}
+
+static void
+config_set_large_print (gboolean enabled)
+{
+        GConfClient *client;
+
+        client = gconf_client_get_default ();
+
+        if (enabled) {
+                char *large_font;
+                large_font = get_large_font (client);
+                gconf_client_set_string (client, KEY_GTK_FONT, large_font, NULL);
+                g_free (large_font);
+        } else {
+                gconf_client_unset (client, KEY_GTK_FONT, NULL);
+        }
+
+        g_object_unref (client);
+}
+
+static gboolean
+config_get_high_contrast (gboolean *is_writable)
+{
+        gboolean ret;
+        char    *gtk_theme;
+
+        ret = FALSE;
+
+        gtk_theme = config_get_string (KEY_GTK_THEME, is_writable);
+        if (gtk_theme != NULL && strcmp (gtk_theme, HIGH_CONTRAST_THEME) == 0) {
+                ret = TRUE;
+        }
+        g_free (gtk_theme);
+
+        return ret;
+}
+
+static void
+config_set_high_contrast (gboolean enabled)
+{
+        GConfClient *client;
+
+        client = gconf_client_get_default ();
+
+        if (enabled) {
+                gconf_client_set_string (client, KEY_GTK_THEME, HIGH_CONTRAST_THEME, NULL);
+                gconf_client_set_string (client, KEY_ICON_THEME, HIGH_CONTRAST_THEME, NULL);
+                /* there isn't a high contrast metacity theme afaik */
+        } else {
+                gconf_client_unset (client, KEY_GTK_THEME, NULL);
+                gconf_client_unset (client, KEY_ICON_THEME, NULL);
+                gconf_client_unset (client, KEY_METACITY_THEME, NULL);
+        }
+
+        g_object_unref (client);
+}
+
+static gboolean
+config_get_sticky_keys (gboolean *is_writable)
+{
+        return config_get_bool (KEY_STICKY_KEYS_ENABLED, is_writable);
+}
+
+static void
+config_set_sticky_keys (gboolean enabled)
+{
+        GConfClient *client;
+
+        client = gconf_client_get_default ();
+        gconf_client_set_bool (client, KEY_STICKY_KEYS_ENABLED, enabled, NULL);
+        g_object_unref (client);
+}
+
+static gboolean
+config_get_bounce_keys (gboolean *is_writable)
+{
+        return config_get_bool (KEY_BOUNCE_KEYS_ENABLED, is_writable);
+}
+
+static void
+config_set_bounce_keys (gboolean enabled)
+{
+        GConfClient *client;
+
+        client = gconf_client_get_default ();
+        gconf_client_set_bool (client, KEY_BOUNCE_KEYS_ENABLED, enabled, NULL);
+        g_object_unref (client);
+}
+
+static gboolean
+config_get_slow_keys (gboolean *is_writable)
+{
+        return config_get_bool (KEY_SLOW_KEYS_ENABLED, is_writable);
+}
+
+static void
+config_set_slow_keys (gboolean enabled)
+{
+        GConfClient *client;
+
+        client = gconf_client_get_default ();
+        gconf_client_set_bool (client, KEY_SLOW_KEYS_ENABLED, enabled, NULL);
+        g_object_unref (client);
+}
+
+static gboolean
+config_get_at_screen_reader (gboolean *is_writable)
+{
+        return config_get_bool (KEY_AT_SCREEN_READER_ENABLED, is_writable);
+}
+
+static gboolean
+config_get_at_screen_keyboard (gboolean *is_writable)
+{
+        return config_get_bool (KEY_AT_SCREEN_KEYBOARD_ENABLED, is_writable);
+}
+
+static gboolean
+config_get_at_screen_magnifier (gboolean *is_writable)
+{
+        return config_get_bool (KEY_AT_SCREEN_MAGNIFIER_ENABLED, is_writable);
+}
+
+static void
+config_set_at_screen_reader (gboolean enabled)
+{
+        GConfClient *client;
+
+        client = gconf_client_get_default ();
+        gconf_client_set_bool (client, KEY_AT_SCREEN_READER_ENABLED, enabled, NULL);
+        g_object_unref (client);
+}
+
+static void
+config_set_at_screen_keyboard (gboolean enabled)
+{
+        GConfClient *client;
+
+        client = gconf_client_get_default ();
+        gconf_client_set_bool (client, KEY_AT_SCREEN_KEYBOARD_ENABLED, enabled, NULL);
+        g_object_unref (client);
+}
+
+static void
+config_set_at_screen_magnifier (gboolean enabled)
+{
+        GConfClient *client;
+
+        client = gconf_client_get_default ();
+        gconf_client_set_bool (client, KEY_AT_SCREEN_MAGNIFIER_ENABLED, enabled, NULL);
+        g_object_unref (client);
+}
+
+static void
+on_sticky_keys_checkbutton_toggled (GtkToggleButton          *button,
+                                    GsdA11yPreferencesDialog *dialog)
+{
+        config_set_sticky_keys (gtk_toggle_button_get_active (button));
+}
+
+static void
+on_bounce_keys_checkbutton_toggled (GtkToggleButton          *button,
+                                 GsdA11yPreferencesDialog *dialog)
+{
+        config_set_bounce_keys (gtk_toggle_button_get_active (button));
+}
+
+static void
+on_slow_keys_checkbutton_toggled (GtkToggleButton          *button,
+                                  GsdA11yPreferencesDialog *dialog)
+{
+        config_set_slow_keys (gtk_toggle_button_get_active (button));
+}
+
+static void
+on_high_contrast_checkbutton_toggled (GtkToggleButton          *button,
+                                      GsdA11yPreferencesDialog *dialog)
+{
+        config_set_high_contrast (gtk_toggle_button_get_active (button));
+}
+
+static void
+on_at_screen_reader_checkbutton_toggled (GtkToggleButton          *button,
+                                         GsdA11yPreferencesDialog *dialog)
+{
+        config_set_at_screen_reader (gtk_toggle_button_get_active (button));
+}
+
+static void
+on_at_screen_keyboard_checkbutton_toggled (GtkToggleButton          *button,
+                                           GsdA11yPreferencesDialog *dialog)
+{
+        config_set_at_screen_keyboard (gtk_toggle_button_get_active (button));
+}
+
+static void
+on_at_screen_magnifier_checkbutton_toggled (GtkToggleButton          *button,
+                                            GsdA11yPreferencesDialog *dialog)
+{
+        config_set_at_screen_magnifier (gtk_toggle_button_get_active (button));
+}
+
+static void
+on_large_print_checkbutton_toggled (GtkToggleButton          *button,
+                                    GsdA11yPreferencesDialog *dialog)
+{
+        config_set_large_print (gtk_toggle_button_get_active (button));
+}
+
+static void
+ui_set_sticky_keys (GsdA11yPreferencesDialog *dialog,
+                    gboolean                  enabled)
+{
+        GtkWidget *widget;
+        gboolean   active;
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "sticky_keys_checkbutton");
+        active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+        if (active != enabled) {
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled);
+        }
+}
+
+static void
+ui_set_bounce_keys (GsdA11yPreferencesDialog *dialog,
+                    gboolean                  enabled)
+{
+        GtkWidget *widget;
+        gboolean   active;
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "bounce_keys_checkbutton");
+        active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+        if (active != enabled) {
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled);
+        }
+}
+
+static void
+ui_set_slow_keys (GsdA11yPreferencesDialog *dialog,
+                  gboolean                  enabled)
+{
+        GtkWidget *widget;
+        gboolean   active;
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "slow_keys_checkbutton");
+        active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+        if (active != enabled) {
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled);
+        }
+}
+
+static void
+ui_set_high_contrast (GsdA11yPreferencesDialog *dialog,
+                      gboolean                  enabled)
+{
+        GtkWidget *widget;
+        gboolean   active;
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "high_contrast_checkbutton");
+        active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+        if (active != enabled) {
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled);
+        }
+}
+
+static void
+ui_set_at_screen_reader (GsdA11yPreferencesDialog *dialog,
+                         gboolean                  enabled)
+{
+        GtkWidget *widget;
+        gboolean   active;
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "at_screen_reader_checkbutton");
+        active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+        if (active != enabled) {
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled);
+        }
+}
+
+static void
+ui_set_at_screen_keyboard (GsdA11yPreferencesDialog *dialog,
+                           gboolean                  enabled)
+{
+        GtkWidget *widget;
+        gboolean   active;
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "at_screen_keyboard_checkbutton");
+        active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+        if (active != enabled) {
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled);
+        }
+}
+
+static void
+ui_set_at_screen_magnifier (GsdA11yPreferencesDialog *dialog,
+                            gboolean                  enabled)
+{
+        GtkWidget *widget;
+        gboolean   active;
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "at_screen_magnifier_checkbutton");
+        active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+        if (active != enabled) {
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled);
+        }
+}
+
+static void
+ui_set_large_print (GsdA11yPreferencesDialog *dialog,
+                    gboolean                  enabled)
+{
+        GtkWidget *widget;
+        gboolean   active;
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "large_print_checkbutton");
+        active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+        if (active != enabled) {
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled);
+        }
+}
+
+static void
+key_changed_cb (GConfClient *client,
+                guint        cnxn_id,
+                GConfEntry  *entry,
+                GsdA11yPreferencesDialog *dialog)
+{
+        const char *key;
+        GConfValue *value;
+
+        key = gconf_entry_get_key (entry);
+        value = gconf_entry_get_value (entry);
+
+        if (strcmp (key, KEY_STICKY_KEYS_ENABLED) == 0) {
+                if (value->type == GCONF_VALUE_BOOL) {
+                        gboolean enabled;
+
+                        enabled = gconf_value_get_bool (value);
+                        ui_set_sticky_keys (dialog, enabled);
+                } else {
+                        g_warning ("Error retrieving configuration key '%s': Invalid type",
+                                   key);
+                }
+        } else if (strcmp (key, KEY_BOUNCE_KEYS_ENABLED) == 0) {
+                if (value->type == GCONF_VALUE_BOOL) {
+                        gboolean enabled;
+
+                        enabled = gconf_value_get_bool (value);
+                        ui_set_bounce_keys (dialog, enabled);
+                } else {
+                        g_warning ("Error retrieving configuration key '%s': Invalid type",
+                                   key);
+                }
+        } else if (strcmp (key, KEY_SLOW_KEYS_ENABLED) == 0) {
+                if (value->type == GCONF_VALUE_BOOL) {
+                        gboolean enabled;
+
+                        enabled = gconf_value_get_bool (value);
+                        ui_set_slow_keys (dialog, enabled);
+                } else {
+                        g_warning ("Error retrieving configuration key '%s': Invalid type",
+                                   key);
+                }
+        } else if (strcmp (key, KEY_AT_SCREEN_READER_ENABLED) == 0) {
+                if (value->type == GCONF_VALUE_BOOL) {
+                        gboolean enabled;
+
+                        enabled = gconf_value_get_bool (value);
+                        ui_set_at_screen_reader (dialog, enabled);
+                } else {
+                        g_warning ("Error retrieving configuration key '%s': Invalid type",
+                                   key);
+                }
+        } else if (strcmp (key, KEY_AT_SCREEN_KEYBOARD_ENABLED) == 0) {
+                if (value->type == GCONF_VALUE_BOOL) {
+                        gboolean enabled;
+
+                        enabled = gconf_value_get_bool (value);
+                        ui_set_at_screen_keyboard (dialog, enabled);
+                } else {
+                        g_warning ("Error retrieving configuration key '%s': Invalid type",
+                                   key);
+                }
+        } else if (strcmp (key, KEY_AT_SCREEN_MAGNIFIER_ENABLED) == 0) {
+                if (value->type == GCONF_VALUE_BOOL) {
+                        gboolean enabled;
+
+                        enabled = gconf_value_get_bool (value);
+                        ui_set_at_screen_magnifier (dialog, enabled);
+                } else {
+                        g_warning ("Error retrieving configuration key '%s': Invalid type",
+                                   key);
+                }
+        } else {
+                g_debug ("Config key not handled: %s", key);
+        }
+}
+
+static void
+setup_dialog (GsdA11yPreferencesDialog *dialog)
+{
+        GtkWidget   *widget;
+        gboolean     enabled;
+        gboolean     is_writable;
+        GConfClient *client;
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "sticky_keys_checkbutton");
+        g_signal_connect (widget,
+                          "toggled",
+                          G_CALLBACK (on_sticky_keys_checkbutton_toggled),
+                          NULL);
+        enabled = config_get_sticky_keys (&is_writable);
+        ui_set_sticky_keys (dialog, enabled);
+        if (! is_writable) {
+                gtk_widget_set_sensitive (widget, FALSE);
+        }
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "bounce_keys_checkbutton");
+        g_signal_connect (widget,
+                          "toggled",
+                          G_CALLBACK (on_bounce_keys_checkbutton_toggled),
+                          NULL);
+        enabled = config_get_bounce_keys (&is_writable);
+        ui_set_bounce_keys (dialog, enabled);
+        if (! is_writable) {
+                gtk_widget_set_sensitive (widget, FALSE);
+        }
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "slow_keys_checkbutton");
+        g_signal_connect (widget,
+                          "toggled",
+                          G_CALLBACK (on_slow_keys_checkbutton_toggled),
+                          NULL);
+        enabled = config_get_slow_keys (&is_writable);
+        ui_set_slow_keys (dialog, enabled);
+        if (! is_writable) {
+                gtk_widget_set_sensitive (widget, FALSE);
+        }
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "high_contrast_checkbutton");
+        g_signal_connect (widget,
+                          "toggled",
+                          G_CALLBACK (on_high_contrast_checkbutton_toggled),
+                          NULL);
+        enabled = config_get_high_contrast (&is_writable);
+        ui_set_high_contrast (dialog, enabled);
+        if (! is_writable) {
+                gtk_widget_set_sensitive (widget, FALSE);
+        }
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "at_screen_keyboard_checkbutton");
+        g_signal_connect (widget,
+                          "toggled",
+                          G_CALLBACK (on_at_screen_keyboard_checkbutton_toggled),
+                          NULL);
+        enabled = config_get_at_screen_keyboard (&is_writable);
+        ui_set_at_screen_keyboard (dialog, enabled);
+        if (! is_writable) {
+                gtk_widget_set_sensitive (widget, FALSE);
+        }
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "at_screen_reader_checkbutton");
+        g_signal_connect (widget,
+                          "toggled",
+                          G_CALLBACK (on_at_screen_reader_checkbutton_toggled),
+                          NULL);
+        enabled = config_get_at_screen_reader (&is_writable);
+        ui_set_at_screen_reader (dialog, enabled);
+        if (! is_writable) {
+                gtk_widget_set_sensitive (widget, FALSE);
+        }
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "at_screen_magnifier_checkbutton");
+        g_signal_connect (widget,
+                          "toggled",
+                          G_CALLBACK (on_at_screen_magnifier_checkbutton_toggled),
+                          NULL);
+        enabled = config_get_at_screen_magnifier (&is_writable);
+        ui_set_at_screen_magnifier (dialog, enabled);
+        if (! is_writable) {
+                gtk_widget_set_sensitive (widget, FALSE);
+        }
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "large_print_checkbutton");
+        g_signal_connect (widget,
+                          "toggled",
+                          G_CALLBACK (on_large_print_checkbutton_toggled),
+                          NULL);
+        enabled = config_get_large_print (&is_writable);
+        ui_set_large_print (dialog, enabled);
+        if (! is_writable) {
+                gtk_widget_set_sensitive (widget, FALSE);
+        }
+
+
+        client = gconf_client_get_default ();
+        gconf_client_add_dir (client,
+                              KEY_A11Y_DIR,
+                              GCONF_CLIENT_PRELOAD_ONELEVEL,
+                              NULL);
+        dialog->priv->a11y_dir_cnxn = gconf_client_notify_add (client,
+                                                               KEY_A11Y_DIR,
+                                                               (GConfClientNotifyFunc)key_changed_cb,
+                                                               dialog,
+                                                               NULL,
+                                                               NULL);
+
+        gconf_client_add_dir (client,
+                              KEY_AT_DIR,
+                              GCONF_CLIENT_PRELOAD_ONELEVEL,
+                              NULL);
+        dialog->priv->gsd_a11y_dir_cnxn = gconf_client_notify_add (client,
+                                                                   KEY_AT_DIR,
+                                                                   (GConfClientNotifyFunc)key_changed_cb,
+                                                                   dialog,
+                                                                   NULL,
+                                                                   NULL);
+
+        g_object_unref (client);
+}
+
+static void
+gsd_a11y_preferences_dialog_init (GsdA11yPreferencesDialog *dialog)
+{
+        GtkWidget *widget;
+
+        dialog->priv = GSD_A11Y_PREFERENCES_DIALOG_GET_PRIVATE (dialog);
+
+        dialog->priv->xml = glade_xml_new (GLADEDIR "/" GLADE_XML_FILE,
+                                           "main_box",
+                                           PACKAGE);
+        g_assert (dialog->priv->xml != NULL);
+
+        widget = glade_xml_get_widget (dialog->priv->xml, "main_box");
+        gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), widget);
+
+        gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
+        gtk_container_set_border_width (GTK_CONTAINER (widget), 12);
+        gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+        gtk_window_set_title (GTK_WINDOW (dialog), _("Accessibility Preferences"));
+        gtk_window_set_icon_name (GTK_WINDOW (dialog), "preferences-desktop-accessibility");
+        g_object_set (dialog,
+                      "allow-shrink", FALSE,
+                      "allow-grow", FALSE,
+                      NULL);
+
+        gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                                GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+                                NULL);
+        g_signal_connect (dialog,
+                          "response",
+                          G_CALLBACK (on_response),
+                          dialog);
+
+        setup_dialog (dialog);
+
+        gtk_widget_show_all (GTK_WIDGET (dialog));
+}
+
+static void
+gsd_a11y_preferences_dialog_finalize (GObject *object)
+{
+        GsdA11yPreferencesDialog *dialog;
+        GConfClient *client;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GSD_IS_A11Y_PREFERENCES_DIALOG (object));
+
+        dialog = GSD_A11Y_PREFERENCES_DIALOG (object);
+
+        g_return_if_fail (dialog->priv != NULL);
+
+        client = gconf_client_get_default ();
+
+        if (dialog->priv->a11y_dir_cnxn > 0) {
+                gconf_client_notify_remove (client, dialog->priv->a11y_dir_cnxn);
+        }
+        if (dialog->priv->gsd_a11y_dir_cnxn > 0) {
+                gconf_client_notify_remove (client, dialog->priv->gsd_a11y_dir_cnxn);
+        }
+
+        g_object_unref (client);
+
+        G_OBJECT_CLASS (gsd_a11y_preferences_dialog_parent_class)->finalize (object);
+}
+
+GtkWidget *
+gsd_a11y_preferences_dialog_new (void)
+{
+        GObject *object;
+
+        object = g_object_new (GSD_TYPE_A11Y_PREFERENCES_DIALOG,
+                               NULL);
+
+        return GTK_WIDGET (object);
+}
Index: plugins/a11y-keyboard/gsd-a11y-preferences-dialog.h
===================================================================
--- plugins/a11y-keyboard/gsd-a11y-preferences-dialog.h	(revision 0)
+++ plugins/a11y-keyboard/gsd-a11y-preferences-dialog.h	(revision 0)
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __GSD_A11Y_PREFERENCES_DIALOG_H
+#define __GSD_A11Y_PREFERENCES_DIALOG_H
+
+#include <glib-object.h>
+#include <gtk/gtkdialog.h>
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_A11Y_PREFERENCES_DIALOG         (gsd_a11y_preferences_dialog_get_type ())
+#define GSD_A11Y_PREFERENCES_DIALOG(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_A11Y_PREFERENCES_DIALOG, GsdA11yPreferencesDialog))
+#define GSD_A11Y_PREFERENCES_DIALOG_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_A11Y_PREFERENCES_DIALOG, GsdA11yPreferencesDialogClass))
+#define GSD_IS_A11Y_PREFERENCES_DIALOG(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_A11Y_PREFERENCES_DIALOG))
+#define GSD_IS_A11Y_PREFERENCES_DIALOG_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_A11Y_PREFERENCES_DIALOG))
+#define GSD_A11Y_PREFERENCES_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_A11Y_PREFERENCES_DIALOG, GsdA11yPreferencesDialogClass))
+
+typedef struct GsdA11yPreferencesDialogPrivate GsdA11yPreferencesDialogPrivate;
+
+typedef struct
+{
+        GtkDialog                        parent;
+        GsdA11yPreferencesDialogPrivate *priv;
+} GsdA11yPreferencesDialog;
+
+typedef struct
+{
+        GtkDialogClass   parent_class;
+} GsdA11yPreferencesDialogClass;
+
+GType                  gsd_a11y_preferences_dialog_get_type                   (void);
+
+GtkWidget            * gsd_a11y_preferences_dialog_new                        (void);
+
+G_END_DECLS
+
+#endif /* __GSD_A11Y_PREFERENCES_DIALOG_H */
Index: plugins/a11y-keyboard/Makefile.am
===================================================================
--- plugins/a11y-keyboard/Makefile.am	(revision 409)
+++ plugins/a11y-keyboard/Makefile.am	(working copy)
@@ -1,5 +1,10 @@
 NULL =
 
+gladedir = $(pkgdatadir)/a11y-keyboard
+glade_DATA = 					\
+	gsd-a11y-preferences-dialog.glade	\
+	$(NULL)
+
 plugin_LTLIBRARIES = \
 	liba11y-keyboard.la		\
 	$(NULL)
@@ -9,15 +14,19 @@ liba11y_keyboard_la_SOURCES = 		\
 	gsd-a11y-keyboard-plugin.c	\
 	gsd-a11y-keyboard-manager.h	\
 	gsd-a11y-keyboard-manager.c	\
+	gsd-a11y-preferences-dialog.h	\
+	gsd-a11y-preferences-dialog.c	\
 	$(NULL)
 
 liba11y_keyboard_la_CPPFLAGS = \
 	-I$(top_srcdir)/gnome-settings-daemon		\
 	-DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+	-DGLADEDIR=\""$(gladedir)"\" \
 	$(AM_CPPFLAGS)
 
 liba11y_keyboard_la_CFLAGS = \
 	$(SETTINGS_PLUGIN_CFLAGS)	\
+	$(LIBNOTIFY_CFLAGS)		\
 	$(GNOME_CFLAGS)			\
 	$(AM_CFLAGS)
 
@@ -28,6 +37,7 @@ liba11y_keyboard_la_LDFLAGS = 		\
 liba11y_keyboard_la_LIBADD  = 		\
 	$(SETTINGS_PLUGIN_LIBS)		\
 	$(XF86MISC_LIBS)		\
+	$(LIBNOTIFY_LIBS)		\
 	$(GNOME_LIBS)			\
 	$(NULL)
 
Index: plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c
===================================================================
--- plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c	(revision 409)
+++ plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c	(working copy)
@@ -43,10 +43,16 @@
 
 #include <libgnome/gnome-help.h>
 
+#ifdef HAVE_LIBNOTIFY
+#include <libnotify/notify.h>
+#endif /* HAVE_LIBNOTIFY */
+
 #include "gnome-settings-profile.h"
 #include "gsd-a11y-keyboard-manager.h"
+#include "gsd-a11y-preferences-dialog.h"
 
 #define CONFIG_ROOT "/desktop/gnome/accessibility/keyboard"
+#define NOTIFICATION_TIMEOUT 30
 
 #define GSD_A11Y_KEYBOARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_A11Y_KEYBOARD_MANAGER, GsdA11yKeyboardManagerPrivate))
 
@@ -57,9 +63,14 @@ struct GsdA11yKeyboardManagerPrivate
         gboolean   slowkeys_shortcut_val;
         GtkWidget *stickykeys_alert;
         GtkWidget *slowkeys_alert;
+        GtkWidget *preferences_dialog;
+        GtkStatusIcon *status_icon;
 
         guint      gconf_notify;
 
+#ifdef HAVE_LIBNOTIFY
+        NotifyNotification *notification;
+#endif /* HAVE_LIBNOTIFY */
 };
 
 #define GSD_KBD_A11Y_ERROR gsd_kbd_a11y_error_quark ()
@@ -136,8 +147,9 @@ get_int (GConfClient *client,
          char const  *key)
 {
         int res = gconf_client_get_int  (client, key, NULL);
-        if (res <= 0)
+        if (res <= 0) {
                 res = 1;
+        }
         return res;
 }
 
@@ -179,8 +191,9 @@ set_clear (gboolean      flag,
            unsigned long value,
            unsigned long mask)
 {
-        if (flag)
+        if (flag) {
                 return value | mask;
+        }
         return value & ~mask;
 }
 
@@ -420,10 +433,169 @@ ax_slowkeys_response (GtkDialog         
 }
 
 static void
-ax_slowkeys_warning_dialog_post (GsdA11yKeyboardManager *manager,
+maybe_show_status_icon (GsdA11yKeyboardManager *manager)
+{
+        gboolean     show;
+        GConfClient *client;
+
+        /* for now, show if accessx is enabled */
+        client = gconf_client_get_default ();
+        show = gconf_client_get_bool (client, CONFIG_ROOT "/enable", NULL);
+        g_object_unref (client);
+
+        gtk_status_icon_set_visible (manager->priv->status_icon, show);
+}
+
+#ifdef HAVE_LIBNOTIFY
+static void
+on_notification_closed (NotifyNotification     *notification,
+                        GsdA11yKeyboardManager *manager)
+{
+        /* seems to crash if we unref */
+        manager->priv->notification = NULL;
+}
+
+static void
+on_slow_keys_action (NotifyNotification     *notification,
+                     const char             *action,
+                     GsdA11yKeyboardManager *manager)
+{
+        gboolean res;
+        int      response_id;
+
+        g_assert (action != NULL);
+
+        if (strcmp (action, "accept") == 0) {
+                response_id = GTK_RESPONSE_ACCEPT;
+        } else if (strcmp (action, "reject") == 0) {
+                response_id = GTK_RESPONSE_REJECT;
+        } else {
+                return;
+        }
+
+        res = ax_response_callback (manager, response_id, XkbSlowKeysMask, manager->priv->slowkeys_shortcut_val);
+        if (res) {
+                g_signal_handlers_disconnect_by_func (manager->priv->notification, on_notification_closed, manager);
+                notify_notification_close (manager->priv->notification, NULL);
+                g_object_unref (manager->priv->notification);
+                manager->priv->notification = NULL;
+        }
+}
+
+static void
+on_sticky_keys_action (NotifyNotification     *notification,
+                       const char             *action,
+                       GsdA11yKeyboardManager *manager)
+{
+        gboolean res;
+        int      response_id;
+
+        g_assert (action != NULL);
+
+        if (strcmp (action, "accept") == 0) {
+                response_id = GTK_RESPONSE_ACCEPT;
+        } else if (strcmp (action, "reject") == 0) {
+                response_id = GTK_RESPONSE_REJECT;
+        } else {
+                return;
+        }
+
+        res = ax_response_callback (manager, response_id, XkbStickyKeysMask, manager->priv->stickykeys_shortcut_val);
+        if (res) {
+                g_signal_handlers_disconnect_by_func (manager->priv->notification, on_notification_closed, manager);
+                notify_notification_close (manager->priv->notification, NULL);
+                g_object_unref (manager->priv->notification);
+                manager->priv->notification = NULL;
+        }
+}
+
+#endif /* HAVE_LIBNOTIFY */
+
+static gboolean
+ax_slowkeys_warning_post_bubble (GsdA11yKeyboardManager *manager,
                                  gboolean                enabled)
 {
-        manager->priv->slowkeys_shortcut_val = enabled;
+#ifdef HAVE_LIBNOTIFY
+        gboolean    res;
+        const char *title;
+        const char *message;
+        GError     *error;
+
+        title = enabled ?
+                _("Do you want to activate Slow Keys?") :
+                _("Do you want to deactivate Slow Keys?");
+        message = _("You just held down the Shift key for 8 seconds.  This is the shortcut "
+                    "for the Slow Keys feature, which affects the way your keyboard works.");
+
+        if (! gtk_status_icon_is_embedded (manager->priv->status_icon)) {
+                return FALSE;
+        }
+
+        if (manager->priv->slowkeys_alert != NULL) {
+                gtk_widget_destroy (manager->priv->slowkeys_alert);
+        }
+
+        if (manager->priv->notification != NULL) {
+                g_signal_handlers_disconnect_by_func (manager->priv->notification, on_notification_closed, manager);
+                notify_notification_close (manager->priv->notification, NULL);
+                g_object_unref (manager->priv->notification);
+                manager->priv->notification = NULL;
+        }
+
+        manager->priv->notification = notify_notification_new_with_status_icon (title,
+                                                                                message,
+                                                                                "preferences-desktop-accessibility",
+                                                                                manager->priv->status_icon);
+        notify_notification_set_timeout (manager->priv->notification, NOTIFICATION_TIMEOUT * 1000);
+
+        notify_notification_add_action (manager->priv->notification,
+                                        "reject",
+                                        enabled ? _("Don't activate") : _("Don't deactivate"),
+                                        (NotifyActionCallback) on_slow_keys_action,
+                                        manager,
+                                        NULL);
+        notify_notification_add_action (manager->priv->notification,
+                                        "accept",
+                                        enabled ? _("Activate") : _("Deactivate"),
+                                        (NotifyActionCallback) on_slow_keys_action,
+                                        manager,
+                                        NULL);
+
+        g_signal_connect (manager->priv->notification,
+                          "closed",
+                          G_CALLBACK (on_notification_closed),
+                          manager);
+
+        error = NULL;
+        res = notify_notification_show (manager->priv->notification, &error);
+        if (! res) {
+                g_warning ("GsdA11yKeyboardManager: unable to show notification: %s", error->message);
+                g_error_free (error);
+                g_signal_handlers_disconnect_by_func (manager->priv->notification, on_notification_closed, manager);
+                notify_notification_close (manager->priv->notification, NULL);
+                g_object_unref (manager->priv->notification);
+                manager->priv->notification = NULL;
+        }
+
+        return res;
+#else
+        return FALSE;
+#endif /* HAVE_LIBNOTIFY */
+}
+
+
+static void
+ax_slowkeys_warning_post_dialog (GsdA11yKeyboardManager *manager,
+                                 gboolean                enabled)
+{
+        const char *title;
+        const char *message;
+
+        title = enabled ?
+                _("Do you want to activate Slow Keys?") :
+                _("Do you want to deactivate Slow Keys?");
+        message = _("You just held down the Shift key for 8 seconds.  This is the shortcut "
+                    "for the Slow Keys feature, which affects the way your keyboard works.");
 
         if (manager->priv->slowkeys_alert != NULL) {
                 gtk_widget_show (manager->priv->slowkeys_alert);
@@ -434,13 +606,10 @@ ax_slowkeys_warning_dialog_post (GsdA11y
                                                                 0,
                                                                 GTK_MESSAGE_WARNING,
                                                                 GTK_BUTTONS_NONE,
-                                                                enabled ?
-                                                                _("Do you want to activate Slow Keys?") :
-                                                                _("Do you want to deactivate Slow Keys?"));
+                                                                title);
 
         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (manager->priv->slowkeys_alert),
-                                                  _("You just held down the Shift key for 8 seconds.  This is the shortcut "
-                                                    "for the Slow Keys feature, which affects the way your keyboard works."));
+                                                  message);
 
         gtk_dialog_add_button (GTK_DIALOG (manager->priv->slowkeys_alert),
                                GTK_STOCK_HELP,
@@ -470,10 +639,108 @@ ax_slowkeys_warning_dialog_post (GsdA11y
 }
 
 static void
-ax_stickykeys_warning_dialog_post (GsdA11yKeyboardManager *manager,
+ax_slowkeys_warning_post (GsdA11yKeyboardManager *manager,
+                          gboolean                enabled)
+{
+
+        manager->priv->slowkeys_shortcut_val = enabled;
+
+        /* alway try to show something */
+        if (! ax_slowkeys_warning_post_bubble (manager, enabled)) {
+                ax_slowkeys_warning_post_dialog (manager, enabled);
+        }
+}
+
+static gboolean
+ax_stickykeys_warning_post_bubble (GsdA11yKeyboardManager *manager,
                                    gboolean                enabled)
 {
-        manager->priv->stickykeys_shortcut_val = enabled;
+#ifdef HAVE_LIBNOTIFY
+        gboolean    res;
+        const char *title;
+        const char *message;
+        GError     *error;
+
+        title = enabled ?
+                _("Do you want to activate Sticky Keys?") :
+                _("Do you want to deactivate Sticky Keys?");
+        message = enabled ?
+                _("You just pressed the Shift key 5 times in a row.  This is the shortcut "
+                  "for the Sticky Keys feature, which affects the way your keyboard works.") :
+                _("You just pressed two keys at once, or pressed the Shift key 5 times in a row.  "
+                  "This turns off the Sticky Keys feature, which affects the way your keyboard works.");
+
+        if (! gtk_status_icon_is_embedded (manager->priv->status_icon)) {
+                return FALSE;
+        }
+
+        if (manager->priv->slowkeys_alert != NULL) {
+                gtk_widget_destroy (manager->priv->slowkeys_alert);
+        }
+
+        if (manager->priv->notification != NULL) {
+                g_signal_handlers_disconnect_by_func (manager->priv->notification, on_notification_closed, manager);
+                notify_notification_close (manager->priv->notification, NULL);
+                g_object_unref (manager->priv->notification);
+                manager->priv->notification = NULL;
+        }
+
+        manager->priv->notification = notify_notification_new_with_status_icon (title,
+                                                                                message,
+                                                                                "preferences-desktop-accessibility",
+                                                                                manager->priv->status_icon);
+        notify_notification_set_timeout (manager->priv->notification, NOTIFICATION_TIMEOUT * 1000);
+
+        notify_notification_add_action (manager->priv->notification,
+                                        "reject",
+                                        enabled ? _("Don't activate") : _("Don't deactivate"),
+                                        (NotifyActionCallback) on_sticky_keys_action,
+                                        manager,
+                                        NULL);
+        notify_notification_add_action (manager->priv->notification,
+                                        "accept",
+                                        enabled ? _("Activate") : _("Deactivate"),
+                                        (NotifyActionCallback) on_sticky_keys_action,
+                                        manager,
+                                        NULL);
+
+        g_signal_connect (manager->priv->notification,
+                          "closed",
+                          G_CALLBACK (on_notification_closed),
+                          manager);
+
+        error = NULL;
+        res = notify_notification_show (manager->priv->notification, &error);
+        if (! res) {
+                g_warning ("GsdA11yKeyboardManager: unable to show notification: %s", error->message);
+                g_error_free (error);
+                g_signal_handlers_disconnect_by_func (manager->priv->notification, on_notification_closed, manager);
+                notify_notification_close (manager->priv->notification, NULL);
+                g_object_unref (manager->priv->notification);
+                manager->priv->notification = NULL;
+        }
+
+        return res;
+#else
+        return FALSE;
+#endif /* HAVE_LIBNOTIFY */
+}
+
+static void
+ax_stickykeys_warning_post_dialog (GsdA11yKeyboardManager *manager,
+                                   gboolean                enabled)
+{
+        const char *title;
+        const char *message;
+
+        title = enabled ?
+                _("Do you want to activate Sticky Keys?") :
+                _("Do you want to deactivate Sticky Keys?");
+        message = enabled ?
+                _("You just pressed the Shift key 5 times in a row.  This is the shortcut "
+                  "for the Sticky Keys feature, which affects the way your keyboard works.") :
+                _("You just pressed two keys at once, or pressed the Shift key 5 times in a row.  "
+                  "This turns off the Sticky Keys feature, which affects the way your keyboard works.");
 
         if (manager->priv->stickykeys_alert != NULL) {
                 gtk_widget_show (manager->priv->stickykeys_alert);
@@ -484,15 +751,10 @@ ax_stickykeys_warning_dialog_post (GsdA1
                                                                   0,
                                                                   GTK_MESSAGE_WARNING,
                                                                   GTK_BUTTONS_NONE,
-                                                                  enabled ?
-                                                                  _("Do you want to activate Sticky Keys?") :
-                                                                  _("Do you want to deactivate Sticky Keys?"));
+                                                                  title);
 
         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (manager->priv->stickykeys_alert),
-                                                  enabled ? _("You just pressed the Shift key 5 times in a row.  This is the shortcut "
-                                                              "for the Sticky Keys feature, which affects the way your keyboard works.") :
-                                                  _("You just pressed two keys at once, or pressed the Shift key 5 times in a row.  "
-                                                    "This turns off the Sticky Keys feature, which affects the way your keyboard works."));
+                                                  message);
 
         gtk_dialog_add_button (GTK_DIALOG (manager->priv->stickykeys_alert),
                                GTK_STOCK_HELP,
@@ -522,6 +784,19 @@ ax_stickykeys_warning_dialog_post (GsdA1
 }
 
 static void
+ax_stickykeys_warning_post (GsdA11yKeyboardManager *manager,
+                            gboolean                enabled)
+{
+
+        manager->priv->stickykeys_shortcut_val = enabled;
+
+        /* alway try to show something */
+        if (! ax_stickykeys_warning_post_bubble (manager, enabled)) {
+                ax_stickykeys_warning_post_dialog (manager, enabled);
+        }
+}
+
+static void
 set_gconf_from_server (GsdA11yKeyboardManager *manager)
 {
         GConfClient    *client;
@@ -645,11 +920,11 @@ set_gconf_from_server (GsdA11yKeyboardMa
                 /* sanity check: are keyboard shortcuts available? */
                 if (desc->ctrls->enabled_ctrls & XkbAccessXKeysMask) {
                         if (slowkeys_changed) {
-                                ax_slowkeys_warning_dialog_post (manager,
-                                                                 desc->ctrls->enabled_ctrls & XkbSlowKeysMask);
+                                ax_slowkeys_warning_post (manager,
+                                                          desc->ctrls->enabled_ctrls & XkbSlowKeysMask);
                         } else {
-                                ax_stickykeys_warning_dialog_post (manager,
-                                                                   desc->ctrls->enabled_ctrls & XkbStickyKeysMask);
+                                ax_stickykeys_warning_post (manager,
+                                                            desc->ctrls->enabled_ctrls & XkbStickyKeysMask);
                         }
                 }
         }
@@ -701,6 +976,7 @@ keyboard_callback (GConfClient          
                    GsdA11yKeyboardManager *manager)
 {
         set_server_from_gconf (manager, client);
+        maybe_show_status_icon (manager);
 }
 
 static void
@@ -761,7 +1037,11 @@ gsd_a11y_keyboard_manager_start (GsdA11y
         gdk_window_add_filter (NULL,
                                (GdkFilterFunc) cb_xkb_event_filter,
                                manager);
+
+        maybe_show_status_icon (manager);
+
         ret = TRUE;
+
  out:
         gnome_settings_profile_end (NULL);
         return ret;
@@ -774,6 +1054,8 @@ gsd_a11y_keyboard_manager_stop (GsdA11yK
 
         g_debug ("Stopping a11y_keyboard manager");
 
+        gtk_status_icon_set_visible (manager->priv->status_icon, FALSE);
+
         if (p->gconf_notify != 0) {
                 GConfClient *client = gconf_client_get_default ();
                 gconf_client_remove_dir (client, CONFIG_ROOT, NULL);
@@ -872,9 +1154,53 @@ gsd_a11y_keyboard_manager_class_init (Gs
 }
 
 static void
+on_preferences_dialog_response (GtkDialog              *dialog,
+                                int                     response,
+                                GsdA11yKeyboardManager *manager)
+{
+        g_signal_handlers_disconnect_by_func (dialog,
+                                              on_preferences_dialog_response,
+                                              manager);
+
+        gtk_widget_destroy (GTK_WIDGET (dialog));
+        manager->priv->preferences_dialog = NULL;
+}
+
+static void
+on_status_icon_activate (GtkStatusIcon          *status_icon,
+                         GsdA11yKeyboardManager *manager)
+{
+        if (manager->priv->preferences_dialog == NULL) {
+                manager->priv->preferences_dialog = gsd_a11y_preferences_dialog_new ();
+                g_signal_connect (manager->priv->preferences_dialog,
+                                  "response",
+                                  G_CALLBACK (on_preferences_dialog_response),
+                                  manager);
+
+                gtk_window_present (GTK_WINDOW (manager->priv->preferences_dialog));
+        } else {
+                g_signal_handlers_disconnect_by_func (manager->priv->preferences_dialog,
+                                                      on_preferences_dialog_response,
+                                                      manager);
+                gtk_widget_destroy (GTK_WIDGET (manager->priv->preferences_dialog));
+                manager->priv->preferences_dialog = NULL;
+        }
+}
+
+static void
 gsd_a11y_keyboard_manager_init (GsdA11yKeyboardManager *manager)
 {
         manager->priv = GSD_A11Y_KEYBOARD_MANAGER_GET_PRIVATE (manager);
+
+        manager->priv->status_icon = gtk_status_icon_new_from_icon_name ("preferences-desktop-accessibility");
+        g_signal_connect (manager->priv->status_icon,
+                          "activate",
+                          G_CALLBACK (on_status_icon_activate),
+                          manager);
+
+#ifdef HAVE_LIBNOTIFY
+        notify_init ("gnome-settings-daemon");
+#endif /* HAVE_LIBNOTIFY */
 }
 
 static void
Index: plugins/a11y-keyboard/gsd-a11y-preferences-dialog.glade
===================================================================
--- plugins/a11y-keyboard/gsd-a11y-preferences-dialog.glade	(revision 0)
+++ plugins/a11y-keyboard/gsd-a11y-preferences-dialog.glade	(revision 0)
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.4 on Wed Jul 30 17:12:34 2008 -->
+<glade-interface>
+  <widget class="GtkDialog" id="dialog1">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Assistive Technology Preferences</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="icon_name">preferences-desktop-accessibility</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkHBox" id="main_box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="border_width">5</property>
+            <property name="spacing">10</property>
+            <child>
+              <widget class="GtkImage" id="image1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="yalign">0</property>
+                <property name="icon_size">6</property>
+                <property name="icon_name">preferences-desktop-accessibility</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkVBox" id="vbox1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="spacing">10</property>
+                <child>
+                  <widget class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Enable features that make your computer easier to use:&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkVBox" id="vbox1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <widget class="GtkCheckButton" id="at_screen_keyboard_checkbutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Use on-screen _keyboard</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="at_screen_reader_checkbutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Use screen _reader (Speech Output)</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="at_screen_magnifier_checkbutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Use screen _magnifier</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="high_contrast_checkbutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Use more _contrast in colors (High Contrast)</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="sticky_keys_checkbutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">_Press keyboard shortcuts one key at a time (Sticky Keys)</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="bounce_keys_checkbutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">_Ignore duplicate keypresses (Bounce Keys)</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">5</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="slow_keys_checkbutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Press and _hold keys to accept them (Slow Keys)</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">6</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="large_print_checkbutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">_Use a larger font size (Large Print)</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">7</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+              </widget>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>
Index: configure.ac
===================================================================
--- configure.ac	(revision 409)
+++ configure.ac	(working copy)
@@ -48,6 +48,7 @@ GTK_REQUIRED_VERSION=2.10.0
 GCONF_REQUIRED_VERSION=2.6.1
 GIO_REQUIRED_VERSION=2.15.0
 GNOME_DESKTOP_REQUIRED_VERSION=2.23.5
+LIBNOTIFY_REQUIRED_VERSION=0.4.3
 
 EXTRA_COMPILE_WARNINGS(yes)
 
@@ -83,6 +84,21 @@ AC_PATH_PROG(GCONFTOOL, gconftool-2)
 AM_GCONF_SOURCE_2
 
 dnl ---------------------------------------------------------------------------
+dnl - Is a new enough libnotify available?
+dnl ---------------------------------------------------------------------------
+
+if $PKG_CONFIG --atleast-version $LIBNOTIFY_REQUIRED_VERSION libnotify; then
+   have_libnotify=yes
+   PKG_CHECK_MODULES(LIBNOTIFY, libnotify >= $LIBNOTIFY_REQUIRED_VERSION)
+   AC_SUBST(LIBNOTIFY_CFLAGS)
+   AC_SUBST(LIBNOTIFY_LIBS)
+   AC_DEFINE(HAVE_LIBNOTIFY, 1, [Building with libnotify support])
+else
+   have_libnotify=no
+fi
+AM_CONDITIONAL([HAVE_LIBNOTIFY], [test $have_libnotify = yes])
+
+dnl ---------------------------------------------------------------------------
 dnl - Check for D-Bus
 dnl ---------------------------------------------------------------------------
 
