[gnome] Move to Grimble tiling manager
This commit is contained in:
@ -1,43 +0,0 @@
|
||||
import GObject from "gi://GObject";
|
||||
|
||||
import St from "gi://St";
|
||||
|
||||
import { ThemeManagerBase } from "../shared/theme.js";
|
||||
import { Logger } from "../shared/logger.js";
|
||||
import { production } from "../shared/settings.js";
|
||||
|
||||
export class ExtensionThemeManager extends ThemeManagerBase {
|
||||
static {
|
||||
GObject.registerClass(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../../extension.js").default} extension
|
||||
*/
|
||||
constructor(extension) {
|
||||
super(extension);
|
||||
this.metadata = extension.metadata;
|
||||
}
|
||||
|
||||
reloadStylesheet() {
|
||||
const uuid = this.metadata.uuid;
|
||||
const stylesheetFile = this.configMgr.stylesheetFile;
|
||||
const defaultStylesheetFile = this.configMgr.defaultStylesheetFile;
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
|
||||
try {
|
||||
theme.unload_stylesheet(defaultStylesheetFile);
|
||||
theme.unload_stylesheet(stylesheetFile);
|
||||
if (production) {
|
||||
theme.load_stylesheet(stylesheetFile);
|
||||
this.stylesheet = stylesheetFile;
|
||||
} else {
|
||||
theme.load_stylesheet(defaultStylesheetFile);
|
||||
this.stylesheet = defaultStylesheetFile;
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error(`${uuid} - ${e}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,129 +0,0 @@
|
||||
import GObject from "gi://GObject";
|
||||
import Gio from "gi://Gio";
|
||||
|
||||
import * as Main from "resource:///org/gnome/shell/ui/main.js";
|
||||
import { gettext as _ } from "resource:///org/gnome/shell/extensions/extension.js";
|
||||
import { QuickMenuToggle, SystemIndicator } from "resource:///org/gnome/shell/ui/quickSettings.js";
|
||||
import {
|
||||
PopupSwitchMenuItem,
|
||||
PopupSeparatorMenuItem,
|
||||
} from "resource:///org/gnome/shell/ui/popupMenu.js";
|
||||
|
||||
import * as Utils from "./utils.js";
|
||||
import { Logger } from "../shared/logger.js";
|
||||
|
||||
const iconName = "view-grid-symbolic";
|
||||
|
||||
/** @typedef {import('../../extension.js').default} ForgeExtension */
|
||||
|
||||
class SettingsPopupSwitch extends PopupSwitchMenuItem {
|
||||
static {
|
||||
GObject.registerClass(this);
|
||||
}
|
||||
|
||||
/** @type {ForgeExtension} extension */
|
||||
extension;
|
||||
|
||||
/**
|
||||
* @param {string} title
|
||||
* @param {ForgeExtension} extension
|
||||
* @param {string} bind
|
||||
*/
|
||||
constructor(title, extension, bind) {
|
||||
const active = !!extension.settings.get_boolean(bind);
|
||||
super(title, active);
|
||||
this.extension = extension;
|
||||
Logger.info(bind, active);
|
||||
this.connect("toggled", (item) => this.extension.settings.set_boolean(bind, item.state));
|
||||
}
|
||||
}
|
||||
|
||||
export class FeatureMenuToggle extends QuickMenuToggle {
|
||||
static {
|
||||
GObject.registerClass(this);
|
||||
}
|
||||
|
||||
constructor(extension) {
|
||||
const title = _("Tiling");
|
||||
const initSettings = Utils.isGnomeGTE(45)
|
||||
? { title, iconName, toggleMode: true }
|
||||
: { label: title, iconName, toggleMode: true };
|
||||
super(initSettings);
|
||||
this.extension = extension;
|
||||
this.extension.settings.bind(
|
||||
"tiling-mode-enabled",
|
||||
this,
|
||||
"checked",
|
||||
Gio.SettingsBindFlags.DEFAULT
|
||||
);
|
||||
this.extension.settings.bind(
|
||||
"quick-settings-enabled",
|
||||
this,
|
||||
"visible",
|
||||
Gio.SettingsBindFlags.DEFAULT
|
||||
);
|
||||
|
||||
this.menu.setHeader(iconName, _("Forge"), _("Tiling Window Management"));
|
||||
|
||||
this.menu.addMenuItem(
|
||||
(this._singleSwitch = new SettingsPopupSwitch(
|
||||
_("Gaps Hidden when Single"),
|
||||
this.extension,
|
||||
"window-gap-hidden-on-single"
|
||||
))
|
||||
);
|
||||
|
||||
this.menu.addMenuItem(
|
||||
(this._focusHintSwitch = new SettingsPopupSwitch(
|
||||
_("Show Focus Hint Border"),
|
||||
this.extension,
|
||||
"focus-border-toggle"
|
||||
))
|
||||
);
|
||||
|
||||
this.menu.addMenuItem(
|
||||
(this._focusMovePointer = new SettingsPopupSwitch(
|
||||
_("Move Pointer with the Focus"),
|
||||
this.extension,
|
||||
"move-pointer-focus-enabled"
|
||||
))
|
||||
);
|
||||
|
||||
// Add an entry-point for more settings
|
||||
this.menu.addMenuItem(new PopupSeparatorMenuItem());
|
||||
const settingsItem = this.menu.addAction(_("Settings"), () => this.extension.openPreferences());
|
||||
|
||||
// Ensure the settings are unavailable when the screen is locked
|
||||
settingsItem.visible = Main.sessionMode.allowSettings;
|
||||
this.menu._settingsActions[this.extension.uuid] = settingsItem;
|
||||
}
|
||||
}
|
||||
|
||||
export class FeatureIndicator extends SystemIndicator {
|
||||
static {
|
||||
GObject.registerClass(this);
|
||||
}
|
||||
|
||||
constructor(extension) {
|
||||
super();
|
||||
|
||||
this.extension = extension;
|
||||
|
||||
// Create the icon for the indicator
|
||||
this._indicator = this._addIndicator();
|
||||
this._indicator.icon_name = iconName;
|
||||
|
||||
const tilingModeEnabled = this.extension.settings.get_boolean("tiling-mode-enabled");
|
||||
const quickSettingsEnabled = this.extension.settings.get_boolean("quick-settings-enabled");
|
||||
|
||||
this._indicator.visible = tilingModeEnabled && quickSettingsEnabled;
|
||||
|
||||
this.extension.settings.connect("changed", (_, name) => {
|
||||
switch (name) {
|
||||
case "tiling-mode-enabled":
|
||||
case "quick-settings-enabled":
|
||||
this._indicator.visible = this.extension.settings.get_boolean(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,493 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Forge extension for GNOME
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Gnome imports
|
||||
import GObject from "gi://GObject";
|
||||
import Meta from "gi://Meta";
|
||||
import Shell from "gi://Shell";
|
||||
|
||||
// Gnome Shell imports
|
||||
import * as Main from "resource:///org/gnome/shell/ui/main.js";
|
||||
|
||||
// Shared state
|
||||
import { Logger } from "../shared/logger.js";
|
||||
|
||||
export class Keybindings extends GObject.Object {
|
||||
static {
|
||||
GObject.registerClass(this);
|
||||
}
|
||||
|
||||
/** @type {import('./extension.js').default} */
|
||||
ext;
|
||||
|
||||
constructor(ext) {
|
||||
super();
|
||||
Logger.debug(`created keybindings`);
|
||||
this._grabbers = new Map();
|
||||
// this._bindSignals();
|
||||
this.ext = ext;
|
||||
this.extWm = ext.extWm;
|
||||
this.kbdSettings = ext.kbdSettings;
|
||||
this.settings = ext.settings;
|
||||
this.buildBindingDefinitions();
|
||||
}
|
||||
|
||||
// @deprecated
|
||||
_acceleratorActivate(action) {
|
||||
let grabber = this._grabbers.get(action);
|
||||
if (grabber) {
|
||||
Logger.debug(`Firing accelerator ${grabber.accelerator} : ${grabber.name}`);
|
||||
grabber.callback();
|
||||
} else {
|
||||
Logger.error(`No listeners [action={${action}}]`);
|
||||
}
|
||||
}
|
||||
|
||||
// @deprecated
|
||||
_bindSignals() {
|
||||
global.display.connect("accelerator-activated", (_display, action, _deviceId, _timestamp) => {
|
||||
this._acceleratorActivate(action);
|
||||
});
|
||||
}
|
||||
|
||||
enable() {
|
||||
let keybindings = this._bindings;
|
||||
|
||||
for (const key in keybindings) {
|
||||
Main.wm.addKeybinding(
|
||||
key,
|
||||
this.kbdSettings,
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
Shell.ActionMode.NORMAL,
|
||||
keybindings[key]
|
||||
);
|
||||
}
|
||||
|
||||
Logger.debug(`keybindings:enable`);
|
||||
}
|
||||
|
||||
disable() {
|
||||
let keybindings = this._bindings;
|
||||
|
||||
for (const key in keybindings) {
|
||||
Main.wm.removeKeybinding(key);
|
||||
}
|
||||
|
||||
Logger.debug(`keybindings:disable`);
|
||||
}
|
||||
|
||||
// @deprecated
|
||||
enableListenForBindings() {
|
||||
windowConfig.forEach((config) => {
|
||||
config.shortcut.forEach((shortcut) => {
|
||||
this.listenFor(shortcut, () => {
|
||||
config.actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// @deprecated
|
||||
disableListenForBindings() {
|
||||
// The existing grabber items are from the custom config by
|
||||
// this extension.
|
||||
this._grabbers.forEach((grabber) => {
|
||||
global.display.ungrab_accelerator(grabber.action);
|
||||
Main.wm.allowKeybinding(grabber.name, Shell.ActionMode.NONE);
|
||||
});
|
||||
|
||||
this._grabbers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* API for quick binding of keys to function. This is going to be useful with SpaceMode
|
||||
*
|
||||
* @param {String} accelerator - keybinding combinations
|
||||
* @param {Function} callback - function to call when the accelerator is invoked
|
||||
*
|
||||
* Credits:
|
||||
* - https://superuser.com/a/1182899
|
||||
* - Adapted based on current Gnome-shell API or syntax
|
||||
*/
|
||||
listenFor(accelerator, callback) {
|
||||
let grabFlags = Meta.KeyBindingFlags.NONE;
|
||||
let action = global.display.grab_accelerator(accelerator, grabFlags);
|
||||
|
||||
if (action == Meta.KeyBindingAction.NONE) {
|
||||
Logger.error(`Unable to grab accelerator [binding={${accelerator}}]`);
|
||||
// TODO - check the gnome keybindings for conflicts and notify the user
|
||||
} else {
|
||||
let name = Meta.external_binding_name_for_action(action);
|
||||
|
||||
Logger.debug(`Requesting WM to allow binding [name={${name}}]`);
|
||||
Main.wm.allowKeybinding(name, Shell.ActionMode.ALL);
|
||||
|
||||
this._grabbers.set(action, {
|
||||
name: name,
|
||||
accelerator: accelerator,
|
||||
callback: callback,
|
||||
action: action,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get modifierState() {
|
||||
const [_x, _y, state] = this.extWm.getPointer();
|
||||
return state;
|
||||
}
|
||||
|
||||
allowDragDropTile() {
|
||||
const tileModifier = this.kbdSettings.get_string("mod-mask-mouse-tile");
|
||||
const modState = this.modifierState;
|
||||
// Using Clutter.ModifierType values and also testing for pointer
|
||||
// being grabbed (256). E.g. grabbed + pressing Super = 256 + 64 = 320
|
||||
// See window.js#_handleMoving() - an overlay preview is shown.
|
||||
// See window.js#_handleGrabOpEnd() - when the drag has been dropped
|
||||
switch (tileModifier) {
|
||||
case "Super":
|
||||
return modState === 64 || modState === 320;
|
||||
case "Alt":
|
||||
return modState === 8 || modState === 264;
|
||||
case "Ctrl":
|
||||
return modState === 4 || modState === 260;
|
||||
case "None":
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
buildBindingDefinitions() {
|
||||
this._bindings = {
|
||||
"window-toggle-float": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "FloatToggle",
|
||||
mode: "float",
|
||||
x: "center",
|
||||
y: "center",
|
||||
width: 0.65,
|
||||
height: 0.75,
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-toggle-always-float": () => {
|
||||
let action = {
|
||||
name: "FloatClassToggle",
|
||||
mode: "float",
|
||||
x: "center",
|
||||
y: "center",
|
||||
width: 0.65,
|
||||
height: 0.75,
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-focus-left": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Focus",
|
||||
direction: "Left",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-focus-down": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Focus",
|
||||
direction: "Down",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-focus-up": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Focus",
|
||||
direction: "Up",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-focus-right": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Focus",
|
||||
direction: "Right",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-swap-left": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Swap",
|
||||
direction: "Left",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-swap-down": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Swap",
|
||||
direction: "Down",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-swap-up": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Swap",
|
||||
direction: "Up",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-swap-right": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Swap",
|
||||
direction: "Right",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-move-left": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Move",
|
||||
direction: "Left",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-move-down": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Move",
|
||||
direction: "Down",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-move-up": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Move",
|
||||
direction: "Up",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"window-move-right": () => {
|
||||
let actions = [
|
||||
{
|
||||
name: "Move",
|
||||
direction: "Right",
|
||||
},
|
||||
];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"con-split-layout-toggle": () => {
|
||||
let actions = [{ name: "LayoutToggle" }];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"con-split-vertical": () => {
|
||||
let actions = [{ name: "Split", orientation: "vertical" }];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"con-split-horizontal": () => {
|
||||
let actions = [{ name: "Split", orientation: "horizontal" }];
|
||||
actions.forEach((action) => {
|
||||
this.extWm.command(action);
|
||||
});
|
||||
},
|
||||
"con-stacked-layout-toggle": () => {
|
||||
let action = { name: "LayoutStackedToggle" };
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"con-tabbed-layout-toggle": () => {
|
||||
let action = { name: "LayoutTabbedToggle" };
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"con-tabbed-showtab-decoration-toggle": () => {
|
||||
let action = { name: "ShowTabDecorationToggle" };
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"focus-border-toggle": () => {
|
||||
let action = { name: "FocusBorderToggle" };
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"prefs-tiling-toggle": () => {
|
||||
let action = { name: "TilingModeToggle" };
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-gap-size-increase": () => {
|
||||
let action = { name: "GapSize", amount: 1 };
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-gap-size-decrease": () => {
|
||||
let action = { name: "GapSize", amount: -1 };
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"workspace-active-tile-toggle": () => {
|
||||
let action = { name: "WorkspaceActiveTileToggle" };
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"prefs-open": () => {
|
||||
let action = { name: "PrefsOpen" };
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-swap-last-active": () => {
|
||||
let action = {
|
||||
name: "WindowSwapLastActive",
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-snap-one-third-right": () => {
|
||||
let action = {
|
||||
name: "SnapLayoutMove",
|
||||
direction: "Right",
|
||||
amount: 1 / 3,
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-snap-two-third-right": () => {
|
||||
let action = {
|
||||
name: "SnapLayoutMove",
|
||||
direction: "Right",
|
||||
amount: 2 / 3,
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-snap-one-third-left": () => {
|
||||
let action = {
|
||||
name: "SnapLayoutMove",
|
||||
direction: "Left",
|
||||
amount: 1 / 3,
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-snap-two-third-left": () => {
|
||||
let action = {
|
||||
name: "SnapLayoutMove",
|
||||
direction: "Left",
|
||||
amount: 2 / 3,
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-snap-center": () => {
|
||||
let action = {
|
||||
name: "SnapLayoutMove",
|
||||
direction: "Center",
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-resize-top-increase": () => {
|
||||
let action = {
|
||||
name: "WindowResizeTop",
|
||||
amount: this.settings.get_uint("resize-amount"),
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-resize-top-decrease": () => {
|
||||
let action = {
|
||||
name: "WindowResizeTop",
|
||||
amount: -1 * this.settings.get_uint("resize-amount"),
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-resize-bottom-increase": () => {
|
||||
let action = {
|
||||
name: "WindowResizeBottom",
|
||||
amount: this.settings.get_uint("resize-amount"),
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-resize-bottom-decrease": () => {
|
||||
let action = {
|
||||
name: "WindowResizeBottom",
|
||||
amount: -1 * this.settings.get_uint("resize-amount"),
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-resize-left-increase": () => {
|
||||
let action = {
|
||||
name: "WindowResizeLeft",
|
||||
amount: this.settings.get_uint("resize-amount"),
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-resize-left-decrease": () => {
|
||||
let action = {
|
||||
name: "WindowResizeLeft",
|
||||
amount: -1 * this.settings.get_uint("resize-amount"),
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-resize-right-increase": () => {
|
||||
let action = {
|
||||
name: "WindowResizeRight",
|
||||
amount: this.settings.get_uint("resize-amount"),
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
"window-resize-right-decrease": () => {
|
||||
let action = {
|
||||
name: "WindowResizeRight",
|
||||
amount: -1 * this.settings.get_uint("resize-amount"),
|
||||
};
|
||||
this.extWm.command(action);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,407 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Forge extension for GNOME
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Credits:
|
||||
* This file has some code from Dash-To-Panel extension: convenience.js
|
||||
* Some code was also adapted from the upstream Gnome Shell source code.
|
||||
*/
|
||||
|
||||
// Gnome imports
|
||||
import Meta from "gi://Meta";
|
||||
import St from "gi://St";
|
||||
|
||||
// Gnome-shell imports
|
||||
import { PACKAGE_VERSION } from "resource:///org/gnome/shell/misc/config.js";
|
||||
|
||||
// App imports
|
||||
import { ORIENTATION_TYPES, LAYOUT_TYPES, POSITION } from "./tree.js";
|
||||
import { GRAB_TYPES } from "./window.js";
|
||||
|
||||
const [major] = PACKAGE_VERSION.split(".").map((s) => Number(s));
|
||||
|
||||
/**
|
||||
*
|
||||
* Turns an array into an immutable enum-like object
|
||||
*
|
||||
*/
|
||||
export function createEnum(anArray) {
|
||||
const enumObj = {};
|
||||
for (const val of anArray) {
|
||||
enumObj[val] = val;
|
||||
}
|
||||
return Object.freeze(enumObj);
|
||||
}
|
||||
|
||||
export function resolveX(rectRequest, metaWindow) {
|
||||
let metaRect = metaWindow.get_frame_rect();
|
||||
let monitorRect = metaWindow.get_work_area_current_monitor();
|
||||
let val = metaRect.x;
|
||||
let x = rectRequest.x;
|
||||
switch (typeof x) {
|
||||
case "string": //center,
|
||||
switch (x) {
|
||||
case "center":
|
||||
val = monitorRect.width * 0.5 - this.resolveWidth(rectRequest, metaWindow) * 0.5;
|
||||
break;
|
||||
case "left":
|
||||
val = 0;
|
||||
break;
|
||||
case "right":
|
||||
val = monitorRect.width - this.resolveWidth(rectRequest, metaWindow);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "number":
|
||||
val = x;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
val = monitorRect.x + val;
|
||||
return val;
|
||||
}
|
||||
|
||||
export function resolveY(rectRequest, metaWindow) {
|
||||
let metaRect = metaWindow.get_frame_rect();
|
||||
let monitorRect = metaWindow.get_work_area_current_monitor();
|
||||
let val = metaRect.y;
|
||||
let y = rectRequest.y;
|
||||
switch (typeof y) {
|
||||
case "string": //center,
|
||||
switch (y) {
|
||||
case "center":
|
||||
val = monitorRect.height * 0.5 - this.resolveHeight(rectRequest, metaWindow) * 0.5;
|
||||
break;
|
||||
case "top":
|
||||
val = 0;
|
||||
break;
|
||||
case "bottom": // inverse of y=0
|
||||
val = monitorRect.height - this.resolveHeight(rectRequest, metaWindow);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "number":
|
||||
val = y;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
val = monitorRect.y + val;
|
||||
return val;
|
||||
}
|
||||
|
||||
export function resolveWidth(rectRequest, metaWindow) {
|
||||
let metaRect = metaWindow.get_frame_rect();
|
||||
let monitorRect = metaWindow.get_work_area_current_monitor();
|
||||
let val = metaRect.width;
|
||||
let width = rectRequest.width;
|
||||
switch (typeof width) {
|
||||
case "number":
|
||||
if (Number.isInteger(width) && width != 1) {
|
||||
val = width;
|
||||
} else {
|
||||
let monitorWidth = monitorRect.width;
|
||||
val = monitorWidth * width;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
export function resolveHeight(rectRequest, metaWindow) {
|
||||
let metaRect = metaWindow.get_frame_rect();
|
||||
let monitorRect = metaWindow.get_work_area_current_monitor();
|
||||
let val = metaRect.height;
|
||||
let height = rectRequest.height;
|
||||
switch (typeof height) {
|
||||
case "number":
|
||||
if (Number.isInteger(height) && height != 1) {
|
||||
val = height;
|
||||
} else {
|
||||
let monitorHeight = monitorRect.height;
|
||||
val = monitorHeight * height;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
export function orientationFromDirection(direction) {
|
||||
return direction === Meta.MotionDirection.LEFT || direction === Meta.MotionDirection.RIGHT
|
||||
? ORIENTATION_TYPES.HORIZONTAL
|
||||
: ORIENTATION_TYPES.VERTICAL;
|
||||
}
|
||||
|
||||
export function orientationFromLayout(layout) {
|
||||
switch (layout) {
|
||||
case LAYOUT_TYPES.HSPLIT:
|
||||
case LAYOUT_TYPES.TABBED:
|
||||
return ORIENTATION_TYPES.HORIZONTAL;
|
||||
case LAYOUT_TYPES.VSPLIT:
|
||||
case LAYOUT_TYPES.STACKED:
|
||||
return ORIENTATION_TYPES.VERTICAL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export function positionFromDirection(direction) {
|
||||
return direction === Meta.MotionDirection.LEFT || direction === Meta.MotionDirection.UP
|
||||
? POSITION.BEFORE
|
||||
: POSITION.AFTER;
|
||||
}
|
||||
|
||||
export function resolveDirection(directionString) {
|
||||
if (directionString) {
|
||||
directionString = directionString.toUpperCase();
|
||||
|
||||
if (directionString === "LEFT") {
|
||||
return Meta.MotionDirection.LEFT;
|
||||
}
|
||||
|
||||
if (directionString === "RIGHT") {
|
||||
return Meta.MotionDirection.RIGHT;
|
||||
}
|
||||
|
||||
if (directionString === "UP") {
|
||||
return Meta.MotionDirection.UP;
|
||||
}
|
||||
|
||||
if (directionString === "DOWN") {
|
||||
return Meta.MotionDirection.DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function directionFrom(position, orientation) {
|
||||
if (position === POSITION.AFTER) {
|
||||
if (orientation === ORIENTATION_TYPES.HORIZONTAL) {
|
||||
return Meta.DisplayDirection.RIGHT;
|
||||
} else {
|
||||
return Meta.DisplayDirection.DOWN;
|
||||
}
|
||||
} else if (position === POSITION.BEFORE) {
|
||||
if (orientation === ORIENTATION_TYPES.HORIZONTAL) {
|
||||
return Meta.DisplayDirection.LEFT;
|
||||
} else {
|
||||
return Meta.DisplayDirection.UP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function rectContainsPoint(rect, pointP) {
|
||||
if (!(rect && pointP)) return false;
|
||||
return (
|
||||
rect.x <= pointP[0] &&
|
||||
pointP[0] <= rect.x + rect.width &&
|
||||
rect.y <= pointP[1] &&
|
||||
pointP[1] <= rect.y + rect.height
|
||||
);
|
||||
}
|
||||
|
||||
export function orientationFromGrab(grabOp) {
|
||||
if (
|
||||
grabOp === Meta.GrabOp.RESIZING_N ||
|
||||
grabOp === Meta.GrabOp.RESIZING_S ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_N ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_S
|
||||
) {
|
||||
return ORIENTATION_TYPES.VERTICAL;
|
||||
} else if (
|
||||
grabOp === Meta.GrabOp.RESIZING_E ||
|
||||
grabOp === Meta.GrabOp.RESIZING_W ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_E ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_W
|
||||
) {
|
||||
return ORIENTATION_TYPES.HORIZONTAL;
|
||||
}
|
||||
return ORIENTATION_TYPES.NONE;
|
||||
}
|
||||
|
||||
export function positionFromGrabOp(grabOp) {
|
||||
if (
|
||||
grabOp === Meta.GrabOp.RESIZING_W ||
|
||||
grabOp === Meta.GrabOp.RESIZING_N ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_W ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_N
|
||||
) {
|
||||
return POSITION.BEFORE;
|
||||
} else if (
|
||||
grabOp === Meta.GrabOp.RESIZING_E ||
|
||||
grabOp === Meta.GrabOp.RESIZING_S ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_E ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_S
|
||||
) {
|
||||
return POSITION.AFTER;
|
||||
}
|
||||
return POSITION.UNKNOWN;
|
||||
}
|
||||
|
||||
export function allowResizeGrabOp(grabOp) {
|
||||
grabOp &= ~1024; // ignore META_GRAB_OP_WINDOW_FLAG_UNCONSTRAINED
|
||||
return (
|
||||
grabOp === Meta.GrabOp.RESIZING_N ||
|
||||
grabOp === Meta.GrabOp.RESIZING_E ||
|
||||
grabOp === Meta.GrabOp.RESIZING_W ||
|
||||
grabOp === Meta.GrabOp.RESIZING_S ||
|
||||
grabOp === Meta.GrabOp.RESIZING_NE ||
|
||||
grabOp === Meta.GrabOp.RESIZING_NW ||
|
||||
grabOp === Meta.GrabOp.RESIZING_SE ||
|
||||
grabOp === Meta.GrabOp.RESIZING_SW ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_N ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_E ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_W ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_S ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_UNKNOWN
|
||||
);
|
||||
}
|
||||
|
||||
export function grabMode(grabOp) {
|
||||
grabOp &= ~1024; // ignore META_GRAB_OP_WINDOW_FLAG_UNCONSTRAINED
|
||||
if (
|
||||
grabOp === Meta.GrabOp.RESIZING_N ||
|
||||
grabOp === Meta.GrabOp.RESIZING_E ||
|
||||
grabOp === Meta.GrabOp.RESIZING_W ||
|
||||
grabOp === Meta.GrabOp.RESIZING_S ||
|
||||
grabOp === Meta.GrabOp.RESIZING_NE ||
|
||||
grabOp === Meta.GrabOp.RESIZING_NW ||
|
||||
grabOp === Meta.GrabOp.RESIZING_SE ||
|
||||
grabOp === Meta.GrabOp.RESIZING_SW ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_N ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_E ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_W ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_S ||
|
||||
grabOp === Meta.GrabOp.KEYBOARD_RESIZING_UNKNOWN
|
||||
) {
|
||||
return GRAB_TYPES.RESIZING;
|
||||
} else if (
|
||||
grabOp === Meta.GrabOp.KEYBOARD_MOVING ||
|
||||
grabOp === Meta.GrabOp.MOVING ||
|
||||
grabOp === Meta.GrabOp.MOVING_UNCONSTRAINED
|
||||
) {
|
||||
return GRAB_TYPES.MOVING;
|
||||
}
|
||||
return GRAB_TYPES.UNKNOWN;
|
||||
}
|
||||
|
||||
export function decomposeGrabOp(grabOp) {
|
||||
grabOp &= ~1024; // ignore META_GRAB_OP_WINDOW_FLAG_UNCONSTRAINED
|
||||
switch (grabOp) {
|
||||
case Meta.GrabOp.RESIZING_NE:
|
||||
return [Meta.GrabOp.RESIZING_N, Meta.GrabOp.RESIZING_E];
|
||||
case Meta.GrabOp.RESIZING_NW:
|
||||
return [Meta.GrabOp.RESIZING_N, Meta.GrabOp.RESIZING_W];
|
||||
case Meta.GrabOp.RESIZING_SE:
|
||||
return [Meta.GrabOp.RESIZING_S, Meta.GrabOp.RESIZING_E];
|
||||
case Meta.GrabOp.RESIZING_SW:
|
||||
return [Meta.GrabOp.RESIZING_S, Meta.GrabOp.RESIZING_W];
|
||||
default:
|
||||
return [grabOp];
|
||||
}
|
||||
}
|
||||
|
||||
export function directionFromGrab(grabOp) {
|
||||
if (grabOp === Meta.GrabOp.RESIZING_E || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_E) {
|
||||
return Meta.MotionDirection.RIGHT;
|
||||
} else if (grabOp === Meta.GrabOp.RESIZING_W || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_W) {
|
||||
return Meta.MotionDirection.LEFT;
|
||||
} else if (grabOp === Meta.GrabOp.RESIZING_N || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_N) {
|
||||
return Meta.MotionDirection.UP;
|
||||
} else if (grabOp === Meta.GrabOp.RESIZING_S || grabOp === Meta.GrabOp.KEYBOARD_RESIZING_S) {
|
||||
return Meta.MotionDirection.DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
export function removeGapOnRect(rectWithGap, gap) {
|
||||
rectWithGap.x = rectWithGap.x -= gap;
|
||||
rectWithGap.y = rectWithGap.y -= gap;
|
||||
rectWithGap.width = rectWithGap.width += gap * 2;
|
||||
rectWithGap.height = rectWithGap.height += gap * 2;
|
||||
return rectWithGap;
|
||||
}
|
||||
|
||||
// Credits: PopShell
|
||||
export function findWindowWith(title) {
|
||||
let display = global.display;
|
||||
let type = Meta.TabList.NORMAL_ALL;
|
||||
let workspaceMgr = display.get_workspace_manager();
|
||||
let workspaces = workspaceMgr.get_n_workspaces();
|
||||
|
||||
for (let wsId = 1; wsId <= workspaces; wsId++) {
|
||||
let workspace = workspaceMgr.get_workspace_by_index(wsId);
|
||||
for (const metaWindow of display.get_tab_list(type, workspace)) {
|
||||
if (
|
||||
metaWindow.title &&
|
||||
title &&
|
||||
(metaWindow.title === title || metaWindow.title.includes(title))
|
||||
) {
|
||||
return metaWindow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function oppositeDirectionOf(direction) {
|
||||
if (direction === Meta.MotionDirection.LEFT) {
|
||||
return Meta.MotionDirection.RIGHT;
|
||||
} else if (direction === Meta.MotionDirection.RIGHT) {
|
||||
return Meta.MotionDirection.LEFT;
|
||||
} else if (direction === Meta.MotionDirection.UP) {
|
||||
return Meta.MotionDirection.DOWN;
|
||||
} else if (direction === Meta.MotionDirection.DOWN) {
|
||||
return Meta.MotionDirection.UP;
|
||||
}
|
||||
}
|
||||
|
||||
export function monitorIndex(monitorValue) {
|
||||
if (!monitorValue) return -1;
|
||||
let wsIndex = monitorValue.indexOf("ws");
|
||||
let indexVal = monitorValue.slice(0, wsIndex);
|
||||
indexVal = indexVal.replace("mo", "");
|
||||
return parseInt(indexVal);
|
||||
}
|
||||
|
||||
export function _disableDecorations() {
|
||||
let decos = global.window_group.get_children().filter((a) => a.type != null);
|
||||
decos.forEach((d) => {
|
||||
global.window_group.remove_child(d);
|
||||
d.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
export function dpi() {
|
||||
return St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
}
|
||||
|
||||
export function isGnome(majorVersion) {
|
||||
return major == majorVersion;
|
||||
}
|
||||
|
||||
export function isGnomeGTE(majorVersion) {
|
||||
return major >= majorVersion;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user