[gnome-shell/gnome-3-28] keyboard: Implement standalone FocusTracker



commit df57829ea1c9467b0d684a9d67d4e180e528b9e1
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri May 25 11:35:49 2018 +0200

    keyboard: Implement standalone FocusTracker
    
    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.

 js/misc/ibusManager.js |   5 ++
 js/ui/keyboard.js      | 236 +++++++++++++++++++++++--------------------------
 2 files changed, 117 insertions(+), 124 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..5fcdf988a 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,39 @@ 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 (this._animFocusedWindow)
+            this._animateWindow(this._animFocusedWindow, false);
+        if (window)
+            this._animateWindow(window, true);
 
-            if (display.get_grab_op() == Meta.GrabOp.NONE ||
-                display.get_focus_window() != this._oskFocusWindow)
-                this._animateWindow(this._oskFocusWindow, false, this._oskFocusWindowDelta);
+        this._animFocusedWindow = window;
+    },
 
-            this._oskFocusWindow = null;
-            this._oskFocusWindowDelta = null;
-        }
+    setCursorLocation(window, x, y , w, h) {
+        let monitor = Main.layoutManager.keyboardMonitor;
 
-        if (window) {
-            let monitor = Main.layoutManager.keyboardMonitor;
+        if (window && monitor) {
             let keyboardHeight = Main.layoutManager.keyboardBox.height;
-            let frameRect = window.get_frame_rect();
-            let windowActor = window.get_compositor_private();
-            let delta = 0;
+            let focusObscured = false;
 
-            if (frameRect.y + y + h >= monitor.height - keyboardHeight)
-                delta = keyboardHeight;
-
-            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;
     },
 });
 


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