I followed this https://wiki.gnome.org/Projects/GnomeShell/Extensions/StepByStepTutorial for Overwriting a function.
For example, I want to override the function _setupKeyboard()
on the Keyboard
class, but my override isn't invoked. The specific portion I want to change is this, to remove the if
guard:
if (Meta.is_wayland_compositor()) {
this._connectSignal(this._keyboardController, 'emoji-visible',
this._onEmojiKeyVisible.bind(this));
}
I copied the function from the source, removed the part I didn't want, then set the replacement function like this:
const Keyboard = imports.ui.keyboard;
Keyboard.Keyboard.prototype._setupKeyboard = myOverride;
Why isn't my override being invoked and how can I achieve this?
There are two common reasons an override won't be invoked. If the method is invoked before your override is applied, or if the function is a callback set with Function.prototype.bind()
which creates a new closure.
In this case, the function _setupKeyboard()
is called before your override is applied. When GNOME Shell starts up, it creates an instance of Keyboard.KeyboardManager
here:
// main.js, line #204
keyboard = new Keyboard.KeyboardManager();
By the time the keyboard
variable has been assigned to the instance, a default Keyboard.Keyboard
class has been created and the function _setupKeyboard()
has already been called in Keyboard._init()
, which is much sooner than your extension is loaded.
Since there's no way to easily fix that, your best option is to just re-create the one part of the code you want to run:
const Meta = imports.gi.Meta;
const Main = imports.ui.main;
const Keyboard = imports.ui.keyboard.Keyboard;
const originalSetup = Keyboard.prototype._setupKeyboard;
const modifiedSetup = function () {
originalSetup.call(this);
if (!Meta.is_wayland_compositor()) {
this._connectSignal(this._keyboardController, 'emoji-visible',
this._onEmojiKeyVisible.bind(this));
}
this._relayout();
};
function init() {
}
// Your extension's enable function (might be a class method)
function enable() {
let kbd = Main.keyboard.keyboardActor;
if (kbd !== null) {
if (!Meta.is_wayland_compositor()) {
kbd.__mySignalId = kbd._connectSignal(kbd._keyboardController, 'emoji-visible',
kbd._onEmojiKeyVisible.bind(kbd));
}
}
Keyboard.prototype._setupKeyboard = modifiedSetup;
}
function disable() {
let kbd = Main.keyboard.keyboardActor;
if (kbd !== null && kbd.__mySignalId) {
kbd.disconnect(kbd.__mySignalId);
kbd.__mySignalId = 0;
}
Keyboard.prototype._setupKeyboard = originalSetup;
}
This is not very pretty, but that is often the price of patching private code. I can also not guarantee that the code will do what you want, because I suspect the emoji key is hidden on X11 for a reason.