[gnome-shell] accessibility: Add pointer accessibility support
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] accessibility: Add pointer accessibility support
- Date: Thu, 6 Jun 2019 11:42:43 +0000 (UTC)
commit 5ace4682bf325e62f03b2f94600e281c622c67a3
Author: Olivier Fourdan <ofourdan redhat com>
Date: Wed Mar 20 17:46:12 2019 +0100
accessibility: Add pointer accessibility support
Adds the UI part for the pointer accessibility features.
The various timeouts running are notified using a pie-timer showing
under the pointer.
For dwell-click type selection, we use a drop-down menu. Users can
use the dwell-click to select the next type of dwell click to be
emitted.
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/474
data/theme/gnome-shell-sass/_common.scss | 9 +++
js/js-resources.gresource.xml | 2 +
js/ui/main.js | 4 ++
js/ui/panel.js | 1 +
js/ui/pointerA11yTimeout.js | 104 +++++++++++++++++++++++++++++++
js/ui/sessionMode.js | 6 +-
js/ui/status/dwellClick.js | 86 +++++++++++++++++++++++++
po/POTFILES.in | 1 +
8 files changed, 210 insertions(+), 3 deletions(-)
---
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
index c8c53d557..50bfc6650 100644
--- a/data/theme/gnome-shell-sass/_common.scss
+++ b/data/theme/gnome-shell-sass/_common.scss
@@ -1195,6 +1195,15 @@ StScrollBar {
}
}
+// Pointer accessibility notifications
+.pie-timer {
+ width: 60px;
+ height: 60px;
+ -pie-border-width: 3px;
+ -pie-border-color: $selected_bg_color;
+ -pie-background-color: lighten(transparentize($selected_bg_color, 0.7), 40%);
+}
+
/* NETWORK DIALOGS */
.nm-dialog {
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index 7807cce9d..b5348ddcb 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -82,6 +82,7 @@
<file>ui/pageIndicators.js</file>
<file>ui/panel.js</file>
<file>ui/panelMenu.js</file>
+ <file>ui/pointerA11yTimeout.js</file>
<file>ui/pointerWatcher.js</file>
<file>ui/popupMenu.js</file>
<file>ui/remoteSearch.js</file>
@@ -122,6 +123,7 @@
<file>ui/status/accessibility.js</file>
<file>ui/status/brightness.js</file>
+ <file>ui/status/dwellClick.js</file>
<file>ui/status/location.js</file>
<file>ui/status/keyboard.js</file>
<file>ui/status/nightLight.js</file>
diff --git a/js/ui/main.js b/js/ui/main.js
index b3cd69283..c01be9882 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -38,6 +38,7 @@ const Magnifier = imports.ui.magnifier;
const XdndHandler = imports.ui.xdndHandler;
const KbdA11yDialog = imports.ui.kbdA11yDialog;
const LocatePointer = imports.ui.locatePointer;
+const PointerA11yTimeout = imports.ui.pointerA11yTimeout;
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
const STICKY_KEYS_ENABLE = 'stickykeys-enable';
@@ -82,6 +83,7 @@ let _cssStylesheet = null;
let _a11ySettings = null;
let _themeResource = null;
let _oskResource = null;
+let pointerA11yTimeout = null;
function _sessionUpdated() {
if (sessionMode.isPrimary)
@@ -189,6 +191,8 @@ function _initializeUI() {
layoutManager.init();
overview.init();
+ pointerA11yTimeout = new PointerA11yTimeout.PointerA11yTimeout();
+
_a11ySettings = new Gio.Settings({ schema_id: A11Y_SCHEMA });
global.display.connect('overlay-key', () => {
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 6522e9099..ef08b1aad 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -817,6 +817,7 @@ const PANEL_ITEM_IMPLEMENTATIONS = {
'dateMenu': imports.ui.dateMenu.DateMenuButton,
'a11y': imports.ui.status.accessibility.ATIndicator,
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
+ 'dwellClick': imports.ui.status.dwellClick.DwellClickIndicator,
};
var Panel = GObject.registerClass(
diff --git a/js/ui/pointerA11yTimeout.js b/js/ui/pointerA11yTimeout.js
new file mode 100644
index 000000000..d9309415b
--- /dev/null
+++ b/js/ui/pointerA11yTimeout.js
@@ -0,0 +1,104 @@
+const { Clutter, GLib, GObject, Meta, St } = imports.gi;
+const Tweener = imports.ui.tweener;
+const Main = imports.ui.main;
+const Cairo = imports.cairo;
+
+const ANIMATION_STEPS = 36.;
+
+var PieTimer = GObject.registerClass(
+class PieTimer extends St.DrawingArea {
+ _init() {
+ this._x = 0;
+ this._y = 0;
+ this._startTime = 0;
+ this._duration = 0;
+ super._init( { style_class: 'pie-timer',
+ visible: false,
+ can_focus: false,
+ reactive: false });
+ }
+
+ vfunc_repaint() {
+ let node = this.get_theme_node();
+ let backgroundColor = node.get_color('-pie-background-color');
+ let borderColor = node.get_color('-pie-border-color');
+ let borderWidth = node.get_length('-pie-border-width');
+ let [width, height] = this.get_surface_size();
+ let radius = Math.min(width / 2, height / 2);
+
+ let currentTime = GLib.get_monotonic_time() / 1000.0;
+ let ellapsed = currentTime - this._startTime;
+ let angle = (ellapsed / this._duration) * 2 * Math.PI;
+ let startAngle = 3 * Math.PI / 2;
+ let endAngle = startAngle + angle;
+
+ let cr = this.get_context();
+ cr.setLineCap(Cairo.LineCap.ROUND);
+ cr.setLineJoin(Cairo.LineJoin.ROUND);
+ cr.translate(width / 2, height / 2);
+
+ cr.moveTo(0, 0);
+ cr.arc(0, 0, radius - borderWidth, startAngle, endAngle);
+ cr.lineTo(0, 0);
+ cr.closePath();
+
+ cr.setLineWidth(0);
+ Clutter.cairo_set_source_color(cr, backgroundColor);
+ cr.fillPreserve();
+
+ cr.setLineWidth(borderWidth);
+ Clutter.cairo_set_source_color(cr, borderColor);
+ cr.stroke();
+
+ cr.$dispose();
+ }
+
+ start(x, y, duration) {
+ Tweener.removeTweens(this);
+
+ this.x = x - this.width / 2;
+ this.y = y - this.height / 2;
+ this.show();
+ Main.uiGroup.set_child_above_sibling(this, null);
+
+ this._startTime = GLib.get_monotonic_time() / 1000.0;
+ this._duration = duration;
+
+ Tweener.addTween(this,
+ { opacity: 255,
+ time: duration / 1000,
+ transition: 'easeOutQuad',
+ onUpdateScope: this,
+ onUpdate() { this.queue_repaint() },
+ onCompleteScope: this,
+ onComplete() { this.stop(); }
+ });
+ }
+
+ stop() {
+ Tweener.removeTweens(this);
+ this.hide();
+ }
+});
+
+var PointerA11yTimeout = class PointerA11yTimeout {
+ constructor() {
+ let manager = Clutter.DeviceManager.get_default();
+ let pieTimer = new PieTimer();
+
+ Main.uiGroup.add_actor(pieTimer);
+
+ manager.connect('ptr-a11y-timeout-started', (manager, device, type, timeout) => {
+ let [x, y, mods] = global.get_pointer();
+ pieTimer.start(x, y, timeout);
+ if (type == Clutter.PointerA11yTimeoutType.GESTURE)
+ global.display.set_cursor(Meta.Cursor.CROSSHAIR);
+ });
+
+ manager.connect('ptr-a11y-timeout-stopped', (manager, device, type) => {
+ pieTimer.stop();
+ if (type == Clutter.PointerA11yTimeoutType.GESTURE)
+ global.display.set_cursor(Meta.Cursor.DEFAULT);
+ });
+ }
+};
diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js
index 1f3e23b7a..ae6c64dd3 100644
--- a/js/ui/sessionMode.js
+++ b/js/ui/sessionMode.js
@@ -48,7 +48,7 @@ const _modes = {
panel: {
left: [],
center: ['dateMenu'],
- right: ['a11y', 'keyboard', 'aggregateMenu']
+ right: ['dwellClick', 'a11y', 'keyboard', 'aggregateMenu']
},
panelStyle: 'login-screen'
},
@@ -73,7 +73,7 @@ const _modes = {
panel: {
left: [],
center: [],
- right: ['a11y', 'keyboard', 'aggregateMenu']
+ right: ['dwellClick', 'a11y', 'keyboard', 'aggregateMenu']
},
panelStyle: 'unlock-screen'
},
@@ -101,7 +101,7 @@ const _modes = {
panel: {
left: ['activities', 'appMenu'],
center: ['dateMenu'],
- right: ['a11y', 'keyboard', 'aggregateMenu']
+ right: ['dwellClick', 'a11y', 'keyboard', 'aggregateMenu']
}
}
};
diff --git a/js/ui/status/dwellClick.js b/js/ui/status/dwellClick.js
new file mode 100644
index 000000000..cb9f331f3
--- /dev/null
+++ b/js/ui/status/dwellClick.js
@@ -0,0 +1,86 @@
+const { Clutter, Gio, GLib, GObject, St } = imports.gi;
+const Mainloop = imports.mainloop;
+
+const PanelMenu = imports.ui.panelMenu;
+const PopupMenu = imports.ui.popupMenu;
+
+const MOUSE_A11Y_SCHEMA = 'org.gnome.desktop.a11y.mouse';
+const KEY_DWELL_CLICK_ENABLED = 'dwell-click-enabled';
+const KEY_DWELL_MODE = 'dwell-mode';
+const DWELL_MODE_WINDOW = 'window';
+const DWELL_CLICK_MODES = {
+ primary: {
+ name: _("Single Click"),
+ icon: 'pointer-primary-click-symbolic',
+ type: Clutter.PointerA11yDwellClickType.PRIMARY
+ },
+ double: {
+ name: _("Double Click"),
+ icon: 'pointer-double-click-symbolic',
+ type: Clutter.PointerA11yDwellClickType.DOUBLE
+ },
+ drag: {
+ name: _("Drag"),
+ icon: 'pointer-drag-symbolic',
+ type: Clutter.PointerA11yDwellClickType.DRAG
+ },
+ secondary: {
+ name: _("Secondary Click"),
+ icon: 'pointer-secondary-click-symbolic',
+ type: Clutter.PointerA11yDwellClickType.SECONDARY
+ },
+};
+
+var DwellClickIndicator = GObject.registerClass(
+class DwellClickIndicator extends PanelMenu.Button {
+ _init() {
+ super._init(0.0, _("Dwell Click"));
+
+ this._hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
+ this._icon = new St.Icon({ style_class: 'system-status-icon',
+ icon_name: 'pointer-primary-click-symbolic' });
+ this._hbox.add_child(this._icon);
+ this._hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
+
+ this.add_child(this._hbox);
+
+ this._a11ySettings = new Gio.Settings({ schema_id: MOUSE_A11Y_SCHEMA });
+ this._a11ySettings.connect('changed::' + KEY_DWELL_CLICK_ENABLED,
this._syncMenuVisibility.bind(this));
+ this._a11ySettings.connect('changed::' + KEY_DWELL_MODE, this._syncMenuVisibility.bind(this));
+
+ this._deviceManager = Clutter.DeviceManager.get_default();
+ this._deviceManager.connect('ptr-a11y-dwell-click-type-changed', this._updateClickType.bind(this));
+
+ this._addDwellAction(DWELL_CLICK_MODES.primary);
+ this._addDwellAction(DWELL_CLICK_MODES.double);
+ this._addDwellAction(DWELL_CLICK_MODES.drag);
+ this._addDwellAction(DWELL_CLICK_MODES.secondary);
+
+ this._setClickType(DWELL_CLICK_MODES.primary);
+ this._syncMenuVisibility();
+ }
+
+ _syncMenuVisibility() {
+ this.visible =
+ (this._a11ySettings.get_boolean(KEY_DWELL_CLICK_ENABLED) &&
+ this._a11ySettings.get_string(KEY_DWELL_MODE) == DWELL_MODE_WINDOW);
+
+ return GLib.SOURCE_REMOVE;
+ }
+
+ _addDwellAction(mode) {
+ this.menu.addAction(mode.name, this._setClickType.bind(this, mode), mode.icon);
+ }
+
+ _updateClickType(manager, click_type) {
+ for (let mode in DWELL_CLICK_MODES) {
+ if (DWELL_CLICK_MODES[mode].type == click_type)
+ this._icon.icon_name = DWELL_CLICK_MODES[mode].icon;
+ }
+ }
+
+ _setClickType(mode) {
+ this._deviceManager.set_pointer_a11y_dwell_click_type(mode.type);
+ this._icon.icon_name = mode.icon;
+ }
+});
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 43ea408ac..a7b216710 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -54,6 +54,7 @@ js/ui/shellMountOperation.js
js/ui/status/accessibility.js
js/ui/status/bluetooth.js
js/ui/status/brightness.js
+js/ui/status/dwellClick.js
js/ui/status/keyboard.js
js/ui/status/location.js
js/ui/status/network.js
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]