Once the shell is ported to ESM, it will no longer be possible to replace entire classes (even when exported). Prepare for that by overriding methods of the regular classes, instead of creating custom subclasses. Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/268>
292 lines
12 KiB
JavaScript
292 lines
12 KiB
JavaScript
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
import Clutter from 'gi://Clutter';
|
|
import Graphene from 'gi://Graphene';
|
|
import St from 'gi://St';
|
|
|
|
import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
|
|
|
|
const Main = imports.ui.main;
|
|
const OverviewControls = imports.ui.overviewControls;
|
|
const {WindowPreview} = imports.ui.windowPreview;
|
|
const {Workspace} = imports.ui.workspace;
|
|
const {WorkspacesView} = imports.ui.workspacesView;
|
|
|
|
const WINDOW_SLOT = 4;
|
|
|
|
export default class Extension {
|
|
constructor() {
|
|
this._injectionManager = new InjectionManager();
|
|
}
|
|
|
|
enable() {
|
|
const previewProto = WindowPreview.prototype;
|
|
|
|
this._injectionManager.overrideMethod(previewProto, '_init', originalMethod => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function (...args) {
|
|
originalMethod.call(this, ...args);
|
|
|
|
this._text = new St.Label({
|
|
style_class: 'extension-windowsNavigator-window-tooltip',
|
|
visible: false,
|
|
});
|
|
|
|
this._text.add_constraint(new Clutter.BindConstraint({
|
|
source: this.windowContainer,
|
|
coordinate: Clutter.BindCoordinate.POSITION,
|
|
}));
|
|
this._text.add_constraint(new Clutter.AlignConstraint({
|
|
source: this.windowContainer,
|
|
align_axis: Clutter.AlignAxis.X_AXIS,
|
|
pivot_point: new Graphene.Point({x: 0.5, y: -1}),
|
|
factor: this._closeButtonSide === St.Side.LEFT ? 1 : 0,
|
|
}));
|
|
this._text.add_constraint(new Clutter.AlignConstraint({
|
|
source: this.windowContainer,
|
|
align_axis: Clutter.AlignAxis.Y_AXIS,
|
|
pivot_point: new Graphene.Point({x: -1, y: 0.5}),
|
|
factor: 0,
|
|
}));
|
|
|
|
this.add_child(this._text);
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(previewProto, 'showTooltip', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function (text) {
|
|
this._text.set({text});
|
|
this._text.show();
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(previewProto, 'hideTooltip', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function () {
|
|
this._text?.hide();
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
|
|
const workspaceProto = Workspace.prototype;
|
|
this._injectionManager.overrideMethod(workspaceProto, '_init', originalMethod => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function (...args) {
|
|
originalMethod.call(this, ...args);
|
|
|
|
if (this.metaWorkspace && this.metaWorkspace.index() < 9) {
|
|
this._tip = new St.Label({
|
|
style_class: 'extension-windowsNavigator-window-tooltip',
|
|
visible: false,
|
|
});
|
|
this.add_actor(this._tip);
|
|
|
|
this.connect('notify::scale-x', () => {
|
|
this._tip.set_scale(1 / this.scale_x, 1 / this.scale_x);
|
|
});
|
|
} else {
|
|
this._tip = null;
|
|
}
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(workspaceProto, 'vfunc_allocate', originalMethod => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function (box) {
|
|
originalMethod.call(this, box);
|
|
|
|
this._tip?.allocate_preferred_size(0, 0);
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(workspaceProto, 'showTooltip', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function () {
|
|
if (!this._tip)
|
|
return;
|
|
this._tip.text = (this.metaWorkspace.index() + 1).toString();
|
|
this._tip.show();
|
|
this.set_child_below_sibling(this._tip, null);
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(workspaceProto, 'hideTooltip', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function () {
|
|
this._tip?.hide();
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(workspaceProto, 'getWindowWithTooltip', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function (id) {
|
|
const {layoutManager} = this._container;
|
|
const slot = layoutManager._windowSlots[id - 1];
|
|
return slot ? slot[WINDOW_SLOT].metaWindow : null;
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(workspaceProto, 'showWindowsTooltips', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function () {
|
|
const {layoutManager} = this._container;
|
|
for (let i = 0; i < layoutManager._windowSlots.length; i++) {
|
|
if (layoutManager._windowSlots[i])
|
|
layoutManager._windowSlots[i][WINDOW_SLOT].showTooltip(`${i + 1}`);
|
|
}
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(workspaceProto, 'hideWindowsTooltips', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function () {
|
|
const {layoutManager} = this._container;
|
|
for (let i in layoutManager._windowSlots) {
|
|
if (layoutManager._windowSlots[i])
|
|
layoutManager._windowSlots[i][WINDOW_SLOT].hideTooltip();
|
|
}
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
|
|
const viewProto = WorkspacesView.prototype;
|
|
this._injectionManager.overrideMethod(viewProto, '_init', originalMethod => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function (...args) {
|
|
originalMethod.call(this, ...args);
|
|
|
|
this._pickWorkspace = false;
|
|
this._pickWindow = false;
|
|
global.stage.connectObject(
|
|
'key-press-event', this._onKeyPress.bind(this),
|
|
'key-release-event', this._onKeyRelease.bind(this),
|
|
this);
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(viewProto, '_hideTooltips', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function () {
|
|
if (global.stage.get_key_focus() === global.stage)
|
|
global.stage.set_key_focus(this._prevFocusActor);
|
|
this._pickWindow = false;
|
|
for (let i = 0; i < this._workspaces.length; i++)
|
|
this._workspaces[i].hideWindowsTooltips();
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(viewProto, '_hideWorkspacesTooltips', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function () {
|
|
global.stage.set_key_focus(this._prevFocusActor);
|
|
this._pickWorkspace = false;
|
|
for (let i = 0; i < this._workspaces.length; i++)
|
|
this._workspaces[i].hideTooltip();
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(viewProto, '_onKeyRelease', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function (actor, event) {
|
|
if (this._pickWindow &&
|
|
(event.get_key_symbol() === Clutter.KEY_Alt_L ||
|
|
event.get_key_symbol() === Clutter.KEY_Alt_R))
|
|
this._hideTooltips();
|
|
if (this._pickWorkspace &&
|
|
(event.get_key_symbol() === Clutter.KEY_Control_L ||
|
|
event.get_key_symbol() === Clutter.KEY_Control_R))
|
|
this._hideWorkspacesTooltips();
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
this._injectionManager.overrideMethod(viewProto, '_onKeyPress', () => {
|
|
/* eslint-disable no-invalid-this */
|
|
return function (actor, event) {
|
|
const {ControlsState} = OverviewControls;
|
|
if (this._overviewAdjustment.value !== ControlsState.WINDOW_PICKER)
|
|
return false;
|
|
|
|
let workspaceManager = global.workspace_manager;
|
|
|
|
if ((event.get_key_symbol() === Clutter.KEY_Alt_L ||
|
|
event.get_key_symbol() === Clutter.KEY_Alt_R) &&
|
|
!this._pickWorkspace) {
|
|
this._prevFocusActor = global.stage.get_key_focus();
|
|
global.stage.set_key_focus(null);
|
|
this._active = workspaceManager.get_active_workspace_index();
|
|
this._pickWindow = true;
|
|
this._workspaces[workspaceManager.get_active_workspace_index()].showWindowsTooltips();
|
|
return true;
|
|
}
|
|
if ((event.get_key_symbol() === Clutter.KEY_Control_L ||
|
|
event.get_key_symbol() === Clutter.KEY_Control_R) &&
|
|
!this._pickWindow) {
|
|
this._prevFocusActor = global.stage.get_key_focus();
|
|
global.stage.set_key_focus(null);
|
|
this._pickWorkspace = true;
|
|
for (let i = 0; i < this._workspaces.length; i++)
|
|
this._workspaces[i].showTooltip();
|
|
return true;
|
|
}
|
|
|
|
if (global.stage.get_key_focus() !== global.stage)
|
|
return false;
|
|
|
|
// ignore shift presses, they're required to get numerals in azerty keyboards
|
|
if ((this._pickWindow || this._pickWorkspace) &&
|
|
(event.get_key_symbol() === Clutter.KEY_Shift_L ||
|
|
event.get_key_symbol() === Clutter.KEY_Shift_R))
|
|
return true;
|
|
|
|
if (this._pickWindow) {
|
|
if (this._active !== workspaceManager.get_active_workspace_index()) {
|
|
this._hideTooltips();
|
|
return false;
|
|
}
|
|
|
|
let c = event.get_key_symbol() - Clutter.KEY_KP_0;
|
|
if (c > 9 || c <= 0) {
|
|
c = event.get_key_symbol() - Clutter.KEY_0;
|
|
if (c > 9 || c <= 0) {
|
|
this._hideTooltips();
|
|
log(c);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
let win = this._workspaces[this._active].getWindowWithTooltip(c);
|
|
this._hideTooltips();
|
|
|
|
if (win)
|
|
Main.activateWindow(win, global.get_current_time());
|
|
|
|
return true;
|
|
}
|
|
if (this._pickWorkspace) {
|
|
let c = event.get_key_symbol() - Clutter.KEY_KP_0;
|
|
if (c > 9 || c <= 0) {
|
|
c = event.get_key_symbol() - Clutter.KEY_0;
|
|
if (c > 9 || c <= 0) {
|
|
this._hideWorkspacesTooltips();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
let workspace = this._workspaces[c - 1];
|
|
if (workspace !== undefined)
|
|
workspace.metaWorkspace.activate(global.get_current_time());
|
|
|
|
this._hideWorkspacesTooltips();
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
/* eslint-enable */
|
|
});
|
|
}
|
|
|
|
disable() {
|
|
this._injectionManager.clear();
|
|
}
|
|
}
|