keyboard: Avoid runtime dependency on the Caribou daemon
The caribou daemon only gives us focus tracking, which is almost 1:1 with our own FocusCaretTracker implementation. This means we can entirely replace the Caribou daemon inside gnome-shell, reducing the Caribou dependency to just libcaribou, and more specifically the CaribouKeyboardModel we pull the keyboard models from. As we still need underneath a CaribouDisplayAdapter to drive the keyboard, reuse the wayland one, which has been renamed to make it look generic, plus it will use the virtual input device API from mutter/clutter. https://bugzilla.gnome.org/show_bug.cgi?id=777342
This commit is contained in:
parent
9b7304488e
commit
aecd1c126a
@ -1,5 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const FocusCaretTracker = imports.ui.focusCaretTracker;
|
||||||
|
const Atspi = imports.gi.Atspi;
|
||||||
const Caribou = imports.gi.Caribou;
|
const Caribou = imports.gi.Caribou;
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gdk = imports.gi.Gdk;
|
const Gdk = imports.gi.Gdk;
|
||||||
@ -25,42 +27,6 @@ const KEYBOARD_TYPE = 'keyboard-type';
|
|||||||
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
||||||
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
|
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
|
||||||
|
|
||||||
const CARIBOU_BUS_NAME = 'org.gnome.Caribou.Daemon';
|
|
||||||
const CARIBOU_OBJECT_PATH = '/org/gnome/Caribou/Daemon';
|
|
||||||
|
|
||||||
const CaribouKeyboardIface = '<node> \
|
|
||||||
<interface name="org.gnome.Caribou.Keyboard"> \
|
|
||||||
<method name="Show"> \
|
|
||||||
<arg type="u" direction="in" /> \
|
|
||||||
</method> \
|
|
||||||
<method name="Hide"> \
|
|
||||||
<arg type="u" direction="in" /> \
|
|
||||||
</method> \
|
|
||||||
<method name="SetCursorLocation"> \
|
|
||||||
<arg type="i" direction="in" /> \
|
|
||||||
<arg type="i" direction="in" /> \
|
|
||||||
<arg type="i" direction="in" /> \
|
|
||||||
<arg type="i" direction="in" /> \
|
|
||||||
</method> \
|
|
||||||
<method name="SetEntryLocation"> \
|
|
||||||
<arg type="i" direction="in" /> \
|
|
||||||
<arg type="i" direction="in" /> \
|
|
||||||
<arg type="i" direction="in" /> \
|
|
||||||
<arg type="i" direction="in" /> \
|
|
||||||
</method> \
|
|
||||||
<property name="Name" access="read" type="s" /> \
|
|
||||||
</interface> \
|
|
||||||
</node>';
|
|
||||||
|
|
||||||
const CaribouDaemonIface = '<node> \
|
|
||||||
<interface name="org.gnome.Caribou.Daemon"> \
|
|
||||||
<method name="Run" /> \
|
|
||||||
<method name="Quit" /> \
|
|
||||||
</interface> \
|
|
||||||
</node>';
|
|
||||||
|
|
||||||
const CaribouDaemonProxy = Gio.DBusProxy.makeProxyWrapper(CaribouDaemonIface);
|
|
||||||
|
|
||||||
const Key = new Lang.Class({
|
const Key = new Lang.Class({
|
||||||
Name: 'Key',
|
Name: 'Key',
|
||||||
|
|
||||||
@ -188,19 +154,22 @@ const Key = new Lang.Class({
|
|||||||
Signals.addSignalMethods(Key.prototype);
|
Signals.addSignalMethods(Key.prototype);
|
||||||
|
|
||||||
const Keyboard = new Lang.Class({
|
const Keyboard = new Lang.Class({
|
||||||
// HACK: we can't set Name, because it collides with Name dbus property
|
Name: 'Keyboard',
|
||||||
// Name: 'Keyboard',
|
|
||||||
|
|
||||||
_init: function () {
|
_init: function () {
|
||||||
this._impl = Gio.DBusExportedObject.wrapJSObject(CaribouKeyboardIface, this);
|
|
||||||
this._impl.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
|
|
||||||
|
|
||||||
this.actor = null;
|
this.actor = null;
|
||||||
this._focusInTray = false;
|
this._focusInTray = false;
|
||||||
this._focusInExtendedKeys = false;
|
this._focusInExtendedKeys = false;
|
||||||
|
|
||||||
this._timestamp = global.display.get_current_time_roundtrip();
|
this._timestamp = global.display.get_current_time_roundtrip();
|
||||||
|
|
||||||
|
this._focusCaretTracker = new FocusCaretTracker.FocusCaretTracker();
|
||||||
|
this._focusCaretTracker.connect('focus-changed', Lang.bind(this, this._onFocusChanged));
|
||||||
|
this._focusCaretTracker.connect('caret-moved', Lang.bind(this, this._onCaretMoved));
|
||||||
|
this._currentAccessible = null;
|
||||||
|
this._caretTrackingEnabled = false;
|
||||||
|
this._updateCaretPositionId = 0;
|
||||||
|
|
||||||
this._keyboardSettings = new Gio.Settings({ schema_id: KEYBOARD_SCHEMA });
|
this._keyboardSettings = new Gio.Settings({ schema_id: KEYBOARD_SCHEMA });
|
||||||
this._keyboardSettings.connect('changed', Lang.bind(this, this._sync));
|
this._keyboardSettings.connect('changed', Lang.bind(this, this._sync));
|
||||||
this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA });
|
this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA });
|
||||||
@ -208,9 +177,7 @@ const Keyboard = new Lang.Class({
|
|||||||
this._daemonProxy = null;
|
this._daemonProxy = null;
|
||||||
this._lastDeviceId = null;
|
this._lastDeviceId = null;
|
||||||
|
|
||||||
if (Meta.is_wayland_compositor() &&
|
Caribou.DisplayAdapter.set_default(new LocalAdapter());
|
||||||
Caribou.DisplayAdapter.set_default)
|
|
||||||
Caribou.DisplayAdapter.set_default(new ShellWaylandAdapter());
|
|
||||||
|
|
||||||
Meta.get_backend().connect('last-device-changed', Lang.bind(this,
|
Meta.get_backend().connect('last-device-changed', Lang.bind(this,
|
||||||
function (backend, deviceId) {
|
function (backend, deviceId) {
|
||||||
@ -240,6 +207,93 @@ const Keyboard = new Lang.Class({
|
|||||||
this._redraw();
|
this._redraw();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_setCaretTrackerEnabled: function (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: function (accessible) {
|
||||||
|
if (this._updateCaretPositionId)
|
||||||
|
GLib.source_remove(this._updateCaretPositionId);
|
||||||
|
this._updateCaretPositionId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, Lang.bind(this, function() {
|
||||||
|
this._updateCaretPositionId = 0;
|
||||||
|
|
||||||
|
let currentWindow = global.screen.get_display().focus_window;
|
||||||
|
if (!currentWindow)
|
||||||
|
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);
|
||||||
|
|
||||||
|
caretRect.x += windowRect.x;
|
||||||
|
caretRect.y += windowRect.y;
|
||||||
|
focusRect.x += windowRect.x;
|
||||||
|
focusRect.y += windowRect.y;
|
||||||
|
|
||||||
|
if (caretRect.width == 0 && caretRect.height == 0)
|
||||||
|
caretRect = focusRect;
|
||||||
|
|
||||||
|
this.SetEntryLocation(focusRect.x, focusRect.y, focusRect.width, focusRect.height);
|
||||||
|
this.SetCursorLocation(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: function (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: function (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(this._timestamp);
|
||||||
|
} else if (this._currentAccessible == accessible) {
|
||||||
|
this._currentAccessible = null;
|
||||||
|
this.Hide(this._timestamp);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCaretMoved: function (caretTracker, event) {
|
||||||
|
let accessible = event.source;
|
||||||
|
if (this._currentAccessible == accessible)
|
||||||
|
this._updateCaretPosition(accessible);
|
||||||
|
},
|
||||||
|
|
||||||
_lastDeviceIsTouchscreen: function () {
|
_lastDeviceIsTouchscreen: function () {
|
||||||
if (!this._lastDeviceId)
|
if (!this._lastDeviceId)
|
||||||
return false;
|
return false;
|
||||||
@ -262,6 +316,8 @@ const Keyboard = new Lang.Class({
|
|||||||
this._keyboard.keyboard_type == this._keyboardSettings.get_string(KEYBOARD_TYPE))
|
this._keyboard.keyboard_type == this._keyboardSettings.get_string(KEYBOARD_TYPE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
this._setCaretTrackerEnabled(this._enableKeyboard);
|
||||||
|
|
||||||
if (this._keyboard)
|
if (this._keyboard)
|
||||||
this._destroyKeyboard();
|
this._destroyKeyboard();
|
||||||
|
|
||||||
@ -297,23 +353,6 @@ const Keyboard = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_setupKeyboard: function() {
|
_setupKeyboard: function() {
|
||||||
if (!this._daemonProxy) {
|
|
||||||
this._daemonProxy = new CaribouDaemonProxy(Gio.DBus.session, CARIBOU_BUS_NAME,
|
|
||||||
CARIBOU_OBJECT_PATH,
|
|
||||||
Lang.bind(this, function(proxy, error) {
|
|
||||||
if (error) {
|
|
||||||
log(error.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
this._daemonProxy.RunRemote(function (result, error) {
|
|
||||||
if (error) {
|
|
||||||
log(error.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
|
this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
|
||||||
Main.layoutManager.keyboardBox.add_actor(this.actor);
|
Main.layoutManager.keyboardBox.add_actor(this.actor);
|
||||||
Main.layoutManager.trackChrome(this.actor);
|
Main.layoutManager.trackChrome(this.actor);
|
||||||
@ -685,7 +724,6 @@ const Keyboard = new Lang.Class({
|
|||||||
this._showIdleId = 0;
|
this._showIdleId = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
// D-Bus methods
|
|
||||||
Show: function(timestamp) {
|
Show: function(timestamp) {
|
||||||
if (!this._enableKeyboard)
|
if (!this._enableKeyboard)
|
||||||
return;
|
return;
|
||||||
@ -727,10 +765,6 @@ const Keyboard = new Lang.Class({
|
|||||||
|
|
||||||
// this._setLocation(x, y);
|
// this._setLocation(x, y);
|
||||||
},
|
},
|
||||||
|
|
||||||
get Name() {
|
|
||||||
return 'gnome-shell';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const KeyboardSource = new Lang.Class({
|
const KeyboardSource = new Lang.Class({
|
||||||
@ -754,8 +788,8 @@ const KeyboardSource = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const ShellWaylandAdapter = new Lang.Class({
|
const LocalAdapter = new Lang.Class({
|
||||||
Name: 'ShellWaylandAdapter',
|
Name: 'LocalAdapter',
|
||||||
Extends: Caribou.XAdapter,
|
Extends: Caribou.XAdapter,
|
||||||
|
|
||||||
_init: function () {
|
_init: function () {
|
||||||
|
Loading…
Reference in New Issue
Block a user