summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2018-05-25 11:35:49 +0200
committerCarlos Garnacho <carlosg@gnome.org>2018-05-25 11:57:22 +0200
commit7d1d970a5c7827b0b528e50433af8cec663f2119 (patch)
tree660ec6780ee68c61a963fad71f403f4be0ede679
parent86bd5b281d5000547c928c143b4225f11178c909 (diff)
downloadgnome-shell-wip/carlosg/osk-focus-tracking.tar.gz
keyboard: Implement standalone FocusTrackerwip/carlosg/osk-focus-tracking
And stop using FocusCaretTracker for caret position purposes. This new object uses 1) the text-input protocol in wayland and 2) Info from IBusPanelService for X11 (which is meant to work for XIM too). This drops the usage of AtspiEventListener for OSK purposes, which is best to avoid.
-rw-r--r--js/misc/ibusManager.js5
-rw-r--r--js/ui/keyboard.js233
2 files changed, 115 insertions, 123 deletions
diff --git a/js/misc/ibusManager.js b/js/misc/ibusManager.js
index 782b9ad28..6452e492f 100644
--- a/js/misc/ibusManager.js
+++ b/js/misc/ibusManager.js
@@ -115,6 +115,11 @@ var IBusManager = new Lang.Class({
object_path: IBus.PATH_PANEL });
this._candidatePopup.setPanelService(this._panelService);
this._panelService.connect('update-property', this._updateProperty.bind(this));
+ this._panelService.connect('set-cursor-location', (ps, x, y, w, h) => {
+ let cursorLocation = { x, y, width: w, height: h };
+ this.emit('set-cursor-location', cursorLocation);
+ });
+
try {
// IBus versions older than 1.5.10 have a bug which
// causes spurious set-content-type emissions when
diff --git a/js/ui/keyboard.js b/js/ui/keyboard.js
index e13c7b724..9a12db667 100644
--- a/js/ui/keyboard.js
+++ b/js/ui/keyboard.js
@@ -1,6 +1,5 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-const FocusCaretTracker = imports.ui.focusCaretTracker;
const Atspi = imports.gi.Atspi;
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
@@ -13,6 +12,7 @@ const Signals = imports.signals;
const St = imports.gi.St;
const InputSourceManager = imports.ui.status.keyboard;
+const IBusManager = imports.misc.ibusManager;
const BoxPointer = imports.ui.boxpointer;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
@@ -261,6 +261,7 @@ var Key = new Lang.Class({
this._extended_keyboard = null;
this._pressTimeoutId = 0;
this._capturedPress = false;
+
this._capturedEventId = 0;
this._unmapId = 0;
this._longPress = false;
@@ -484,6 +485,71 @@ var KeyboardModel = new Lang.Class({
}
});
+var FocusTracker = new Lang.Class({
+ Name: 'FocusTracker',
+
+ _init() {
+ this._currentWindow = null;
+ this._currentWindowPositionId = 0;
+
+ global.screen.get_display().connect('notify::focus-window', () => {
+ this._setCurrentWindow(global.screen.get_display().focus_window);
+ this.emit('window-changed', this._currentWindow);
+ });
+
+ /* Valid for wayland clients */
+ Main.inputMethod.connect('cursor-location-changed', (o, rect) => {
+ let newRect = { x: rect.get_x(), y: rect.get_y(), width: rect.get_width(), height: rect.get_height() };
+ this._setCurrentRect(newRect);
+ });
+
+ this._ibusManager = IBusManager.getIBusManager();
+ this._ibusManager.connect('set-cursor-location', (manager, rect) => {
+ /* Valid for X11 clients only */
+ if (Main.inputMethod.currentFocus)
+ return;
+
+ this._setCurrentRect(rect);
+ });
+ },
+
+ get currentWindow() {
+ return this._currentWindow;
+ },
+
+ _setCurrentWindow(window) {
+ if (this._currentWindow)
+ this._currentWindow.disconnect(this._currentWindowPositionId);
+
+ this._currentWindow = window;
+ if (window) {
+ this._currentWindowPositionId = this._currentWindow.connect('position-changed', () => {
+ if (global.display.get_grab_op() == Meta.GrabOp.NONE)
+ this.emit('position-changed');
+ else
+ this.emit('reset');
+ });
+ }
+ },
+
+ _setCurrentRect(rect) {
+ let frameRect = this._currentWindow.get_frame_rect();
+ rect.x -= frameRect.x;
+ rect.y -= frameRect.y;
+
+ this._rect = rect;
+ this.emit('position-changed');
+ },
+
+ getCurrentRect() {
+ let frameRect = this._currentWindow.get_frame_rect();
+ let rect = { x: this._rect.x + frameRect.x, y: this._rect.y + frameRect.y, width: this._rect.width, height: this._rect.height };
+
+ return rect;
+ }
+});
+Signals.addSignalMethods(FocusTracker.prototype);
+
var Keyboard = new Lang.Class({
Name: 'Keyboard',
@@ -491,15 +557,10 @@ var Keyboard = new Lang.Class({
this.actor = null;
this._focusInExtendedKeys = false;
- this._focusCaretTracker = new FocusCaretTracker.FocusCaretTracker();
- this._focusCaretTracker.connect('focus-changed', this._onFocusChanged.bind(this));
- this._focusCaretTracker.connect('caret-moved', this._onCaretMoved.bind(this));
this._languagePopup = null;
- this._currentAccessible = null;
- this._caretTrackingEnabled = false;
- this._updateCaretPositionId = 0;
this._currentFocusWindow = null;
- this._originalWindowY = null;
+ this._animFocusedWindow = null;
+ this._delayedAnimFocusWindow = null;
this._enableKeyboard = false; // a11y settings value
this._enabled = false; // enabled state (by setting or device type)
@@ -510,6 +571,14 @@ var Keyboard = new Lang.Class({
this._lastDeviceId = null;
this._suggestions = null;
+ this._focusTracker = new FocusTracker();
+ this._focusTracker.connect('position-changed', this._onFocusPositionChanged.bind(this));
+ this._focusTracker.connect('reset', () => {
+ this._delayedAnimFocusWindow = null;
+ this._animFocusedWindow = null;
+ this._oskFocusWindow = null;
+ });
+
Meta.get_backend().connect('last-device-changed',
(backend, deviceId) => {
let manager = Clutter.DeviceManager.get_default();
@@ -532,102 +601,15 @@ var Keyboard = new Lang.Class({
this._keyboardRestingId = 0;
Main.layoutManager.connect('monitors-changed', this._relayout.bind(this));
- //Main.inputMethod.connect('cursor-location-changed', (o, rect) => {
- // if (this._keyboardVisible) {
- // let currentWindow = global.screen.get_display().focus_window;
- // this.setCursorLocation(currentWindow, rect.get_x(), rect.get_y(),
- // rect.get_width(), rect.get_height());
- // }
- //});
},
get visible() {
return this._keyboardVisible;
},
- _setCaretTrackerEnabled(enabled) {
- if (this._caretTrackingEnabled == enabled)
- return;
-
- this._caretTrackingEnabled = enabled;
-
- if (enabled) {
- this._focusCaretTracker.registerFocusListener();
- this._focusCaretTracker.registerCaretListener();
- } else {
- this._focusCaretTracker.deregisterFocusListener();
- this._focusCaretTracker.deregisterCaretListener();
- }
- },
-
- _updateCaretPosition(accessible) {
- if (this._updateCaretPositionId)
- GLib.source_remove(this._updateCaretPositionId);
- if (!this._keyboardRequested)
- return;
- this._updateCaretPositionId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
- this._updateCaretPositionId = 0;
-
- let currentWindow = global.screen.get_display().focus_window;
- if (!currentWindow) {
- this.setCursorLocation(null);
- return GLib.SOURCE_REMOVE;
- }
-
- let windowRect = currentWindow.get_frame_rect();
- let text = accessible.get_text_iface();
- let component = accessible.get_component_iface();
-
- try {
- let caretOffset = text.get_caret_offset();
- let caretRect = text.get_character_extents(caretOffset, Atspi.CoordType.WINDOW);
- let focusRect = component.get_extents(Atspi.CoordType.WINDOW);
-
- if (caretRect.width == 0 && caretRect.height == 0)
- caretRect = focusRect;
-
- this.setCursorLocation(currentWindow, caretRect.x, caretRect.y, caretRect.width, caretRect.height);
- } catch (e) {
- log('Error updating caret position for OSK: ' + e.message);
- }
-
- return GLib.SOURCE_REMOVE;
- });
-
- GLib.Source.set_name_by_id(this._updateCaretPositionId, '[gnome-shell] this._updateCaretPosition');
- },
-
- _focusIsTextEntry(accessible) {
- try {
- let role = accessible.get_role();
- let stateSet = accessible.get_state_set();
- return stateSet.contains(Atspi.StateType.EDITABLE) || role == Atspi.Role.TERMINAL;
- } catch (e) {
- log('Error determining accessible role: ' + e.message);
- return false;
- }
- },
-
- _onFocusChanged(caretTracker, event) {
- let accessible = event.source;
- if (!this._focusIsTextEntry(accessible))
- return;
-
- let focused = event.detail1 != 0;
- if (focused) {
- this._currentAccessible = accessible;
- this._updateCaretPosition(accessible);
- this.show(Main.layoutManager.focusIndex);
- } else if (this._currentAccessible == accessible) {
- this._currentAccessible = null;
- this.hide();
- }
- },
-
- _onCaretMoved(caretTracker, event) {
- let accessible = event.source;
- if (this._currentAccessible == accessible)
- this._updateCaretPosition(accessible);
+ _onFocusPositionChanged(focusTracker) {
+ let rect = focusTracker.getCurrentRect();
+ this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
},
_lastDeviceIsTouchscreen() {
@@ -650,8 +632,6 @@ var Keyboard = new Lang.Class({
if (!this._enabled && !this._keyboardController)
return;
- this._setCaretTrackerEnabled(this._enabled);
-
if (this._enabled && !this._keyboardController)
this._setupKeyboard();
else if (!this._enabled)
@@ -1027,11 +1007,14 @@ var Keyboard = new Lang.Class({
if (!this._keyboardRequested)
return;
- if (this._currentAccessible)
- this._updateCaretPosition(this._currentAccessible);
Main.layoutManager.keyboardIndex = monitor;
this._relayout();
Main.layoutManager.showKeyboard();
+
+ if (this._delayedAnimFocusWindow) {
+ this._setAnimationWindow(this._delayedAnimFocusWindow);
+ this._delayedAnimFocusWindow = null;
+ }
},
hide() {
@@ -1102,8 +1085,9 @@ var Keyboard = new Lang.Class({
window.move_frame(true, frameRect.x, frameRect.y);
},
- _animateWindow(window, show, deltaY) {
+ _animateWindow(window, show) {
let windowActor = window.get_compositor_private();
+ let deltaY = Main.layoutManager.keyboardBox.height;
if (!windowActor)
return;
@@ -1124,35 +1108,38 @@ var Keyboard = new Lang.Class({
}
},
- setCursorLocation(window, x, y , w, h) {
- if (window == this._oskFocusWindow)
+ _setAnimationWindow(window) {
+ if (this._animFocusedWindow == window)
return;
- if (this._oskFocusWindow) {
- let display = global.screen.get_display();
-
- if (display.get_grab_op() == Meta.GrabOp.NONE ||
- display.get_focus_window() != this._oskFocusWindow)
- this._animateWindow(this._oskFocusWindow, false, this._oskFocusWindowDelta);
+ if (this._animFocusedWindow)
+ this._animateWindow(this._animFocusedWindow, false);
+ if (window)
+ this._animateWindow(window, true);
- this._oskFocusWindow = null;
- this._oskFocusWindowDelta = null;
- }
+ this._animFocusedWindow = window;
+ },
+ setCursorLocation(window, x, y , w, h) {
if (window) {
let monitor = Main.layoutManager.keyboardMonitor;
let keyboardHeight = Main.layoutManager.keyboardBox.height;
- let frameRect = window.get_frame_rect();
- let windowActor = window.get_compositor_private();
- let delta = 0;
-
- if (frameRect.y + y + h >= monitor.height - keyboardHeight)
- delta = keyboardHeight;
+ let focusObscured = false;
- this._animateWindow(window, true, delta);
- this._oskFocusWindow = window;
- this._oskFocusWindowDelta = delta;
+ if (y + h >= monitor.y + monitor.height - keyboardHeight) {
+ if (this._keyboardVisible)
+ this._setAnimationWindow(window);
+ else
+ this._delayedAnimFocusWindow = window;
+ } else if (y < keyboardHeight) {
+ this._delayedAnimFocusWindow = null;
+ this._setAnimationWindow(null);
+ }
+ } else {
+ this._setAnimationWindow(null);
}
+
+ this._oskFocusWindow = window;
},
});