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:
parent
e43f10c8ed
commit
6ea18136ac
@ -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 \
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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';
|
||||||
|
238
js/ui/status/accessibility.js
Normal file
238
js/ui/status/accessibility.js
Normal 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);
|
@ -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>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user