[gnome-shell] Add Universal Access status indicator



commit 6ea18136acdfedee9243bdfe9a17334263ebd7d3
Author: Giovanni Campagna <scampa giovanni gmail com>
Date:   Wed Jul 21 10:44:59 2010 +0200

    Add Universal Access status indicator
    
    Introduce the Universal Access status indicator as designed, modeled
    after the similar UI provided by g-s-d. This indicator allows the user
    to change rapidly the keyboard and mouse behaviour (sticky keys, slow
    keys, bounce keys, mouse keys), as well as the enabled ATs (magnifier,
    screen reader, screen keyboard) and the HighContrast Gtk theme.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=624916

 js/Makefile.am                  |    1 +
 js/ui/magnifier.js              |    6 +
 js/ui/main.js                   |    4 +-
 js/ui/panel.js                  |   10 +--
 js/ui/status/accessibility.js   |  238 +++++++++++++++++++++++++++++++++++++++
 tools/build/gnome-shell.modules |    5 +
 6 files changed, 253 insertions(+), 11 deletions(-)
---
diff --git a/js/Makefile.am b/js/Makefile.am
index f0efa29..6412c71 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -39,6 +39,7 @@ nobase_dist_js_DATA = 	\
 	ui/search.js		\
 	ui/shellDBus.js		\
 	ui/statusMenu.js	\
+	ui/status/accessibility.js	\
 	ui/telepathyClient.js	\
 	ui/tweener.js		\
 	ui/windowAttentionHandler.js	\
diff --git a/js/ui/magnifier.js b/js/ui/magnifier.js
index 9f42ae8..e572961 100644
--- a/js/ui/magnifier.js
+++ b/js/ui/magnifier.js
@@ -6,6 +6,8 @@ const Shell = imports.gi.Shell;
 const St = imports.gi.St;
 const Lang = imports.lang;
 const Mainloop = imports.mainloop;
+const Signals = imports.signals;
+
 const Main = imports.ui.main;
 const MagnifierDBus = imports.ui.magnifierDBus;
 
@@ -112,6 +114,9 @@ Magnifier.prototype = {
         // invisible.
         if (!activate)
             this._xfixesCursor.show();
+
+        // Notify interested parties of this change
+        this.emit('active-changed', activate);
     },
 
     /**
@@ -560,6 +565,7 @@ Magnifier.prototype = {
         }
     }
 };
+Signals.addSignalMethods(Magnifier.prototype);
 
 function ZoomRegion(magnifier, mouseRoot) {
     this._init(magnifier, mouseRoot);
diff --git a/js/ui/main.js b/js/ui/main.js
index c409642..a94ef93 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -124,6 +124,7 @@ function start() {
     placesManager = new PlaceDisplay.PlacesManager();
     overview = new Overview.Overview();
     chrome = new Chrome.Chrome();
+    magnifier = new Magnifier.Magnifier();
     panel = new Panel.Panel();
     wm = new WindowManager.WindowManager();
     messageTray = new MessageTray.MessageTray();
@@ -173,9 +174,6 @@ function start() {
 
     global.stage.connect('captured-event', _globalKeyPressHandler);
 
-    // Install magnifier.
-    magnifier = new Magnifier.Magnifier();
-
     // Perform initial relayout here
     _relayout();
 
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 7678341..1abcad0 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -30,21 +30,15 @@ const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
 const SPINNER_UPDATE_TIMEOUT = 130;
 const SPINNER_SPEED = 0.02;
 
-const STANDARD_TRAY_ICON_ORDER = ['keyboard', 'volume', 'bluetooth', 'network', 'battery'];
+const STANDARD_TRAY_ICON_ORDER = ['a11y', 'keyboard', 'volume', 'bluetooth', 'network', 'battery'];
 const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
     'bluetooth-applet': 'bluetooth',
     'gnome-volume-control-applet': 'volume',
     'nm-applet': 'network',
     'gnome-power-manager': 'battery'
 };
-
-/* Holds constructors for shell-implemented SystemStatusButtons
- * example:
- * const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
- *     'network': imports.ui.network.NMApplet
- * };
- */
 const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
+    'a11y': imports.ui.status.accessibility.ATIndicator
 };
 
 const CLOCK_FORMAT_KEY        = 'format';
diff --git a/js/ui/status/accessibility.js b/js/ui/status/accessibility.js
new file mode 100644
index 0000000..4644f9f
--- /dev/null
+++ b/js/ui/status/accessibility.js
@@ -0,0 +1,238 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const DBus = imports.dbus;
+const GConf = imports.gi.GConf;
+const Gio = imports.gi.Gio;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Shell = imports.gi.Shell;
+const Signals = imports.signals;
+const St = imports.gi.St;
+
+const Main = imports.ui.main;
+const PanelMenu = imports.ui.panelMenu;
+const PopupMenu = imports.ui.popupMenu;
+
+const Gettext = imports.gettext.domain('gnome-shell');
+const _ = Gettext.gettext;
+
+const KEY_A11Y_DIR            = "/desktop/gnome/accessibility";
+const KEY_STICKY_KEYS_ENABLED = KEY_A11Y_DIR + "/keyboard/stickykeys_enable";
+const KEY_BOUNCE_KEYS_ENABLED = KEY_A11Y_DIR + "/keyboard/bouncekeys_enable";
+const KEY_SLOW_KEYS_ENABLED   = KEY_A11Y_DIR + "/keyboard/slowkeys_enable";
+const KEY_MOUSE_KEYS_ENABLED  = KEY_A11Y_DIR + "/keyboard/mousekeys_enable";
+
+const AT_SCREEN_KEYBOARD_SCHEMA = "org.gnome.desktop.default-applications.at.mobility";
+const AT_SCREEN_READER_SCHEMA   = "org.gnome.desktop.default-applications.at.visual";
+
+const KEY_FONT_DPI    = "/desktop/gnome/font_rendering/dpi";
+const DPI_LOW_REASONABLE_VALUE  = 50;
+const DPI_HIGH_REASONABLE_VALUE = 500;
+
+const DPI_FACTOR_LARGE   = 1.25;
+const DPI_FACTOR_LARGER  = 1.5;
+const DPI_FACTOR_LARGEST = 2.0;
+const DPI_DEFAULT        = 96;
+
+const KEY_META_DIR       = "/apps/metacity/general";
+const KEY_VISUAL_BELL = KEY_META_DIR + "/visual_bell";
+
+const DESKTOP_INTERFACE_SCHEMA = "org.gnome.desktop.interface";
+const KEY_GTK_THEME      = "gtk-theme";
+const KEY_ICON_THEME     = "icon-theme";
+
+const HIGH_CONTRAST_THEME = "HighContrast";
+
+function getDPIFromX() {
+    let screen = global.get_gdk_screen();
+    if (screen) {
+        let width_dpi = (screen.get_width() / (screen.get_width_mm() / 25.4));
+        let height_dpi = (screen.get_height() / (screen.get_height_mm() / 25.4));
+        if (width_dpi < DPI_LOW_REASONABLE_VALUE
+            || width_dpi > DPI_HIGH_REASONABLE_VALUE
+            || height_dpi < DPI_LOW_REASONABLE_VALUE
+            || height_dpi > DPI_HIGH_REASONABLE_VALUE)
+            return DPI_DEFAULT;
+        else
+            return (width_dpi + height_dpi) / 2;
+    }
+    return DPI_DEFAULT;
+}
+
+function ATIndicator() {
+    this._init.apply(this, arguments);
+}
+
+ATIndicator.prototype = {
+    __proto__: PanelMenu.SystemStatusButton.prototype,
+
+    _init: function() {
+        PanelMenu.SystemStatusButton.prototype._init.call(this, 'preferences-desktop-accessibility', null);
+
+        let client = GConf.Client.get_default();
+        client.add_dir(KEY_A11Y_DIR, GConf.ClientPreloadType.PRELOAD_ONELEVEL, null);
+        client.notify_add(KEY_A11Y_DIR, Lang.bind(this, this._keyChanged), null, null);
+        client.add_dir(KEY_META_DIR, GConf.ClientPreloadType.PRELOAD_ONELEVEL, null);
+        client.notify_add(KEY_META_DIR, Lang.bind(this, this._keyChanged), null, null);
+
+        let highContrast = this._buildHCItem();
+        this.menu.addMenuItem(highContrast);
+
+        let magnifier = this._buildMagItem();
+        this.menu.addMenuItem(magnifier);
+
+        let textZoom = this._buildFontItem(client);
+        this.menu.addMenuItem(textZoom);
+
+        let screenReader = this._buildItem(_("Screen reader"), AT_SCREEN_READER_SCHEMA, 'startup');
+        this.menu.addMenuItem(screenReader);
+
+        let screenKeyboard = this._buildItem(_("Screen keyboard"), AT_SCREEN_KEYBOARD_SCHEMA, 'startup');
+        this.menu.addMenuItem(screenKeyboard);
+
+        let visualBell = this._buildItemGConf(_("Visual alerts"), client, KEY_VISUAL_BELL);
+        this.menu.addMenuItem(visualBell);
+
+        let stickyKeys = this._buildItemGConf(_("Sticky keys"), client, KEY_STICKY_KEYS_ENABLED);
+        this.menu.addMenuItem(stickyKeys);
+
+        let slowKeys = this._buildItemGConf(_("Slow keys"), client, KEY_SLOW_KEYS_ENABLED);
+        this.menu.addMenuItem(slowKeys);
+
+        let bounceKeys = this._buildItemGConf(_("Bounce keys"), client, KEY_BOUNCE_KEYS_ENABLED);
+        this.menu.addMenuItem(bounceKeys);
+
+        let mouseKeys = this._buildItemGConf(_("Mouse keys"), client, KEY_MOUSE_KEYS_ENABLED);
+        this.menu.addMenuItem(mouseKeys);
+
+        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+        this.menu.addAction(_("Universal access settings"), function() {
+            let p = new Shell.Process({ args: ['gnome-control-center','universal-access'] });
+            p.run();
+        });
+    },
+
+    _buildItemExtended: function(string, initial_value, writable, on_set) {
+        let widget = new PopupMenu.PopupSwitchMenuItem(string, initial_value);
+        if (!writable)
+            widget.actor.reactive = false;
+        else
+            widget.connect('toggled', function(item) {
+                on_set(item.state);
+            });
+        return widget;
+    },
+
+    _buildItemGConf: function(string, client, key) {
+        function on_get() {
+            return client.get_bool(key);
+        }
+        let widget = this._buildItemExtended(string,
+            client.get_bool(key),
+            client.key_is_writable(key),
+            function(enabled) {
+                client.set_bool(key, enabled);
+            });
+        this.connect('gconf-changed', function() {
+            widget.setToggleState(client.get_bool(key));
+        });
+        return widget;
+    },
+
+    _buildItem: function(string, schema, key) {
+        let settings = new Gio.Settings({ schema: schema });
+        let widget = this._buildItemExtended(string,
+            settings.get_boolean(key),
+            settings.is_writable(key),
+            function(enabled) {
+                return settings.set_boolean(key, enabled);
+            });
+        settings.connect('changed::'+key, function() {
+            widget.setToggleState(settings.get_boolean(key));
+        });
+        return widget;
+    },
+
+    _buildHCItem: function() {
+        let settings = new Gio.Settings({ schema: DESKTOP_INTERFACE_SCHEMA });
+        let gtkTheme = settings.get_string(KEY_GTK_THEME);
+        let iconTheme = settings.get_string(KEY_ICON_THEME);
+        let hasHC = (gtkTheme == HIGH_CONTRAST_THEME);
+        let highContrast = this._buildItemExtended(
+            _("High Contrast"),
+            hasHC,
+            settings.is_writable(KEY_GTK_THEME) && settings.is_writable(KEY_ICON_THEME),
+            function (enabled) {
+                if (enabled) {
+                    settings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
+                    settings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME);
+                } else {
+                    settings.set_string(KEY_GTK_THEME, gtkTheme);
+                    settings.set_string(KEY_ICON_THEME, iconTheme);
+                }
+            });
+        settings.connect('changed::' + KEY_GTK_THEME, function() {
+            let value = settings.get_string(KEY_GTK_THEME);
+            if (value == HIGH_CONTRAST_THEME) {
+                highContrast.setToggleState(true);
+            } else {
+                highContrast.setToggleState(false);
+                gtkTheme = value;
+            }
+        });
+        settings.connect('changed::' + KEY_ICON_THEME, function() {
+            let value = settings.get_string(KEY_ICON_THEME);
+            if (value != HIGH_CONTRAST_THEME)
+                iconTheme = value;
+        });
+        return highContrast;
+    },
+
+    _buildFontItem: function(client) {
+        let first_gconf_value = client.get_without_default(KEY_FONT_DPI);
+        let default_value = getDPIFromX();
+        let first_value = first_gconf_value ? first_gconf_value.get_float() : default_value;
+        log('default_value = %f, first_value = %f'.format(default_value,first_value));
+        function on_get() {
+            let u_dpi = client.get_float(KEY_FONT_DPI);
+            let x_dpi = getDPIFromX();
+            return (u_dpi - (DPI_FACTOR_LARGE * x_dpi) > -1);
+        }
+        let initial_setting = on_get();
+        let widget = this._buildItemExtended(_("Large text"),
+            initial_setting,
+            client.key_is_writable(KEY_FONT_DPI),
+            function (enabled) {
+                if (enabled)
+                    client.set_float(KEY_FONT_DPI, DPI_FACTOR_LARGE * getDPIFromX());
+                else
+                    client.set_float(KEY_FONT_DPI, (first_value && !initial_setting) ? first_value : default_value);
+            });
+        this.connect('gconf-changed', function() {
+            let active = on_get();
+            if (!active)
+                // setting was modified manually, update it
+                first_value = client.get_value(KEY_FONT_DPI);
+            widget.setToggleState(on_get());
+        });
+        return widget;
+    },
+
+    _buildMagItem: function() {
+        let mag = Main.magnifier;
+        let widget = this._buildItemExtended(_("Zoom screen"),
+            mag.isActive(),
+            true,
+            Lang.bind(mag, mag.setActive));
+        mag.connect('active-changed', function(magnifier, active) {
+            widget.setToggleState(active);
+        });
+        return widget;
+    },
+
+    _keyChanged: function() {
+        this.emit('gconf-changed');
+    }
+};
+Signals.addSignalMethods(ATIndicator.prototype);
diff --git a/tools/build/gnome-shell.modules b/tools/build/gnome-shell.modules
index 478b854..7d6f076 100644
--- a/tools/build/gnome-shell.modules
+++ b/tools/build/gnome-shell.modules
@@ -158,6 +158,10 @@
     </dependencies>
   </autotools>
 
+  <autotools id="gsettings-desktop-schemas">
+    <branch repo="git.gnome.org" module="gsettings-desktop-schemas" />
+  </autotools>
+
   <autotools id="gnome-shell">
     <branch repo="git.gnome.org" module="gnome-shell"/>
     <dependencies>
@@ -168,6 +172,7 @@
         <dep package="gconf"/>
         <dep package="glib"/>
         <dep package="gnome-desktop-3"/>
+        <dep package="gsettings-desktop-schemas"/>
     </dependencies>
   </autotools>
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]