[gnome] Move to Grimble tiling manager

This commit is contained in:
2026-01-14 00:55:43 -05:00
parent de41369f5f
commit 941c727d38
90 changed files with 3999 additions and 9602 deletions

View File

@ -0,0 +1,83 @@
import {Combo, Shortcut} from '../common.js';
import {loadConfiguration, saveConfiguration} from '../utils.js';
import GLib from 'gi://GLib';
export default class ComboRowHandler {
_combos;
_windowManager;
constructor(windowManager, extension) {
this._windowManager = windowManager;
this._combos = Combo.getCombo();
this._combos.forEach(({key}) => {
extension._settings?.connect(`changed::${key}`, () => this._onComboChanged(key, extension));
});
}
_onComboChanged(key, extension) {
const shortcuts = Shortcut.getShortcuts();
switch (key) {
case 'keybinding-config':
if (extension.metadata && extension._settings?.get_string('keybinding-config')) {
let conf = extension._settings?.get_string('keybinding-config');
if (conf === 'i3') {
loadConfiguration(`${extension.path}/configs/i3.json`, c => {
if (extension._settings) {
for (const p of shortcuts) {
if (c[p])
extension._settings.set_strv(p, [c[p]]);
else
extension._settings.set_strv(p, []);
}
}
}, () => { });
} else if (conf === 'Grimble') {
loadConfiguration(`${extension.path}/configs/grimble.json`, c => {
if (extension._settings) {
for (const p of shortcuts) {
if (c[p])
extension._settings.set_strv(p, [c[p]]);
else
extension._settings.set_strv(p, []);
}
}
}, () => { });
} else if (conf === 'None') {
loadConfiguration(`${extension.path}/configs/default.json`, c => {
if (extension._settings) {
for (const p of shortcuts) {
if (c[p])
extension._settings.set_strv(p, [c[p]]);
else
extension._settings.set_strv(p, []);
}
}
}, () => { });
} else if (conf === 'Custom') {
const userPath = GLib.get_user_config_dir();
let o = {};
for (const p of shortcuts)
o[p] = extension._settings.get_strv(p) ?? [];
loadConfiguration(`${userPath}/grimble/config/custom.json`, c => {
if (extension._settings) {
for (const p of shortcuts) {
if (c[p])
extension._settings.set_strv(p, c[p]);
else
extension._settings.set_strv(p, []);
}
}
}, () => {
saveConfiguration('custom.json', o);
});
}
}
break;
default:
break;
}
}
}

View File

@ -0,0 +1,197 @@
/**
* © gnome-shell-extension-tiling-assistant
* Source: https://git.launchpad.net/ubuntu/+source/gnome-shell-extension-tiling-assistant/tree/tiling-assistant@leleat-on-github/src/prefs/shortcutListener.js
*
* This code is partially reused from Ubuntu tiling assistant extension (GPL-2.0).
*
* enableArrowBinding and disableArrowBinding are new methods.
* Other methods are modified for our use case.
*/
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import Meta from 'gi://Meta';
import Shell from 'gi://Shell';
import GLib from 'gi://GLib';
import {Shortcut} from '../common.js';
import {Direction} from '../tileWindowManager.js';
const MAX_RESIZE_GAP = 50;
const MIN_RESIZE_GAP = 10;
/**
* Class to handle the keyboard shortcuts (on the extension side) except the
* ones related to the Layouts. For those, see layoutsManager.js.
*/
export default class KeybindingHandler {
_keyBindings;
_windowManager;
_extensionObject = null;
_settings;
_waitingAction;
_enableArrow = false;
_prevArrowTyped;
constructor(windowManager, extension) {
this._extensionObject = extension;
this._settings = extension.getSettings();
this._windowManager = windowManager;
this._prevArrowTyped = [Direction.North, 0];
this._keyBindings = Shortcut.getShortcuts();
this._keyBindings.forEach(key => {
Main.wm.addKeybinding(key, this._settings, Meta.KeyBindingFlags.IGNORE_AUTOREPEAT, Shell.ActionMode.NORMAL, this._onCustomKeybindingPressed.bind(this, key));
});
}
destroy() {
this._keyBindings.forEach(key => Main.wm.removeKeybinding(key));
this.disableArrowBinding();
}
enableArrowBinding() {
let bindings = ['arrow-up', 'arrow-down', 'arrow-left', 'arrow-right', 'key-escape'];
bindings.forEach(key => {
Main.wm.addKeybinding(key, this._settings, Meta.KeyBindingFlags.IGNORE_AUTOREPEAT, Shell.ActionMode.NORMAL, this._onCustomKeybindingPressed.bind(this, key));
});
}
disableArrowBinding() {
let bindings = ['arrow-up', 'arrow-down', 'arrow-left', 'arrow-right', 'key-escape'];
bindings.forEach(key => Main.wm.removeKeybinding(key));
}
compute_gap(direction) {
const t = GLib.get_real_time();
const dir = this._prevArrowTyped[0];
const time = Math.min(Math.max(t - this._prevArrowTyped[1], 150000), 300000) - 150000;
this._prevArrowTyped = [direction, t];
let gap = dir === direction
? MAX_RESIZE_GAP - ((time * (MAX_RESIZE_GAP - MIN_RESIZE_GAP) / 150000))
: MIN_RESIZE_GAP;
return gap;
}
/**
* @param {string} shortcutName
*/
_onCustomKeybindingPressed(shortcutName) {
switch (shortcutName) {
case 'keybinding-close':
global.display.get_focus_window().delete(global.get_current_time());
break;
case 'keybinding-open-settings':
this._extensionObject?.openPreferences();
break;
case 'keybinding-rotation':
this._windowManager.rotateWindow(global.display.get_focus_window());
break;
case 'keybinding-maximize':
this._windowManager.maximizeTile(global.display.get_focus_window());
break;
case 'keybinding-search':
this._windowManager.createSearchBar();
break;
case 'keybinding-refresh':
// Unused
this._windowManager.refresh();
break;
case 'keybinding-move-left':
this._windowManager.moveTile(Direction.West);
break;
case 'keybinding-move-right':
this._windowManager.moveTile(Direction.East);
break;
case 'keybinding-move-top':
this._windowManager.moveTile(Direction.North);
break;
case 'keybinding-move-bottom':
this._windowManager.moveTile(Direction.South);
break;
case 'keybinding-move':
this._waitingAction = shortcutName;
this.enableArrowBinding();
break;
case 'keybinding-resize':
this._waitingAction = shortcutName;
this.enableArrowBinding();
break;
case 'keybinding-resize-left':
this._windowManager.resizeFocusedWindow(Meta.GrabOp.RESIZING_W);
break;
case 'keybinding-resize-right':
this._windowManager.resizeFocusedWindow(Meta.GrabOp.RESIZING_E);
break;
case 'keybinding-resize-top':
this._windowManager.resizeFocusedWindow(Meta.GrabOp.RESIZING_N);
break;
case 'keybinding-resize-bottom':
this._windowManager.resizeFocusedWindow(Meta.GrabOp.RESIZING_S);
break;
case 'keybinding-focus':
this._waitingAction = shortcutName;
this.enableArrowBinding();
break;
case 'keybinding-focus-left':
this._windowManager.changeFocus(Direction.West);
break;
case 'keybinding-focus-right':
this._windowManager.changeFocus(Direction.East);
break;
case 'keybinding-focus-top':
this._windowManager.changeFocus(Direction.North);
break;
case 'keybinding-focus-bottom':
this._windowManager.changeFocus(Direction.South);
break;
case 'keybinding-next-workspace':
this._windowManager.moveToWorkspace(true);
break;
case 'keybinding-previous-workspace':
this._windowManager.moveToWorkspace(false);
break;
case 'keybinding-next-monitor':
this._windowManager.moveToNextMonitor();
break;
case 'arrow-up':
if (this._waitingAction === 'keybinding-move') {
this._windowManager.moveTile(Direction.North);
this.disableArrowBinding();
} else if (this._waitingAction === 'keybinding-resize') {
this._windowManager.resizeFocusedWindow(Meta.GrabOp.RESIZING_N, this.compute_gap(Direction.North));
} else if (this._waitingAction === 'keybinding-focus') {
this._windowManager.changeFocus(Direction.North);
}
break;
case 'arrow-down':
if (this._waitingAction === 'keybinding-move') {
this._windowManager.moveTile(Direction.South);
this.disableArrowBinding();
} else if (this._waitingAction === 'keybinding-resize') {
this._windowManager.resizeFocusedWindow(Meta.GrabOp.RESIZING_S, this.compute_gap(Direction.South));
} else if (this._waitingAction === 'keybinding-focus') {
this._windowManager.changeFocus(Direction.South);
}
break;
case 'arrow-left':
if (this._waitingAction === 'keybinding-move') {
this._windowManager.moveTile(Direction.West);
this.disableArrowBinding();
} else if (this._waitingAction === 'keybinding-resize') {
this._windowManager.resizeFocusedWindow(Meta.GrabOp.RESIZING_W, this.compute_gap(Direction.West));
} else if (this._waitingAction === 'keybinding-focus') {
this._windowManager.changeFocus(Direction.West);
}
break;
case 'arrow-right':
if (this._waitingAction === 'keybinding-move') {
this._windowManager.moveTile(Direction.East);
this.disableArrowBinding();
} else if (this._waitingAction === 'keybinding-resize') {
this._windowManager.resizeFocusedWindow(Meta.GrabOp.RESIZING_E, this.compute_gap(Direction.East));
} else if (this._waitingAction === 'keybinding-focus') {
this._windowManager.changeFocus(Direction.East);
}
break;
case 'key-escape':
this.disableArrowBinding();
break;
default:
break;
}
}
}

View File

@ -0,0 +1,26 @@
import {Spin} from '../common.js';
import {Tile} from '../tile.js';
export default class SpinHandler {
_spins;
_windowManager;
constructor(windowManager, extension) {
this._windowManager = windowManager;
this._spins = Spin.getSpins();
this._spins.forEach(key => {
extension._settings?.connect(`changed::${key}`, () => this._onSwitchChanged(key, extension));
});
}
_onSwitchChanged(key, extension) {
switch (key) {
case 'tile-padding':
if (extension.metadata && extension._settings?.get_int('tile-padding')) {
Tile.padding = extension._settings.get_int('tile-padding');
this._windowManager.updateMonitors();
}
break;
default:
break;
}
}
}

View File

@ -0,0 +1,28 @@
import {Switches} from '../common.js';
import {enableWindowTheme} from '../theme.js';
export default class SwitchHandler {
_switchs;
_windowManager;
constructor(windowManager, extension) {
this._windowManager = windowManager;
this._switchs = Switches.getSwitches();
this._switchs.forEach(key => {
extension._settings?.connect(`changed::${key}`, () => this._onSwitchChanged(key, extension));
});
}
_onSwitchChanged(key, extension) {
switch (key) {
case 'header-bar':
if (extension.metadata && extension._settings?.get_boolean('header-bar'))
enableWindowTheme();
else if (extension.metadata)
enableWindowTheme();
break;
default:
break;
}
}
}