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
This commit is contained in:
Giovanni Campagna 2010-07-21 10:44:59 +02:00 committed by Dan Winship
parent e43f10c8ed
commit 6ea18136ac
6 changed files with 253 additions and 11 deletions

View File

@ -39,6 +39,7 @@ nobase_dist_js_DATA = \
ui/search.js \ ui/search.js \
ui/shellDBus.js \ ui/shellDBus.js \
ui/statusMenu.js \ ui/statusMenu.js \
ui/status/accessibility.js \
ui/telepathyClient.js \ ui/telepathyClient.js \
ui/tweener.js \ ui/tweener.js \
ui/windowAttentionHandler.js \ ui/windowAttentionHandler.js \

View File

@ -6,6 +6,8 @@ const Shell = imports.gi.Shell;
const St = imports.gi.St; const St = imports.gi.St;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Main = imports.ui.main; const Main = imports.ui.main;
const MagnifierDBus = imports.ui.magnifierDBus; const MagnifierDBus = imports.ui.magnifierDBus;
@ -112,6 +114,9 @@ Magnifier.prototype = {
// invisible. // invisible.
if (!activate) if (!activate)
this._xfixesCursor.show(); 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) { function ZoomRegion(magnifier, mouseRoot) {
this._init(magnifier, mouseRoot); this._init(magnifier, mouseRoot);

View File

@ -124,6 +124,7 @@ function start() {
placesManager = new PlaceDisplay.PlacesManager(); placesManager = new PlaceDisplay.PlacesManager();
overview = new Overview.Overview(); overview = new Overview.Overview();
chrome = new Chrome.Chrome(); chrome = new Chrome.Chrome();
magnifier = new Magnifier.Magnifier();
panel = new Panel.Panel(); panel = new Panel.Panel();
wm = new WindowManager.WindowManager(); wm = new WindowManager.WindowManager();
messageTray = new MessageTray.MessageTray(); messageTray = new MessageTray.MessageTray();
@ -173,9 +174,6 @@ function start() {
global.stage.connect('captured-event', _globalKeyPressHandler); global.stage.connect('captured-event', _globalKeyPressHandler);
// Install magnifier.
magnifier = new Magnifier.Magnifier();
// Perform initial relayout here // Perform initial relayout here
_relayout(); _relayout();

View File

@ -30,21 +30,15 @@ const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
const SPINNER_UPDATE_TIMEOUT = 130; const SPINNER_UPDATE_TIMEOUT = 130;
const SPINNER_SPEED = 0.02; 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 = { const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
'bluetooth-applet': 'bluetooth', 'bluetooth-applet': 'bluetooth',
'gnome-volume-control-applet': 'volume', 'gnome-volume-control-applet': 'volume',
'nm-applet': 'network', 'nm-applet': 'network',
'gnome-power-manager': 'battery' '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 = { const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
'a11y': imports.ui.status.accessibility.ATIndicator
}; };
const CLOCK_FORMAT_KEY = 'format'; const CLOCK_FORMAT_KEY = 'format';

View File

@ -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);

View File

@ -158,6 +158,10 @@
</dependencies> </dependencies>
</autotools> </autotools>
<autotools id="gsettings-desktop-schemas">
<branch repo="git.gnome.org" module="gsettings-desktop-schemas" />
</autotools>
<autotools id="gnome-shell"> <autotools id="gnome-shell">
<branch repo="git.gnome.org" module="gnome-shell"/> <branch repo="git.gnome.org" module="gnome-shell"/>
<dependencies> <dependencies>
@ -168,6 +172,7 @@
<dep package="gconf"/> <dep package="gconf"/>
<dep package="glib"/> <dep package="glib"/>
<dep package="gnome-desktop-3"/> <dep package="gnome-desktop-3"/>
<dep package="gsettings-desktop-schemas"/>
</dependencies> </dependencies>
</autotools> </autotools>