mirror of
https://github.com/gosticks/PaperWM.git
synced 2026-03-02 04:32:52 +00:00
Needed due to weird hang (sometimes crash) when creating (probably only when done rapidly?) same relocatable setting more than once. (noticed when implementing workspace settings cycling)
260 lines
7.4 KiB
JavaScript
260 lines
7.4 KiB
JavaScript
/**
|
|
|
|
Settings utility shared between the running extension and the preference UI.
|
|
|
|
*/
|
|
var Extension;
|
|
if (imports.misc.extensionUtils.extensions) {
|
|
Extension = imports.misc.extensionUtils.extensions["paperwm@hedning:matrix.org"];
|
|
} else {
|
|
// Cannot relaiably test for imports.ui in the preference ui
|
|
try {
|
|
Extension = imports.ui.main.extensionManager.lookup("paperwm@hedning:matrix.org");
|
|
} catch(e) {
|
|
Extension = imports.misc.extensionUtils.getCurrentExtension();
|
|
}
|
|
}
|
|
|
|
var Gio = imports.gi.Gio;
|
|
var GLib = imports.gi.GLib;
|
|
var Gtk = imports.gi.Gtk;
|
|
|
|
var Convenience = Extension.imports.convenience;
|
|
var settings = Convenience.getSettings();
|
|
var workspaceSettingsCache = {};
|
|
|
|
var WORKSPACE_KEY = 'org.gnome.Shell.Extensions.PaperWM.Workspace';
|
|
var WORKSPACE_LIST_KEY = 'org.gnome.Shell.Extensions.PaperWM.WorkspaceList';
|
|
var KEYBINDINGS_KEY = 'org.gnome.Shell.Extensions.PaperWM.Keybindings';
|
|
|
|
// This is the value mutter uses for the keyvalue of above_tab
|
|
var META_KEY_ABOVE_TAB = 0x2f7259c9;
|
|
|
|
var prefs = {};
|
|
['window-gap', 'vertical-margin', 'vertical-margin-bottom', 'horizontal-margin',
|
|
'workspace-colors', 'default-background', 'animation-time', 'use-workspace-name',
|
|
'pressure-barrier', 'default-show-top-bar', 'swipe-sensitivity',
|
|
'cycle-width-steps', 'cycle-height-steps']
|
|
.forEach((k) => setState(null, k));
|
|
|
|
function setVerticalMargin() {
|
|
let vMargin = settings.get_int('vertical-margin');
|
|
let gap = settings.get_int('window-gap');
|
|
prefs.vertical_margin = Math.max(Math.round(gap/2), vMargin);
|
|
}
|
|
let timerId;
|
|
function onWindowGapChanged() {
|
|
setVerticalMargin();
|
|
if (timerId)
|
|
imports.mainloop.source_remove(timerId);
|
|
timerId = imports.mainloop.timeout_add(500, () => {
|
|
Extension.imports.tiling.spaces.mru().forEach(space => {
|
|
space.layout();
|
|
});
|
|
timerId = null;
|
|
});
|
|
}
|
|
|
|
function setState($, key) {
|
|
let value = settings.get_value(key);
|
|
let name = key.replace(/-/g, '_');
|
|
prefs[name] = value.deep_unpack();
|
|
}
|
|
|
|
var schemaSource, workspaceList, conflictSettings;
|
|
function setSchemas() {
|
|
// Schemas that may contain conflicting keybindings
|
|
// It's possible to inject or remove settings here on `user.init`.
|
|
conflictSettings = [
|
|
new Gio.Settings({schema_id: 'org.gnome.mutter.keybindings'}),
|
|
new Gio.Settings({schema_id: 'org.gnome.mutter.wayland.keybindings'}),
|
|
new Gio.Settings({schema_id: "org.gnome.desktop.wm.keybindings"}),
|
|
new Gio.Settings({schema_id: "org.gnome.shell.keybindings"})
|
|
];
|
|
schemaSource = Gio.SettingsSchemaSource.new_from_directory(
|
|
GLib.build_filenamev([Extension.path, "schemas"]),
|
|
Gio.SettingsSchemaSource.get_default(),
|
|
false
|
|
);
|
|
|
|
workspaceList = new Gio.Settings({
|
|
settings_schema: schemaSource.lookup(WORKSPACE_LIST_KEY, true)
|
|
});
|
|
}
|
|
setSchemas(); // Initialize imediately so prefs.js can import properly
|
|
function init() {
|
|
settings.connect('changed', setState);
|
|
settings.connect('changed::vertical-margin', onWindowGapChanged);
|
|
settings.connect('changed::vertical-margin-bottom', onWindowGapChanged);
|
|
settings.connect('changed::window-gap', onWindowGapChanged);
|
|
setVerticalMargin();
|
|
|
|
// A intermediate window is created before the prefs dialog is created.
|
|
// Prevent it from being inserted into the tiling causing flickering and general disorder
|
|
defwinprop({
|
|
wm_class: "Gnome-shell-extension-prefs",
|
|
scratch_layer: true,
|
|
focus: true,
|
|
});
|
|
}
|
|
|
|
var id;
|
|
function enable() {
|
|
setSchemas();
|
|
}
|
|
|
|
function disable() {
|
|
workspaceSettingsCache = {};
|
|
}
|
|
|
|
/// Workspaces
|
|
|
|
|
|
function getWorkspaceSettings(index) {
|
|
let list = workspaceList.get_strv('list');
|
|
for (let uuid of list) {
|
|
let settings = getWorkspaceSettingsByUUID(uuid);
|
|
if (settings.get_int('index') === index) {
|
|
return [uuid, settings];
|
|
}
|
|
}
|
|
return getNewWorkspaceSettings(index);
|
|
}
|
|
|
|
function getNewWorkspaceSettings(index) {
|
|
let uuid = GLib.uuid_string_random();
|
|
let settings = getWorkspaceSettingsByUUID(uuid);
|
|
let list = workspaceList.get_strv('list');
|
|
list.push(uuid);
|
|
workspaceList.set_strv('list', list);
|
|
settings.set_int('index', index);
|
|
return [uuid, settings];
|
|
}
|
|
|
|
function getWorkspaceSettingsByUUID(uuid) {
|
|
if (!workspaceSettingsCache[uuid]) {
|
|
let settings = new Gio.Settings({
|
|
settings_schema: schemaSource.lookup(WORKSPACE_KEY, true),
|
|
path: `/org/gnome/shell/extensions/paperwm/workspaces/${uuid}/`
|
|
});
|
|
workspaceSettingsCache[uuid] = settings;
|
|
}
|
|
return workspaceSettingsCache[uuid];
|
|
}
|
|
|
|
/// Keybindings
|
|
|
|
/**
|
|
* Two keystrings can represent the same key combination
|
|
*/
|
|
function keystrToKeycombo(keystr) {
|
|
// Above_Tab is a fake keysymbol provided by mutter
|
|
let aboveTab = false;
|
|
if (keystr.match(/Above_Tab/)) {
|
|
// Gtk bails out if provided with an unknown keysymbol
|
|
keystr = keystr.replace('Above_Tab', 'A');
|
|
aboveTab = true;
|
|
}
|
|
let [key, mask] = Gtk.accelerator_parse(keystr);
|
|
if (aboveTab)
|
|
key = META_KEY_ABOVE_TAB;
|
|
return `${key}|${mask}`; // Since js doesn't have a mapable tuple type
|
|
}
|
|
|
|
function keycomboToKeystr(combo) {
|
|
let [mutterKey, mods] = combo.split('|').map(s => Number.parseInt(s));
|
|
let key = mutterKey;
|
|
if (mutterKey === META_KEY_ABOVE_TAB)
|
|
key = 97; // a
|
|
let keystr = Gtk.accelerator_name(key, mods);
|
|
if (mutterKey === META_KEY_ABOVE_TAB)
|
|
keystr = keystr.replace(/a$/, 'Above_Tab');
|
|
return keystr;
|
|
}
|
|
|
|
function generateKeycomboMap(settings) {
|
|
let map = {};
|
|
for (let name of settings.list_keys()) {
|
|
let value = settings.get_value(name);
|
|
if (value.get_type_string() !== 'as')
|
|
continue;
|
|
|
|
for (let combo of value.deep_unpack().map(keystrToKeycombo)) {
|
|
if (combo === '0|0')
|
|
continue;
|
|
if (map[combo]) {
|
|
map[combo].push(name);
|
|
} else {
|
|
map[combo] = [name];
|
|
}
|
|
}
|
|
}
|
|
return map;
|
|
}
|
|
|
|
function findConflicts(schemas) {
|
|
schemas = schemas || conflictSettings;
|
|
let conflicts = [];
|
|
const paperMap =
|
|
generateKeycomboMap(Convenience.getSettings(KEYBINDINGS_KEY));
|
|
|
|
for (let settings of schemas) {
|
|
const against = generateKeycomboMap(settings);
|
|
for (let combo in paperMap) {
|
|
if (against[combo]) {
|
|
conflicts.push({
|
|
name: paperMap[combo][0],
|
|
conflicts: against[combo],
|
|
settings, combo
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return conflicts;
|
|
}
|
|
|
|
|
|
/// Winprops
|
|
|
|
/**
|
|
Modelled after notion/ion3's system
|
|
|
|
Examples:
|
|
|
|
defwinprop({
|
|
wm_class: "Riot",
|
|
scratch_layer: true
|
|
})
|
|
*/
|
|
var winprops = [];
|
|
|
|
function winprop_match_p(meta_window, prop) {
|
|
let wm_class = meta_window.wm_class || "";
|
|
let title = meta_window.title;
|
|
if (prop.wm_class !== wm_class) {
|
|
return false;
|
|
}
|
|
if (prop.title) {
|
|
if (prop.title.constructor === RegExp) {
|
|
if (!title.match(prop.title))
|
|
return false;
|
|
} else {
|
|
if (prop.title !== title)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function find_winprop(meta_window) {
|
|
let props = winprops.filter(
|
|
winprop_match_p.bind(null, meta_window));
|
|
|
|
return props[0];
|
|
}
|
|
|
|
function defwinprop(spec) {
|
|
winprops.push(spec);
|
|
}
|