From 3781e627747b0761ce27a30e2087926a2cc0e2f8 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Fri, 15 Sep 2023 22:12:02 +1000 Subject: [PATCH 01/50] Ported App.js to ESM. --- .eslintrc.yml | 1 + app.js | 15 +++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index 1907519c..2daf31d2 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -277,3 +277,4 @@ globals: clearInterval: readonly parserOptions: ecmaVersion: 2022 + sourceType: module diff --git a/app.js b/app.js index b2883a16..a7286f33 100644 --- a/app.js +++ b/app.js @@ -1,14 +1,13 @@ +import * as ExtensionModule from './extension.js'; +import * as Patches from './patches.js'; +import * as Tiling from './tiling.js'; +import GLib from 'gi://GLib'; +import Gio from 'gi://Gio'; +import Shell from 'gi://Shell'; + /* Application functionality, like global new window actions etc. */ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const ExtensionModule = Extension.imports.extension; -const Patches = Extension.imports.patches; -const Tiling = Extension.imports.tiling; -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; -const Shell = imports.gi.Shell; let Tracker = Shell.WindowTracker.get_default(); let CouldNotLaunch = Symbol(); From 5b48bf1c4fe9bfcead2cbf96249d4bece1e928c4 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 00:08:44 +1000 Subject: [PATCH 02/50] WIP: porting `extensions.js`. --- extension.js | 356 +++++++++++++++++++++++++++------------------------ 1 file changed, 187 insertions(+), 169 deletions(-) diff --git a/extension.js b/extension.js index f25909a3..d0c89f8f 100644 --- a/extension.js +++ b/extension.js @@ -1,10 +1,13 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Navigator = Extension.imports.navigator; -const { Gio, GLib, St } = imports.gi; -const Util = imports.misc.util; -const MessageTray = imports.ui.messageTray; -const Main = imports.ui.main; +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; +import St from 'gi://St'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as MessageTray from 'resource:///org/gnome/shell/ui/messageTray.js'; +import * as Navigator from './navigator.js'; +import * as Util from 'resource:///org/gnome/shell/misc/util.js'; + +import { Extension, dir } from 'resource:///org/gnome/shell/extensions/extension.js'; /** The currently used modules @@ -44,211 +47,226 @@ const modules = [ 'patches', 'app', // these have `enable` dependency order ]; -/** - Tell the modules to run enable or disable. - */ -function run(method, reverse = false) { - // reverse order an array (useful for controlling execution order) - let arr = reverse ? [...modules].reverse() : modules; - for (let name of arr) { +export default class PaperWM extends Extension { + #firstEnable = true; + #userStylesheet = null; + + /** + Tell the modules to run enable or disable. + */ + run(method, reverse = false) { + // reverse order an array (useful for controlling execution order) + let arr = reverse ? [...modules].reverse() : modules; + for (let name of arr) { // Bail if there's an error in our own modules - if (!safeCall(name, method)) { - return false; + if (!this.safeCall(name, method)) { + return false; + } } - } - // run 'user.js' methods (if it exists) - if (hasUserConfigFile()) { + /* + // run 'user.js' methods (if it exists) + if (this.hasUserConfigFile()) { // if enable method, call 'init' for backwards compat and then enable - if (method === 'enable') { - if (firstEnable) { - safeCall('user', 'init'); + if (method === 'enable') { + if (this.#firstEnable) { + this.safeCall('user', 'init'); + } + this.safeCall('user', 'enable'); + } + else { + this.safeCall('user', method); } - safeCall('user', 'enable'); - } - else { - safeCall('user', method); } - } + */ - return true; -} + return true; + } -function safeCall(name, method) { - try { - let module = Extension.imports[name]; - if (module && module[method]) { - console.debug("#paperwm", `${method} ${name}`); + safeCall(name, method) { + try { + let module = Extension.imports[name]; + if (module && module[method]) { + console.debug("#paperwm", `${method} ${name}`); + } + module && module[method] && module[method].call(module, errorNotification); + return true; + } catch (e) { + console.error("#paperwm", `${name} failed ${method}`); + console.error(`JS ERROR: ${e}\n${e.stack}`); + this.errorNotification( + "PaperWM", + `Error occured in ${name} @${method}:\n\n${e.message}`, + e.stack); + return false; } - module && module[method] && module[method].call(module, errorNotification); - return true; - } catch (e) { - console.error("#paperwm", `${name} failed ${method}`); - console.error(`JS ERROR: ${e}\n${e.stack}`); - errorNotification( - "PaperWM", - `Error occured in ${name} @${method}:\n\n${e.message}`, - e.stack); - return false; } -} -let firstEnable = true; -function enable() { - console.log(`#PaperWM enabled`); + enable() { + console.log(`#PaperWM enabled`); - enableUserConfig(); - enableUserStylesheet(); + // 45 SearchPath doesn't exist in 45... + // this.enableUserConfig(); + this.enableUserStylesheet(); - if (run('enable')) { - firstEnable = false; + if (this.run('enable')) { + this.#firstEnable = false; + } } -} -/** + /** * Prepares PaperWM for disable across modules. */ -function prepareForDisable() { + prepareForDisable() { /** * Finish any navigation (e.g. workspace switch view). * Can put PaperWM in a breakable state of lock/disable * while navigating. */ - Navigator.finishNavigation(); -} - -function disable() { - console.log('#PaperWM disabled'); - prepareForDisable(); - run('disable', true); - - disableUserStylesheet(); - safeCall('user', 'disable'); -} - -function getConfigDir() { - return Gio.file_new_for_path(`${GLib.get_user_config_dir()}/paperwm`); -} + Navigator.finishNavigation(); + } -function configDirExists() { - return getConfigDir().query_exists(null); -} + disable() { + console.log('#PaperWM disabled'); + this.prepareForDisable(); + this.run('disable', true); -function hasUserConfigFile() { - return getConfigDir().get_child("user.js").query_exists(null); -} + this.disableUserStylesheet(); + this.safeCall('user', 'disable'); + } -/** - * Update the metadata.json in user config dir to always keep it up to date. - * We copy metadata.json to the config directory so gnome-shell-mode - * knows which extension the files belong to (ideally we'd symlink, but - * that trips up the importer: Extension.imports. in - * gnome-shell-mode crashes gnome-shell..) - */ -function updateUserConfigMetadata() { - if (!configDirExists()) { - return; + getConfigDir() { + return Gio.file_new_for_path(`${GLib.get_user_config_dir()}/paperwm`); } - try { - const configDir = getConfigDir(); - const metadata = Extension.dir.get_child("metadata.json"); - metadata.copy(configDir.get_child("metadata.json"), Gio.FileCopyFlags.OVERWRITE, null, null); - } catch (error) { - console.error('PaperWM', `could not update user config metadata.json: ${error}`); + configDirExists() { + return this.getConfigDir().query_exists(null); } -} -function installConfig() { - const configDir = getConfigDir(); - // if user config folder doesn't exist, create it - if (!configDirExists()) { - configDir.make_directory_with_parents(null); + hasUserConfigFile() { + return this.getConfigDir().get_child("user.js").query_exists(null); } - // Copy the user.js template to the config directory - const user = Extension.dir.get_child("config/user.js"); - user.copy(configDir.get_child("user.js"), Gio.FileCopyFlags.NONE, null, null); -} + /** + * Update the metadata.json in user config dir to always keep it up to date. + * We copy metadata.json to the config directory so gnome-shell-mode + * knows which extension the files belong to (ideally we'd symlink, but + * that trips up the importer: Extension.imports. in + * gnome-shell-mode crashes gnome-shell..) + */ + updateUserConfigMetadata() { + if (!this.configDirExists()) { + return; + } -function enableUserConfig() { - if (!configDirExists()) { try { - installConfig(); - - const configDir = getConfigDir().get_path(); - const notification = notify("PaperWM", `Installed user configuration in ${configDir}`); - notification.connect('activated', () => { - Util.spawn(["nautilus", configDir]); - notification.destroy(); - }); - } catch (e) { - errorNotification("PaperWM", `Failed to install user config: ${e.message}`, e.stack); - console.error("PaperWM", "User config install failed", e.message); + const configDir = this.getConfigDir(); + const metadata = dir.get_child("metadata.json"); + metadata.copy(configDir.get_child("metadata.json"), Gio.FileCopyFlags.OVERWRITE, null, null); + } catch (error) { + console.error('PaperWM', `could not update user config metadata.json: ${error}`); + } + } + + /* TODO: figure out something here + fmuellner: + > you can't + > as I said, it's part of gjs legacy imports + > you'll have to do something like const userMod = await import(${this.getConfigDir()}/user.js) + + installConfig() { + const configDir = this.getConfigDir(); + // if user config folder doesn't exist, create it + if (!this.configDirExists()) { + configDir.make_directory_with_parents(null); } + + // Copy the user.js template to the config directory + const user = dir.get_child("config/user.js"); + user.copy(configDir.get_child("user.js"), Gio.FileCopyFlags.NONE, null, null); } + */ + + /* + enableUserConfig() { + if (!this.configDirExists()) { + try { + this.installConfig(); + + const configDir = this.getConfigDir().get_path(); + const notification = this.notify("PaperWM", `Installed user configuration in ${configDir}`); + notification.connect('activated', () => { + Util.spawn(["nautilus", configDir]); + notification.destroy(); + }); + } catch (e) { + this.errorNotification("PaperWM", `Failed to install user config: ${e.message}`, e.stack); + console.error("PaperWM", "User config install failed", e.message); + } + } - updateUserConfigMetadata(); + this.updateUserConfigMetadata(); - // add to searchpath if user has config file and action user.js - if (hasUserConfigFile()) { - let SearchPath = Extension.imports.searchPath; - let path = getConfigDir().get_path(); - if (!SearchPath.includes(path)) { - SearchPath.push(path); + // add to searchpath if user has config file and action user.js + if (this.hasUserConfigFile()) { + let SearchPath = Extension.imports.searchPath; + let path = this.getConfigDir().get_path(); + if (!SearchPath.includes(path)) { + SearchPath.push(path); + } } } -} + */ -/** - * Reloads user.css styles (if user.css present in ~/.config/paperwm). - */ -let userStylesheet; -function enableUserStylesheet() { - userStylesheet = getConfigDir().get_child("user.css"); - if (userStylesheet.query_exists(null)) { - let themeContext = St.ThemeContext.get_for_stage(global.stage); - themeContext.get_theme().load_stylesheet(userStylesheet); + /** + * Reloads user.css styles (if user.css present in ~/.config/paperwm). + */ + enableUserStylesheet() { + this.#userStylesheet = this.getConfigDir().get_child("user.css"); + if (this.#userStylesheet.query_exists(null)) { + let themeContext = St.ThemeContext.get_for_stage(global.stage); + themeContext.get_theme().load_stylesheet(this.#userStylesheet); + } } -} -/** - * Unloads user.css styles (if user.css present in ~/.config/paperwm). - */ -function disableUserStylesheet() { - let themeContext = St.ThemeContext.get_for_stage(global.stage); - themeContext.get_theme().unload_stylesheet(userStylesheet); - userStylesheet = null; -} + /** + * Unloads user.css styles (if user.css present in ~/.config/paperwm). + */ + disableUserStylesheet() { + let themeContext = St.ThemeContext.get_for_stage(global.stage); + themeContext.get_theme().unload_stylesheet(this.#userStylesheet); + this.#userStylesheet = null; + } -/** - * Our own version of imports.ui.main.notify allowing more control over the - * notification - */ -function notify(msg, details, params) { - let source = new MessageTray.SystemNotificationSource(); - // note-to-self: the source is automatically destroyed when all its - // notifications are removed. - Main.messageTray.add(source); - let notification = new MessageTray.Notification(source, msg, details, params); - notification.setResident(true); // Usually more annoying that the notification disappear than not - source.showNotification(notification); - return notification; -} + /** + * Our own version of imports.ui.main.notify allowing more control over the + * notification + */ + notify(msg, details, params) { + let source = new MessageTray.SystemNotificationSource(); + // note-to-self: the source is automatically destroyed when all its + // notifications are removed. + Main.messageTray.add(source); + let notification = new MessageTray.Notification(source, msg, details, params); + notification.setResident(true); // Usually more annoying that the notification disappear than not + source.showNotification(notification); + return notification; + } -function spawnPager(content) { - const quoted = GLib.shell_quote(content); - Util.spawn(["sh", "-c", `echo -En ${quoted} | gedit --new-window -`]); -} + spawnPager(content) { + const quoted = GLib.shell_quote(content); + Util.spawn(["sh", "-c", `echo -En ${quoted} | gedit --new-window -`]); + } -/** - * Show an notification opening a the full message in dedicated window upon - * activation - */ -function errorNotification(title, message, fullMessage) { - const notification = notify(title, message); - notification.connect('activated', () => { - spawnPager([title, message, "", fullMessage].join("\n")); - notification.destroy(); - }); + /** + * Show an notification opening a the full message in dedicated window upon + * activation + */ + errorNotification(title, message, fullMessage) { + const notification = this.notify(title, message); + notification.connect('activated', () => { + this.spawnPager([title, message, "", fullMessage].join("\n")); + notification.destroy(); + }); + } } From 7a2e986d1115c4249748b39210ec5cd2abfad360 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 14:43:22 +1000 Subject: [PATCH 03/50] Ported `extensions.js` to ESM. Using centralised imports file (which exports all modules). --- acceleratorparse.js | 10 +- extension.js | 61 ++++----- imports.js | 13 ++ notes.org | 298 -------------------------------------------- 4 files changed, 50 insertions(+), 332 deletions(-) create mode 100644 imports.js delete mode 100644 notes.org diff --git a/acceleratorparse.js b/acceleratorparse.js index aeccdfd6..71001140 100644 --- a/acceleratorparse.js +++ b/acceleratorparse.js @@ -2,7 +2,7 @@ * Provides replacement for Gtk.accelerator_parse. * @param {String} keystr */ -function accelerator_parse(keystr) { +export function accelerator_parse(keystr) { let mask = accelerator_mask(keystr); const mods = accelerator_mods(keystr); @@ -33,7 +33,7 @@ function accelerator_parse(keystr) { * Returns array of mods for a keystr, e.g. ['', '', '']. * @param {String} keystr */ -function accelerator_mods(keystr) { +export function accelerator_mods(keystr) { return keystr.match(/<.*?>/g) ?? []; } @@ -51,7 +51,7 @@ const GDK_ALT_MASK = 1 << 3; const GDK_SUPER_MASK = 1 << 26; const GDK_HYPER_MASK = 1 << 27; const GDK_META_MASK = 1 << 28; -function accelerator_mask(keystr) { +export function accelerator_mask(keystr) { // need to extact all mods from keystr const mods = accelerator_mods(keystr); let result = 0; @@ -82,7 +82,7 @@ function accelerator_mask(keystr) { return result; } -function destroyKeycodeMap() { +export function destroyKeycodeMap() { keycodeMap = null; } @@ -91,7 +91,7 @@ function destroyKeycodeMap() { * https://gitlab.gnome.org/GNOME/gtk/-/blob/4.13.0/gdk/gdkkeysyms.h?ref_type=tags */ let keycodeMap; -function initKeycodeMap() { +export function initKeycodeMap() { const map = new Map(); map.set('VoidSymbol', 0xffffff); map.set('BackSpace', 0xff08); diff --git a/extension.js b/extension.js index d0c89f8f..d198f332 100644 --- a/extension.js +++ b/extension.js @@ -4,9 +4,13 @@ import St from 'gi://St'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import * as MessageTray from 'resource:///org/gnome/shell/ui/messageTray.js'; -import * as Navigator from './navigator.js'; import * as Util from 'resource:///org/gnome/shell/misc/util.js'; +import { + Utils, Settings, Gestures, Keybindings, LiveAltTab, Navigator, + Stackoverlay, Scratch, Workspace, Tiling, Topbar, Patches, App +} from './imports.js'; + import { Extension, dir } from 'resource:///org/gnome/shell/extensions/extension.js'; /** @@ -40,14 +44,15 @@ import { Extension, dir } from 'resource:///org/gnome/shell/extensions/extension - several modules import settings, so settings should be before them; - settings.js should not depend on other paperwm modules; */ -const modules = [ - 'utils', 'settings', - 'gestures', 'keybindings', 'liveAltTab', 'navigator', 'stackoverlay', 'scratch', - 'workspace', 'tiling', 'topbar', // these have `enable` dependency order - 'patches', 'app', // these have `enable` dependency order -]; export default class PaperWM extends Extension { + modules = [ + Utils, Settings, + Gestures, Keybindings, LiveAltTab, Navigator, Stackoverlay, Scratch, + Workspace, Tiling, Topbar, + Patches, App, + ]; + #firstEnable = true; #userStylesheet = null; @@ -56,10 +61,10 @@ export default class PaperWM extends Extension { */ run(method, reverse = false) { // reverse order an array (useful for controlling execution order) - let arr = reverse ? [...modules].reverse() : modules; - for (let name of arr) { + let arr = reverse ? [...this.modules].reverse() : this.modules; + for (let module of arr) { // Bail if there's an error in our own modules - if (!this.safeCall(name, method)) { + if (!this.safeCall(module, method)) { return false; } } @@ -83,20 +88,17 @@ export default class PaperWM extends Extension { return true; } - safeCall(name, method) { + safeCall(module, method) { try { - let module = Extension.imports[name]; if (module && module[method]) { - console.debug("#paperwm", `${method} ${name}`); + module[method](); } - module && module[method] && module[method].call(module, errorNotification); return true; } catch (e) { - console.error("#paperwm", `${name} failed ${method}`); - console.error(`JS ERROR: ${e}\n${e.stack}`); + console.error(new Error(`#paperwm failed ${method}`)); this.errorNotification( "PaperWM", - `Error occured in ${name} @${method}:\n\n${e.message}`, + `Error occured in @${method}:\n\n${e.message}`, e.stack); return false; } @@ -114,18 +116,6 @@ export default class PaperWM extends Extension { } } - /** - * Prepares PaperWM for disable across modules. - */ - prepareForDisable() { - /** - * Finish any navigation (e.g. workspace switch view). - * Can put PaperWM in a breakable state of lock/disable - * while navigating. - */ - Navigator.finishNavigation(); - } - disable() { console.log('#PaperWM disabled'); this.prepareForDisable(); @@ -135,6 +125,19 @@ export default class PaperWM extends Extension { this.safeCall('user', 'disable'); } + + /** + * Prepares PaperWM for disable across modules. + */ + prepareForDisable() { + /** + * Finish any navigation (e.g. workspace switch view). + * Can put PaperWM in a breakable state of lock/disable + * while navigating. + */ + Navigator.finishNavigation(); + } + getConfigDir() { return Gio.file_new_for_path(`${GLib.get_user_config_dir()}/paperwm`); } diff --git a/imports.js b/imports.js new file mode 100644 index 00000000..6f76e4a7 --- /dev/null +++ b/imports.js @@ -0,0 +1,13 @@ +export * as Utils from './utils.js'; +export * as Settings from './settings.js'; +export * as Gestures from './gestures.js'; +export * as Keybindings from './keybindings.js'; +export * as LiveAltTab from './liveAltTab.js'; +export * as Navigator from './navigator.js'; +export * as Stackoverlay from './stackoverlay.js'; +export * as Scratch from './scratch.js'; +export * as Workspace from './workspace.js'; +export * as Tiling from './tiling.js'; +export * as Topbar from './topbar.js'; +export * as Patches from './patches.js'; +export * as App from './app.js'; diff --git a/notes.org b/notes.org deleted file mode 100644 index 2d55e5bf..00000000 --- a/notes.org +++ /dev/null @@ -1,298 +0,0 @@ -* Mutter state change signal summary (WIP) -stuck -> unstuck: - stuck property change - remove from all workspaces - add on target workspace - -unstuck -> stuck: - stuck property change [not-verified] - remove from current workspace - add on all workspaces - -window moved from workspace A -> workspace B: - remove from A - add on B - -window A close: - next window receive focus - remove A from workspace - window-left-monitor (actor is null) - -window is created: - window-added (actor is null) - window-entered-monitor (actor is null) - window-created - window-focus - -window monitor changed: (ws-only-primary) - [order not-verified] - window-left-monitor [not-verified] - window-entered-monitor - unstuck -> stuck - -window monitor changed: (ws-spans-monitor) - window-left-monitor [not-verified] - window-entered-monitor - -Monitor changes (ws-only-primary) - primary -> secondary <=> unstuck -> stuck - seconday -> primary <=> stuck -> unstuck - -window_added always follows a window_removed except when a window is closed. - -window monitor membership determined by majority area (ish) - -* Mutter signal order -** When window A is closed -1. The next window, B, receives 'focus' (but the actor of A seems to be gone?) -2. Workspace receives 'window-removed'. ('A' seems to have been stripped of signal handlers) -3. on screen 'window-left-monitor', actor isn't available -** When window A is created -1. on workspace "window-added" is run, actor isn't available -2. on screen "window-entered-monitor", actor isn't available -3. on display "window-created" is run, actor is available -4. focus is run if the new window should be focused -** Toggle "Always on visible workspace" (scratch windows) -- window-removed on workspace of window -- window-added on all workspaces -* Keybinding system -`Main.wm.addKeybinding` is used to register a named keybindable /action/ and it's handler. An numeric id is returned. (this is a thin wrapper around `[[https://developer.gnome.org/meta/stable/MetaDisplay.html#meta-display-add-keybinding][MetaDisplay.add_keybinding]]`) - -The action should have an entry in the schema underlying the `GSettings` object supplied to `addKeybinding`. This is where the actual keybinding is specified. Multiple bindings can be specified. - -#+BEGIN_SRC xml - - e']]]> - Toggles the floating scratch layer - -#+END_SRC - -To change a keybinding simply change this value in the gsetting: (mutter will pick up the change automatically. - -#+BEGIN_SRC javascript -mySettings.set_strv("toggle-scratch-layer", ["s"]); -#+END_SRC - -Action names are global. (note that the mutter documentation mostly refers to actions as keybindings) - -`Meta.keybindings_set_custom_handler` is used to change a action handler. Despite what the documentation suggests this works for non-builtin actions too. - -If the action is a mutter built-in (one of `Meta.KeyBindingAction.*`, setting the custom handler to `null` restores the default handler. - -Action handlers fire on key-down. - -Mutter itself does not support key-release sensitive bindings, but it's possible to create a Clutter actor in response to a key-down binding, which temporarily take over the keyboard. Clutter can listen for key-up/key-release events. - -`[[https://developer.gnome.org/meta/stable/MetaDisplay.html#meta-display-get-keybinding-action][MetaDisplay.get_keybinding_action]]` looks up the action id bound to a specific modifer+keycode. This is mostly useful when handling key events within clutter. - -The id -> action-name mapping is not(?) exposed. For builtin actions `Meta.prefs_get_keybinding_action(actionName)` will give the id of actionName. - -It's not possible to look up the handler of a action...(?) - -A slightly annoying detail about how all this works is that you normally give the handler before you know the action-id. So if the handler need to know the action-id (eg. if it use clutter to implement a mini-mode and want to respond to the same key that triggered the mode) you either have to store a name->id map, or re-assign the handler afterward. - -The Keybinding object which is supplied to keyhandler doesn't seem to expose the key used to trigger the action either? - -** Modifier-only bindings -Simply use the keysym name as if the modifier was a regular key. Don't use angle brackets - those are used for **modifiers**. -: settings.set_strv("my-action", ["Super_L"]) -** Bind keys without using actions from a schema -From: https://stackoverflow.com/a/42466781/1517969 - -#+BEGIN_SRC javascript -Meta = imports.gi.Meta; -Main = imports.ui.main; -Shell = imports.gi.Shell; - -let action = global.display.grab_accelerator("u"); -let name = Meta.external_binding_name_for_action(action); -Main.wm.allowKeybinding(name, Shell.ActionMode.ALL); -global.display.connect( - 'accelerator-activated', - function(display, action, deviceId, timestamp){ - print('Accelerator Activated: [display={}, action={}, deviceId={}, timestamp={}]', - display, action, deviceId, timestamp) - }) -#+END_SRC -** Lookup an keybinding action by a accelerator string -~global.display.get_keybinding_action(keycode, mask)~ is simple to use in clutter event handlers since the keycode and mask is readily available. Outside of clutter is harder: - -#+BEGIN_SRC javascript -function devirtualizeMask(gdkVirtualMask) { - const keymap = Gdk.Keymap.get_default(); - let [success, rawMask] = keymap.map_virtual_modifiers(gdkVirtualMask); - if (!success) - throw new Error("Couldn't devirtualize mask " + gdkVirtualMask); - return rawMask; -} - -function getBoundActionId(keystr) { - let [dontcare, keycodes, mask] = - Gtk.accelerator_parse_with_keycode(keystr); - if(keycodes.length > 1) { - throw new Error("Multiple keycodes " + keycodes + " " + keystr); - } - const rawMask = devirtualizeMask(mask); - return global.display.get_keybinding_action(keycodes[0], rawMask); -} -#+END_SRC -* GJS -** import system / module system -`imports.NAME` reflects the directories and javascript files present in `imports.searchPath`. -To add a path, simply do `imports.searchPath.push(PATH)` - -Environment variable `GJS_PATH` initializes `imports.searchPath`. - -The special property `imports.gi` expose gobject-introspectable libraries. -Another search path controls which libraries are available: -`imports.gi.GIRepository.Repository.get_search_path()` initialized by environment variable `GI_TYPELIB_PATH` (`Repository` is the global instance of [[https://developer.gnome.org/gi/stable/GIRepository.html][GIRepository]]) - -*** Reloading modules -Modules **can't** be reloaded, but writing to `imports.myModule.myVariable` works. Eg. -#+BEGIN_SRC javascript -// myModule -var foo = 1; -function printFoo() { - print(foo); -} -#+END_SRC - -After `imports.myModule.foo = 2`, `printFoo` will print 2. All users of the module share the same module object so they will also see the updated variable. - -*** Refering to the current module -Refering to the module being loaded works: -#+BEGIN_SRC javascript -// myModule.js -var currentModule = imports.myModule; -var foo = 1; -currentModule.foo = 2; -print(foo); // prints 2 -#+END_SRC -I don't know if it's possible without knowing the module name. -*** Creating a standalone importer -This trick is due to gnome-shell -#+BEGIN_SRC javascript -function createImporter (directoryPath) { - const Gio = imports.gi.Gio; - let oldSearchPath = imports.searchPath.slice(); // make a copy - let directory = Gio.file_new_for_path(directoryPath); - try { - imports.searchPath = [ directory.get_parent().get_path() ]; - // importing a "subdir" creates a new importer object that doesn't - // affect the global one - return imports[directory.get_basename()]; - } finally { - imports.searchPath = oldSearchPath; - } -} -#+END_SRC -** Debugging -*** Get a stacktrace -`(new Error()).stack` -* GObject -The `notify` signal is emited on changes to all GObject properties. Listen to `notify::propery-name` to only receive for changes to ` property-name`. ([[https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#GObject-notify][Reference]]) -* Gnome-shell scene graph and GUI system -NB: some details might differ with the wayland backend. - -Gnome shell use [[https://developer.gnome.org/clutter/stable/][Clutter]] to mange all visible components including the window textures. Basic GUI components are provided by the [[https://developer.gnome.org/st/stable/][St]] (built on top of clutter). - -Low level window management and input handling happens through [[https://developer.gnome.org/meta/stable/][mutter/meta]]. Gnome-shell is technically a mutter plugin. - -** Input handling - -(Also see [[Keybinding system]]) - -Input is normally fully handled by X11. This means that even though gnome-shell use clutter (which have input mechanisms) inputs does not normally go through clutter. - -Ie. making an actor `reactive` is not enough to capture input reliable. - -Input handling can be directed through clutter by using: - -: Main.layoutManager._trackActor(actor) - -This informs mutter[1] that mouse input in the actor's region should be sent through clutter. - -Some higher-level interfaces: - -: Main.pushModal(actor) - -The clutter actor will receives all input until `Main.popModal` is called. - -: Main.layoutManager.trackChrome(actor) - -NB: It does not seem to be possible to propagate input captured by a tracked actor to a window actor below. - -NB! When a "tracked" actor is stacked below a _window actor_ it will still prevent the window actor from receiving input! - -[1] By using `meta_set_stage_input_region` through `global.set_stage_input_region` - -** `MetaWindow` and `MetaWindowActor` -WIP: display_rect vs frame_rect vs actor.width. Gotchas when placing MetaWindowActors in containers, etc. - -Warning: This is a somewhat confusing part of gnome-shell/mutter. - -A window is represented by two objects: a `MetaWindow` representing the underlying windowing system object (eg. a X11 window) and a `MetaWindowActor` which basically is the window texture/visible part. - -Both of these objects have a /geometry/ (size and position). The meta window geometry determines the input region, while the actor geometry determines the texture. Normally these geometries are kept in sync so the visible and input regions corresponds. It is however possible for these to drift: The thumb of rule is that changes to the meta window geometry is propagated to the actor, but not the other way. - -The coordinate system used is thankfully shared :) - -The size of the window actor is slightly bigger than the meta window since the actor includes border decorations and window-resize region. The size difference varies with the toolkit used to create the window. - -*** Basic operations -To get the window actor of a meta window: `metaWindow.get_compositor_private()` - -To get the meta window of a window actor: `windowActor.meta_window` - -The window actor geometry: `windowActor.size, windowActor.position` or `metaWindow.get_buffer_rect` - -The meta window geometry: `[[https://developer.gnome.org/meta/stable/MetaWindow.html#meta-window-get-frame-rect][metaWindow.get_frame_rect()]]` - -Changing the geometry of a window: `[[https://developer.gnome.org/meta/stable/MetaWindow.html#meta-window-move-frame][metaWindow.move_frame]]` or `[[https://developer.gnome.org/meta/stable/MetaWindow.html#meta-window-move-resize-frame][metaWindow.move_resize_frame]]` - -** Stacking/"z-index" -The "z-index" in clutter is controlled by the actors position in the scene graph. Ie. the actors are drawn in a depth first manner. So the last child of a parent will be drawn on top of all the other children, and so on. - -To my knowledge there is no way to make a actor "break out" of its parent. If sibling A is drawn below another actor X, sibling B will also be drawn below X. - -NB: `ClutterActor.z-position` **don't** control the z-index. It is used to control the perspective of the actors (most relevant for rotated actors). - -A complication when using non-window actors inside `global.window_group` is that mutter keep restacking the window actors in a way that destroys the non-window actors z-index. Listening on the `restacked` signal of `global.screen` (`MetaScreen`) and restack the non-window actors in the handler is a workaround that seems to work. - -** Gotchas -Building `StWidget` detached from the stage are prone to result in the following warning: - -: st_widget_get_theme_node called on the widget [0x... St...] which is not in the stage. - -This is because a lot of actor properties depend on the style of the actor and that can depend on the ancestors of the actor. (`.parent .child { border: 2px; }`) - -So any code that try to access eg. height/width (unless these have been explicitly set beforehand) requires that the full style info is present. -* Extension system -All extension objects are available using -`imports.misc.extensionUtils.extensions[extensionUiid];` -where the key is the uuid from the metadata.json file. - -The /current/ extension object is usually found like this: -#+BEGIN_SRC javascript -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -#+END_SRC - -The absolute path of the an extension: `Extension.path` -* Misc HowTo -** Defer an execution of a function -[[https://developer.gnome.org/meta/stable/meta-Utility-functions.html#meta-later-add][~Meta.later_add~]] (assoc: ~imports.mainloop.timeout_add~) -** Increase mutter log verbosity -~Meta.add_verbose_topic(Meta.DebugTopic.FOCUS)~ -~Meta.remove_verbose_topic(Meta.DebugTopic.FOCUS)~ -** Profiling -*** Show clutter FPS -Clutter prints the FPS at regular intervals if ~CLUTTER_SHOW_FPS~ is set when gnome-shell starts. Where the output ends up depends on how gnome-shell was started. On my system it ends up in the system journal (journalctl) - -To turn on off without disrupting flow too much use ~GLib.setenv("CLUTTER_SHOW_FPS", "1", true)~ and restart gnome-shell. -* Invariants -** Focus and active workspace -It's not possible the have a focused window which doesn't belong to the active workspace -~global.display.focus_window.workspace === workspaceManger.get_active_workspace()~ -* Clutter animation - ~time: 0~ does not result in an instant animation. A default duration seems to be selected instead. From 4d5eb16a28fa52454c0ac1f184fbf242d8c7a7f9 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 14:52:07 +1000 Subject: [PATCH 04/50] Ported app.js. --- app.js | 27 +++++++++++++-------------- imports.js | 1 + 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app.js b/app.js index a7286f33..b3b009d9 100644 --- a/app.js +++ b/app.js @@ -1,10 +1,9 @@ -import * as ExtensionModule from './extension.js'; -import * as Patches from './patches.js'; -import * as Tiling from './tiling.js'; import GLib from 'gi://GLib'; import Gio from 'gi://Gio'; import Shell from 'gi://Shell'; +import { ExtensionModule, Patches, Tiling } from './imports.js'; + /* Application functionality, like global new window actions etc. */ @@ -13,8 +12,8 @@ let Tracker = Shell.WindowTracker.get_default(); let CouldNotLaunch = Symbol(); // Lookup table for custom handlers, keys being the app id -var customHandlers, customSpawnHandlers; -function enable() { +export let customHandlers, customSpawnHandlers; +export function enable() { customHandlers = { 'org.gnome.Terminal.desktop': newGnomeTerminal }; customSpawnHandlers = { 'com.gexperts.Tilix.desktop': mkCommandLineSpawner('tilix --working-directory %d'), @@ -67,12 +66,12 @@ function enable() { ); } -function disable() { +export function disable() { customHandlers = null; customSpawnHandlers = null; } -function launchFromWorkspaceDir(app, workspace = null) { +export function launchFromWorkspaceDir(app, workspace = null) { if (typeof app === 'string') { app = new Shell.App({ app_info: Gio.DesktopAppInfo.new(app) }); } @@ -97,7 +96,7 @@ function launchFromWorkspaceDir(app, workspace = null) { GLib.spawn_async(dir, cmdArgs, GLib.get_environ(), GLib.SpawnFlags.SEARCH_PATH, null); } -function newGnomeTerminal(metaWindow, app) { +export function newGnomeTerminal(metaWindow, app) { /* Note: this action activation is _not_ bound to the window - instead it relies on the window being active when called. @@ -107,7 +106,7 @@ function newGnomeTerminal(metaWindow, app) { "win.new-terminal", new GLib.Variant("(ss)", ["window", "current"])); } -function duplicateWindow(metaWindow) { +export function duplicateWindow(metaWindow) { metaWindow = metaWindow || global.display.focus_window; let app = Tracker.get_window_app(metaWindow); @@ -124,7 +123,7 @@ function duplicateWindow(metaWindow) { return true; } -function trySpawnWindow(app, workspace) { +export function trySpawnWindow(app, workspace) { if (typeof app === 'string') { app = new Shell.App({ app_info: Gio.DesktopAppInfo.new(app) }); } @@ -137,7 +136,7 @@ function trySpawnWindow(app, workspace) { } } -function spawnWindow(app, workspace) { +export function spawnWindow(app, workspace) { if (typeof app === 'string') { app = new Shell.App({ app_info: Gio.DesktopAppInfo.new(app) }); } @@ -149,7 +148,7 @@ function spawnWindow(app, workspace) { } } -function getWorkspaceDirectory(workspace = null) { +export function getWorkspaceDirectory(workspace = null) { let space = workspace ? Tiling.spaces.get(workspace) : Tiling.spaces.selectedSpace; let dir = space.settings.get_string("directory"); @@ -159,7 +158,7 @@ function getWorkspaceDirectory(workspace = null) { return dir; } -function expandCommandline(commandline, workspace) { +export function expandCommandline(commandline, workspace) { let dir = getWorkspaceDirectory(workspace); commandline = commandline.replace(/%d/g, () => GLib.shell_quote(dir)); @@ -167,7 +166,7 @@ function expandCommandline(commandline, workspace) { return commandline; } -function mkCommandLineSpawner(commandlineTemplate, spawnInWorkspaceDir = false) { +export function mkCommandLineSpawner(commandlineTemplate, spawnInWorkspaceDir = false) { return (app, space) => { let workspace = space.workspace; let commandline = expandCommandline(commandlineTemplate, workspace); diff --git a/imports.js b/imports.js index 6f76e4a7..6c4d8d9b 100644 --- a/imports.js +++ b/imports.js @@ -1,3 +1,4 @@ +export * as ExtensionModule from './extension.js'; export * as Utils from './utils.js'; export * as Settings from './settings.js'; export * as Gestures from './gestures.js'; From 8bfd5c7fa1adf271210f77c7fd19152111c94c3f Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 16:33:16 +1000 Subject: [PATCH 05/50] Ported gestures.js. Allow shadowing in eslint. --- .eslintrc.yml | 1 - extension.js | 81 +++++++++------------------------------------------ gestures.js | 73 ++++++++++++++++++++-------------------------- tiling.js | 17 ++++------- 4 files changed, 52 insertions(+), 120 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index 2daf31d2..dd9dc87f 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -168,7 +168,6 @@ rules: no-return-assign: error no-return-await: error no-self-compare: error - no-shadow: error no-shadow-restricted-names: error no-spaced-func: error no-tabs: error diff --git a/extension.js b/extension.js index d198f332..efcf735f 100644 --- a/extension.js +++ b/extension.js @@ -53,79 +53,27 @@ export default class PaperWM extends Extension { Patches, App, ]; - #firstEnable = true; #userStylesheet = null; - /** - Tell the modules to run enable or disable. - */ - run(method, reverse = false) { - // reverse order an array (useful for controlling execution order) - let arr = reverse ? [...this.modules].reverse() : this.modules; - for (let module of arr) { - // Bail if there's an error in our own modules - if (!this.safeCall(module, method)) { - return false; - } - } - - /* - // run 'user.js' methods (if it exists) - if (this.hasUserConfigFile()) { - // if enable method, call 'init' for backwards compat and then enable - if (method === 'enable') { - if (this.#firstEnable) { - this.safeCall('user', 'init'); - } - this.safeCall('user', 'enable'); - } - else { - this.safeCall('user', method); - } - } - */ - - return true; - } - - safeCall(module, method) { - try { - if (module && module[method]) { - module[method](); - } - return true; - } catch (e) { - console.error(new Error(`#paperwm failed ${method}`)); - this.errorNotification( - "PaperWM", - `Error occured in @${method}:\n\n${e.message}`, - e.stack); - return false; - } - } - enable() { console.log(`#PaperWM enabled`); - // 45 SearchPath doesn't exist in 45... - // this.enableUserConfig(); + this.enableUserConfig(); this.enableUserStylesheet(); - if (this.run('enable')) { - this.#firstEnable = false; - } + // run enable method (with extension argument on all modules) + this.modules.forEach(m => m.enable(this)); } disable() { console.log('#PaperWM disabled'); this.prepareForDisable(); this.run('disable', true); + [...this.modules].reverse().forEach(m => m.disable()); this.disableUserStylesheet(); - this.safeCall('user', 'disable'); } - /** * Prepares PaperWM for disable across modules. */ @@ -171,12 +119,6 @@ export default class PaperWM extends Extension { } } - /* TODO: figure out something here - fmuellner: - > you can't - > as I said, it's part of gjs legacy imports - > you'll have to do something like const userMod = await import(${this.getConfigDir()}/user.js) - installConfig() { const configDir = this.getConfigDir(); // if user config folder doesn't exist, create it @@ -188,28 +130,33 @@ export default class PaperWM extends Extension { const user = dir.get_child("config/user.js"); user.copy(configDir.get_child("user.js"), Gio.FileCopyFlags.NONE, null, null); } - */ - /* enableUserConfig() { if (!this.configDirExists()) { try { this.installConfig(); const configDir = this.getConfigDir().get_path(); - const notification = this.notify("PaperWM", `Installed user configuration in ${configDir}`); + const notification = this.notify("PaperWM", `Created user configuration folder: ${configDir}`); notification.connect('activated', () => { Util.spawn(["nautilus", configDir]); notification.destroy(); }); } catch (e) { - this.errorNotification("PaperWM", `Failed to install user config: ${e.message}`, e.stack); + this.errorNotification("PaperWM", `Failed create user configuration folder: ${e.message}`, e.stack); console.error("PaperWM", "User config install failed", e.message); } } this.updateUserConfigMetadata(); + /* TODO: figure out something here + fmuellner: + > you can't + > as I said, it's part of gjs legacy imports + > you'll have to do something like const userMod = await import(${this.getConfigDir()}/user.js) + */ + /* // add to searchpath if user has config file and action user.js if (this.hasUserConfigFile()) { let SearchPath = Extension.imports.searchPath; @@ -218,8 +165,8 @@ export default class PaperWM extends Extension { SearchPath.push(path); } } + */ } - */ /** * Reloads user.css styles (if user.css present in ~/.config/paperwm). diff --git a/gestures.js b/gestures.js index 0e16c83d..3bc66803 100644 --- a/gestures.js +++ b/gestures.js @@ -1,34 +1,25 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Patches = Extension.imports.patches; -const Settings = Extension.imports.settings; -const Tiling = Extension.imports.tiling; -const Utils = Extension.imports.utils; -const Lib = Extension.imports.lib; -const Easer = Extension.imports.utils.easer; -const Navigator = Extension.imports.navigator; - -const { Meta, Gio, Shell, Clutter } = imports.gi; -const Main = imports.ui.main; -const Mainloop = imports.mainloop; +import Clutter from 'gi://Clutter'; +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; +import Meta from 'gi://Meta'; +import Shell from 'gi://Shell'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; + +import { Patches, Settings, Tiling, Utils, Lib, Easer, Navigator } from './imports.js'; const DIRECTIONS = { Horizontal: true, Vertical: false, }; -let vy; -let time; -let vState; -let navigator; -let direction; -let signals; +let vy, time, vState, navigator, direction, signals; // 1 is natural scrolling, -1 is unnatural let natural = 1; -var gliding = false; // exported +export let gliding = false; // exported let touchpadSettings; -function enable() { +export function enable(extension) { signals = new Utils.Signals(); // Touchpad swipes only works in Wayland if (!Meta.is_wayland_compositor()) @@ -39,7 +30,7 @@ function enable() { }); // monitor gesture-enabled for changes - const gsettings = ExtensionUtils.getSettings(); + const gsettings = extension.getSettings(); signals.connect(gsettings, 'changed::gesture-enabled', () => { gestureEnabled() ? swipeTrackersEnable(false) : swipeTrackersEnable(); }); @@ -159,7 +150,7 @@ function enable() { }); } -function disable() { +export function disable() { signals.destroy(); signals = null; Utils.timeout_remove(endVerticalTimeout); @@ -167,15 +158,15 @@ function disable() { touchpadSettings = null; } -function gestureEnabled() { +export function gestureEnabled() { return Settings.prefs.gesture_enabled; } -function gestureHorizontalFingers() { +export function gestureHorizontalFingers() { return Settings.prefs.gesture_horizontal_fingers; } -function gestureWorkspaceFingers() { +export function gestureWorkspaceFingers() { return Settings.prefs.gesture_workspace_fingers; } @@ -184,7 +175,7 @@ function gestureWorkspaceFingers() { connected from each space.background and bound to the space. */ let start, dxs = [], dts = []; -function horizontalScroll(actor, event) { +export function horizontalScroll(space, actor, event) { if (event.type() !== Clutter.EventType.TOUCHPAD_SWIPE) { return Clutter.EVENT_PROPAGATE; } @@ -210,26 +201,26 @@ function horizontalScroll(actor, event) { switch (phase) { case Clutter.TouchpadGesturePhase.UPDATE: if (direction === undefined) { - this.vx = 0; + space.vx = 0; dxs = []; dts = []; - this.hState = phase; - start = this.targetX; - Easer.removeEase(this.cloneContainer); + space.hState = phase; + start = space.targetX; + Easer.removeEase(space.cloneContainer); direction = DIRECTIONS.Horizontal; } - return update(this, -dx * natural * Settings.prefs.swipe_sensitivity[0], event.get_time()); + return update(space, -dx * natural * Settings.prefs.swipe_sensitivity[0], event.get_time()); case Clutter.TouchpadGesturePhase.CANCEL: case Clutter.TouchpadGesturePhase.END: - this.hState = phase; - done(this, event); + space.hState = phase; + done(space, event); dxs = []; dts = []; return Clutter.EVENT_STOP; } } -function update(space, dx, t) { +export function update(space, dx, t) { dxs.push(dx); dts.push(t); @@ -260,7 +251,7 @@ function update(space, dx, t) { return Clutter.EVENT_STOP; } -function done(space) { +export function done(space) { if (!Number.isFinite(space.vx) || space.length === 0) { navigator.finish(); space.hState = -1; @@ -336,7 +327,7 @@ function done(space) { } -function findTargetWindow(space, direction) { +export function findTargetWindow(space, direction) { let selected = space.selectedWindow?.clone; if (!selected) { return; @@ -399,7 +390,7 @@ function findTargetWindow(space, direction) { } let transition = 'easeOutQuad'; -function updateVertical(dy, t) { +export function updateVertical(dy, t) { // if here then initiate workspace stack (for tiling inPreview show) if (!Tiling.inPreview) { Tiling.spaces.initWorkspaceStack(); @@ -451,7 +442,7 @@ function updateVertical(dy, t) { } let endVerticalTimeout; -function endVertical() { +export function endVertical() { let test = vy > 0 ? () => vy < 0 : () => vy > 0; let glide = () => { if (vState < Clutter.TouchpadGesturePhase.END) { @@ -491,7 +482,7 @@ function endVertical() { * function - which returns false (thus destroying this timeout) * when user gesture fininshes, a space is selected, etc. */ - endVerticalTimeout = Mainloop.timeout_add(16, glide, 0); + endVerticalTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 16, glide); } /** @@ -499,7 +490,7 @@ function endVertical() { * default 3 finger swipe actions. * @param {Boolean} option */ -function swipeTrackersEnable(option) { +export function swipeTrackersEnable(option) { let enable = option ?? true; Patches.swipeTrackers.forEach(t => t.enabled = enable); } diff --git a/tiling.js b/tiling.js index 7f3509cf..fefa6ea6 100644 --- a/tiling.js +++ b/tiling.js @@ -39,7 +39,7 @@ var inPreview = PreviewMode.NONE; // export // DEFAULT mode is normal/original PaperWM window focus behaviour var FocusModes = { DEFAULT: 0, CENTER: 1 }; // export -var CycleWindowSizesDirection = { FORWARD: 0, BACKWARDS: 1}; +var CycleWindowSizesDirection = { FORWARD: 0, BACKWARDS: 1 }; /** Scrolled and tiled per monitor workspace. @@ -1461,9 +1461,9 @@ border-radius: ${borderWidth}px; } }); - this.signals.connect( - this.background, 'captured-event', - Gestures.horizontalScroll.bind(this)); + this.signals.connect(this.background, 'captured-event', (actor, event) => { + Gestures.horizontalScroll(this, actor, event); + }); } setMonitor(monitor, animate = false) { @@ -2825,7 +2825,7 @@ let displayConfig; let saveState; let startupTimeoutId, timerId; var inGrab; // exported -function enable(errorNotification) { +function enable(extension) { inGrab = false; displayConfig = new Utils.DisplayConfig(); @@ -2872,12 +2872,7 @@ function enable(errorNotification) { try { spaces.init(); } catch (e) { - console.error('#paperwm startup failed'); - console.error(`JS ERROR: ${e}\n${e.stack}`); - errorNotification( - "PaperWM", - `Error occured in paperwm startup:\n\n${e.message}`, - e.stack); + console.error(new Error('#paperwm startup failed')); } // Fix the stack overlay From 6390718d7d5c29aaba828f8fabd5078e7a54a954 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 17:16:40 +1000 Subject: [PATCH 06/50] Ported grab.js. --- grab.js | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/grab.js b/grab.js index 25d0510f..df67eae0 100644 --- a/grab.js +++ b/grab.js @@ -1,15 +1,12 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Settings = Extension.imports.settings; -const Utils = Extension.imports.utils; -const Tiling = Extension.imports.tiling; -const Navigator = Extension.imports.navigator; -const Scratch = Extension.imports.scratch; -const Easer = Extension.imports.utils.easer; - -const { Meta, Clutter, St, Graphene } = imports.gi; -const Main = imports.ui.main; -const Mainloop = imports.mainloop; +import Clutter from 'gi://Clutter'; +import GLib from 'gi://GLib'; +import Graphene from 'gi://Graphene'; +import Meta from 'gi://Meta'; +import St from 'gi://St'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; + +import { Settings, Utils, Tiling, Navigator, Scratch, Easer } from './imports.js'; /** * Returns a virtual pointer (i.e. mouse) device that can be used to @@ -18,7 +15,7 @@ const Mainloop = imports.mainloop; * @returns Clutter.VirtualInputDevice */ let virtualPointer; -function getVirtualPointer() { +export function getVirtualPointer() { if (!virtualPointer) { virtualPointer = Clutter.get_default_backend() .get_default_seat() @@ -28,7 +25,7 @@ function getVirtualPointer() { return virtualPointer; } -var MoveGrab = class MoveGrab { +export class MoveGrab { constructor(metaWindow, type, space) { this.window = metaWindow; this.type = type; @@ -111,7 +108,7 @@ var MoveGrab = class MoveGrab { this.dnd = true; Utils.debug("#grab", "begin DnD"); Navigator.getNavigator().minimaps.forEach(m => typeof m === 'number' - ? Mainloop.source_remove(m) : m.hide()); + ? GLib.source_remove(m) : m.hide()); global.display.set_cursor(Meta.Cursor.MOVE_OR_RESIZE_WINDOW); let metaWindow = this.window; let clone = metaWindow.clone; @@ -422,7 +419,9 @@ var MoveGrab = class MoveGrab { clone.set_scale(1, 1); clone.set_pivot_point(0, 0); - params.onStopped = () => { actor.set_pivot_point(0, 0); }; + params.onStopped = () => { + actor.set_pivot_point(0, 0); + }; Easer.addEase(actor, params); } @@ -538,15 +537,17 @@ var MoveGrab = class MoveGrab { time: Settings.prefs.animation_time, [zone.originProp]: zone.center, [zone.sizeProp]: 0, - onComplete: () => { zone.actor.destroy(); this.zoneActors.delete(zone.actor); }, + onComplete: () => { zone.actor.destroy(); + this.zoneActors.delete(zone.actor); + }, }); } this.dndTarget = null; } -}; +} -var ResizeGrab = class ResizeGrab { +export class ResizeGrab { constructor(metaWindow, type) { this.window = metaWindow; this.signals = new Utils.Signals(); @@ -574,4 +575,4 @@ var ResizeGrab = class ResizeGrab { this.window = null; this.space.layout(); } -}; +} From 4b4ce37c67e02016b1c4739823773eb8bdd08a94 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 17:33:40 +1000 Subject: [PATCH 07/50] Ported settings.js. --- imports.js | 2 +- settings.js | 72 +++++++++++++++++++++++++++-------------------------- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/imports.js b/imports.js index 6c4d8d9b..b7366c57 100644 --- a/imports.js +++ b/imports.js @@ -1,4 +1,4 @@ -export * as ExtensionModule from './extension.js'; +export * as AcceleratorParse from './acceleratorparse.js'; export * as Utils from './utils.js'; export * as Settings from './settings.js'; export * as Gestures from './gestures.js'; diff --git a/settings.js b/settings.js index 3d4d58da..9dee5cde 100644 --- a/settings.js +++ b/settings.js @@ -1,7 +1,7 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const AcceleratorParse = Extension.imports.acceleratorparse; -const { Gio, GLib } = imports.gi; +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; + +import AcceleratorParse from './imports.js'; /** Settings utility shared between the running extension and the preference UI. @@ -9,20 +9,20 @@ const { Gio, GLib } = imports.gi; at the top). */ -let KEYBINDINGS_KEY = 'org.gnome.shell.extensions.paperwm.keybindings'; -let RESTORE_KEYBINDS_KEY = 'restore-keybinds'; +const KEYBINDINGS_KEY = 'org.gnome.shell.extensions.paperwm.keybindings'; +const RESTORE_KEYBINDS_KEY = 'restore-keybinds'; // This is the value mutter uses for the keyvalue of above_tab -let META_KEY_ABOVE_TAB = 0x2f7259c9; +const META_KEY_ABOVE_TAB = 0x2f7259c9; -function setState($, key) { +export function setState($, key) { let value = gsettings.get_value(key); let name = key.replace(/-/g, '_'); prefs[name] = value.deep_unpack(); } -var conflictSettings; // exported -function getConflictSettings() { +export let conflictSettings; // exported +export function getConflictSettings() { if (!conflictSettings) { // Schemas that may contain conflicting keybindings // It's possible to inject or remove settings here on `user.init`. @@ -37,11 +37,13 @@ function getConflictSettings() { return conflictSettings; } -var prefs; -let gsettings, _overriddingConflicts; -function enable() { +export let prefs; +let gsettings, keybindSettings, _overriddingConflicts; +export function enable(extension) { + gsettings = extension.getSettings(); + keybindSettings = extension.getSettings(KEYBINDINGS_KEY); + AcceleratorParse.initKeycodeMap(); - gsettings = ExtensionUtils.getSettings(); _overriddingConflicts = false; prefs = {}; ['window-gap', 'vertical-margin', 'vertical-margin-bottom', 'horizontal-margin', @@ -52,7 +54,7 @@ function enable() { 'disable-topbar-styling', 'default-focus-mode', 'gesture-enabled', 'gesture-horizontal-fingers', 'gesture-workspace-fingers'] .forEach(k => setState(null, k)); - prefs.__defineGetter__("minimum_margin", function () { + prefs.__defineGetter__("minimum_margin", () => { return Math.min(15, this.horizontal_margin); }); gsettings.connect('changed', setState); @@ -76,7 +78,7 @@ function enable() { addWinpropsFromGSettings(); } -function disable() { +export function disable() { AcceleratorParse.destroyKeycodeMap(); gsettings = null; _overriddingConflicts = null; @@ -86,14 +88,14 @@ function disable() { // / Keybindings -function accelerator_parse(keystr) { +export function accelerator_parse(keystr) { return AcceleratorParse.accelerator_parse(keystr); } /** * Two keystrings can represent the same key combination */ -function keystrToKeycombo(keystr) { +export function keystrToKeycombo(keystr) { // Above_Tab is a fake keysymbol provided by mutter let aboveTab = false; if (keystr.match(/Above_Tab/) || keystr.match(/grave/)) { @@ -108,7 +110,7 @@ function keystrToKeycombo(keystr) { return `${key}|${mask}`; // Since js doesn't have a mapable tuple type } -function generateKeycomboMap(settings) { +export function generateKeycomboMap(settings) { let map = {}; for (let name of settings.list_keys()) { let value = settings.get_value(name); @@ -128,10 +130,10 @@ function generateKeycomboMap(settings) { return map; } -function findConflicts(schemas) { +export function findConflicts(schemas) { schemas = schemas || getConflictSettings(); let conflicts = []; - const paperMap = generateKeycomboMap(ExtensionUtils.getSettings(KEYBINDINGS_KEY)); + const paperMap = generateKeycomboMap(keybindSettings); for (let settings of schemas) { const against = generateKeycomboMap(settings); @@ -151,7 +153,7 @@ function findConflicts(schemas) { /** * Returns / reconstitutes saved overrides list. */ -function getSavedOverrides() { +export function getSavedOverrides() { let saveListJson = gsettings.get_string(RESTORE_KEYBINDS_KEY); let saveList; try { @@ -165,11 +167,11 @@ function getSavedOverrides() { /** * Saves an overrides list. */ -function saveOverrides(overrides) { +export function saveOverrides(overrides) { gsettings.set_string(RESTORE_KEYBINDS_KEY, JSON.stringify(Object.fromEntries(overrides))); } -function conflictKeyChanged(settings, key) { +export function conflictKeyChanged(settings, key) { if (_overriddingConflicts) { return; } @@ -190,7 +192,7 @@ function conflictKeyChanged(settings, key) { /** * Override conflicts and save original values for restore. */ -function overrideConflicts(checkKey = null) { +export function overrideConflicts(checkKey = null) { if (_overriddingConflicts) { return; } @@ -233,7 +235,7 @@ function overrideConflicts(checkKey = null) { /** * Update overrides to their current keybinds. */ -function updateOverrides() { +export function updateOverrides() { let saveList = getSavedOverrides(); saveList.forEach((saved, key) => { const settings = getConflictSettings().find(s => s.schema_id === saved.schema_id); @@ -257,7 +259,7 @@ function updateOverrides() { /** * Restores previously overridden conflicts. */ -function restoreConflicts() { +export function restoreConflicts() { let saveList = getSavedOverrides(); const toRemove = []; saveList.forEach((saved, key) => { @@ -288,9 +290,8 @@ function restoreConflicts() { scratch_layer: true }) */ -var winprops = []; - -function winprop_match_p(meta_window, prop) { +export let winprops = []; +export function winprop_match_p(meta_window, prop) { let wm_class = meta_window.wm_class || ""; let title = meta_window.title; if (prop.wm_class) { @@ -312,7 +313,7 @@ function winprop_match_p(meta_window, prop) { return true; } -function find_winprop(meta_window) { +export function find_winprop(meta_window) { // sort by title first (prioritise title over wm_class) let props = winprops.filter(winprop_match_p.bind(null, meta_window)); @@ -330,11 +331,12 @@ function find_winprop(meta_window) { return null; } -function defwinprop(spec) { +export function defwinprop(spec) { // process preferredWidth - expects inputs like 50% or 400px if (spec.preferredWidth) { spec.preferredWidth = { // value is first contiguous block of digits + // eslint-disable-next-line no-new-wrappers value: new Number((spec.preferredWidth.match(/\d+/) ?? ['0'])[0]), // unit is first contiguous block of apha chars or % char unit: (spec.preferredWidth.match(/[a-zA-Z%]+/) ?? ['NO_UNIT'])[0], @@ -377,7 +379,7 @@ function defwinprop(spec) { * Adds user-defined winprops from gsettings (as defined in * org.gnome.shell.extensions.paperwm.winprops) to the winprops array. */ -function addWinpropsFromGSettings() { +export function addWinpropsFromGSettings() { // add gsetting (user config) winprops gsettings.get_value('winprops').deep_unpack() .map(value => JSON.parse(value)) @@ -405,7 +407,7 @@ function addWinpropsFromGSettings() { /** * Removes winprops with the `gsetting:true` property from the winprops array. */ -function removeGSettingWinpropsFromArray() { +export function removeGSettingWinpropsFromArray() { winprops = winprops.filter(prop => !prop.gsetting ?? true); } @@ -415,7 +417,7 @@ function removeGSettingWinpropsFromArray() { * array and then adds the currently defined * org.gnome.shell.extensions.paperwm.winprops winprops. */ -function reloadWinpropsFromGSettings() { +export function reloadWinpropsFromGSettings() { removeGSettingWinpropsFromArray(); addWinpropsFromGSettings(); } From e07315bb4bfa96e58747aa8fe23e3b2ba68bc54c Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 18:09:04 +1000 Subject: [PATCH 08/50] Ported keybindings.js to ESM imports. --- keybindings.js | 157 +++++++++++++++++++++++-------------------------- 1 file changed, 75 insertions(+), 82 deletions(-) diff --git a/keybindings.js b/keybindings.js index ec1c4be2..1783def6 100644 --- a/keybindings.js +++ b/keybindings.js @@ -1,46 +1,77 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const ExtensionModule = Extension.imports.extension; -const Settings = Extension.imports.settings; -const Utils = Extension.imports.utils; -const Tiling = Extension.imports.tiling; -const Navigator = Extension.imports.navigator; -const App = Extension.imports.app; -const Scratch = Extension.imports.scratch; -const LiveAltTab = Extension.imports.liveAltTab; -const keystrToKeycombo = Extension.imports.settings.keystrToKeycombo; - -const { Clutter, Meta, Shell } = imports.gi; +import Clutter from 'gi://Clutter'; +import Meta from 'gi://Meta'; +import Shell from 'gi://Shell'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; + +import { + Settings, Utils, Tiling, Navigator, + App, Scratch, LiveAltTab +} from './imports.js'; + const Seat = Clutter.get_default_backend().get_default_seat(); -const Main = imports.ui.main; const display = global.display; - let KEYBINDINGS_KEY = 'org.gnome.shell.extensions.paperwm.keybindings'; -function registerPaperAction(actionName, handler, flags) { - let settings = ExtensionUtils.getSettings(KEYBINDINGS_KEY); +let keybindSettings; +export function enable(extension) { + // restore previous keybinds (in case failed to restore last time, e.g. gnome crash etc) + Settings.updateOverrides(); + + keybindSettings = extension.getSettings(KEYBINDINGS_KEY); + setupActions(keybindSettings); + signals.connect(display, 'accelerator-activated', (display, actionId, deviceId, timestamp) => { + handleAccelerator(display, actionId, deviceId, timestamp); + }); + actions.forEach(enableAction); + Settings.overrideConflicts(); + + let schemas = [...Settings.getConflictSettings(), extension.getSettings(KEYBINDINGS_KEY)]; + schemas.forEach(schema => { + signals.connect(schema, 'changed', (settings, key) => { + const numConflicts = Settings.conflictKeyChanged(settings, key); + if (numConflicts > 0) { + Main.notify( + `PaperWM: overriding '${key}' keybind`, + `this Gnome Keybind will be restored when PaperWM is disabled`); + } + }); + }); +} + +export function disable() { + signals.destroy(); + signals = null; + actions.forEach(disableAction); + Settings.restoreConflicts(); + + actions = null; + nameMap = null; + actionIdMap = null; + keycomboMap = null; +} + +export function registerPaperAction(actionName, handler, flags) { registerAction( actionName, handler, - { settings, mutterFlags: flags, activeInNavigator: true }); + { settings: keybindSettings, mutterFlags: flags, activeInNavigator: true }); } -function registerNavigatorAction(name, handler) { - let settings = ExtensionUtils.getSettings(KEYBINDINGS_KEY); +export function registerNavigatorAction(name, handler) { registerAction( name, handler, - { settings, opensNavigator: true }); + { settings: keybindSettings, opensNavigator: true }); } -function registerMinimapAction(name, handler) { - let settings = ExtensionUtils.getSettings(KEYBINDINGS_KEY); +export function registerMinimapAction(name, handler) { registerAction( name, handler, { - settings, + settings: keybindSettings, opensNavigator: true, opensMinimap: true, mutterFlags: Meta.KeyBindingFlags.PER_WINDOW, @@ -50,7 +81,7 @@ function registerMinimapAction(name, handler) { let signals, actions, nameMap, actionIdMap, keycomboMap; -function setupActions() { +export function setupActions(settings) { signals = new Utils.Signals(); actions = []; nameMap = {}; // mutter keybinding action name -> action @@ -61,7 +92,6 @@ function setupActions() { let dynamic_function_ref = Utils.dynamic_function_ref; let liveAltTab = dynamic_function_ref('liveAltTab', LiveAltTab); - let settings = ExtensionUtils.getSettings(KEYBINDINGS_KEY); registerAction('live-alt-tab', liveAltTab, { settings }); registerAction('live-alt-tab-backward', @@ -236,8 +266,8 @@ function setupActions() { }, Meta.KeyBindingFlags.PER_WINDOW); } -function idOf(mutterName) { - let action = this.byMutterName(mutterName); +export function idOf(mutterName) { + let action = byMutterName(mutterName); if (action) { return action.id; } else { @@ -245,19 +275,19 @@ function idOf(mutterName) { } } -function byMutterName(name) { +export function byMutterName(name) { return nameMap[name]; } -function byId(mutterId) { +export function byId(mutterId) { return actionIdMap[mutterId]; } -function asKeyHandler(actionHandler) { +export function asKeyHandler(actionHandler) { return (display, mw, binding) => actionHandler(mw, Tiling.spaces.selectedSpace, { display, binding }); } -function impliedOptions(options) { +export function impliedOptions(options) { options = options = Object.assign({ mutterFlags: Meta.KeyBindingFlags.NONE }, options); if (options.opensMinimap) @@ -278,7 +308,7 @@ function impliedOptions(options) { * ... * } */ -function registerAction(actionName, handler, options) { +export function registerAction(actionName, handler, options) { options = impliedOptions(options); let { @@ -316,13 +346,13 @@ function registerAction(actionName, handler, options) { /** * Bind a key to an action (possibly creating a new action) */ -function bindkey(keystr, actionName = null, handler = null, options = {}) { +export function bindkey(keystr, actionName = null, handler = null, options = {}) { Utils.assert(!options.settings, "Can only bind schemaless actions - change action's settings instead", actionName); let action = actionName && actions.find(a => a.name === actionName); - let keycombo = keystrToKeycombo(keystr); + let keycombo = Settings.keystrToKeycombo(keystr); if (!action) { action = registerAction(actionName, handler, options); @@ -365,7 +395,7 @@ function bindkey(keystr, actionName = null, handler = null, options = {}) { message = "Usually caused by the binding already being taken, but could not identify which action"; } - ExtensionModule.errorNotification( + Main.notify( "PaperWM (user.js): Could not enable keybinding", `Tried to bind ${keystr} to ${actionName}\n${message}`); } @@ -373,10 +403,10 @@ function bindkey(keystr, actionName = null, handler = null, options = {}) { return action.id; } -function unbindkey(actionIdOrKeystr) { +export function unbindkey(actionIdOrKeystr) { let actionId; if (typeof actionIdOrKeystr === "string") { - const action = keycomboMap[keystrToKeycombo(actionIdOrKeystr)]; + const action = keycomboMap[Settings.keystrToKeycombo(actionIdOrKeystr)]; actionId = action && action.id; } else { actionId = actionIdOrKeystr; @@ -385,7 +415,7 @@ function unbindkey(actionIdOrKeystr) { disableAction(actionIdMap[actionId]); } -function devirtualizeMask(gdkVirtualMask) { +export function devirtualizeMask(gdkVirtualMask) { const keymap = Seat.get_keymap(); let [success, rawMask] = keymap.map_virtual_modifiers(gdkVirtualMask); if (!success) @@ -393,12 +423,12 @@ function devirtualizeMask(gdkVirtualMask) { return rawMask; } -function rawMaskOfKeystr(keystr) { +export function rawMaskOfKeystr(keystr) { let [dontcare, keycodes, mask] = Settings.accelerator_parse(keystr); return devirtualizeMask(mask); } -function openNavigatorHandler(actionName, keystr) { +export function openNavigatorHandler(actionName, keystr) { const mask = rawMaskOfKeystr(keystr) & 0xff; const binding = { @@ -412,7 +442,7 @@ function openNavigatorHandler(actionName, keystr) { }; } -function getBoundActionId(keystr) { +export function getBoundActionId(keystr) { let [dontcare, keycodes, mask] = Settings.accelerator_parse(keystr); if (keycodes.length > 1) { throw new Error(`Multiple keycodes ${keycodes} ${keystr}`); @@ -421,7 +451,7 @@ function getBoundActionId(keystr) { return display.get_keybinding_action(keycodes[0], rawMask); } -function handleAccelerator(display, actionId, deviceId, timestamp) { +export function handleAccelerator(display, actionId, deviceId, timestamp) { const action = actionIdMap[actionId]; if (action) { Utils.debug("#keybindings", "Schemaless keybinding activated", @@ -434,7 +464,7 @@ function handleAccelerator(display, actionId, deviceId, timestamp) { } } -function disableAction(action) { +export function disableAction(action) { if (action.id === Meta.KeyBindingAction.NONE) { return; } @@ -456,7 +486,7 @@ function disableAction(action) { } } -function enableAction(action) { +export function enableAction(action) { if (action.id !== Meta.KeyBindingAction.NONE) return action.id; // Already enabled (happens on enable right after init) @@ -506,40 +536,3 @@ function enableAction(action) { return action.id; } } - -function enable() { - // restore previous keybinds (in case failed to restore last time, e.g. gnome crash etc) - Settings.updateOverrides(); - - setupActions(); - signals.connect(display, - 'accelerator-activated', - Utils.dynamic_function_ref(handleAccelerator.name, this) - ); - actions.forEach(enableAction); - Settings.overrideConflicts(); - - let schemas = [...Settings.getConflictSettings(), ExtensionUtils.getSettings(KEYBINDINGS_KEY)]; - schemas.forEach(schema => { - signals.connect(schema, 'changed', (settings, key) => { - const numConflicts = Settings.conflictKeyChanged(settings, key); - if (numConflicts > 0) { - Main.notify( - `PaperWM: overriding '${key}' keybind`, - `this Gnome Keybind will be restored when PaperWM is disabled`); - } - }); - }); -} - -function disable() { - signals.destroy(); - signals = null; - actions.forEach(disableAction); - Settings.restoreConflicts(); - - actions = null; - nameMap = null; - actionIdMap = null; - keycomboMap = null; -} From 16bc95fcb57947732d9ca03796b9eac3f6711603 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 18:12:38 +1000 Subject: [PATCH 09/50] Export functions in lib.js. --- lib.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib.js b/lib.js index ca016dce..31f2aade 100644 --- a/lib.js +++ b/lib.js @@ -8,7 +8,7 @@ Cycle to first value if no larger value is found. `values` should be sorted in ascending order. */ -function findNext(cur, values, slack=0) { +export function findNext(cur, values, slack = 0) { for (let i = 0; i < values.length; i++) { let x = values[i]; if (cur < x) { @@ -23,7 +23,7 @@ function findNext(cur, values, slack=0) { return values[0]; // cycle } -function findPrev(cur, values, slack=0) { +export function findPrev(cur, values, slack = 0) { let i = 0; for (;i < values.length; i++) { let x = values[i]; @@ -31,7 +31,7 @@ function findPrev(cur, values, slack=0) { break; } } - target_i = i - 1; + let target_i = i - 1; if (target_i < 0) { target_i = values.length - 1; } @@ -39,7 +39,7 @@ function findPrev(cur, values, slack=0) { return values[target_i]; } -function arrayEqual(a, b) { +export function arrayEqual(a, b) { if (a === b) return true; if (!a || !b) @@ -54,21 +54,21 @@ function arrayEqual(a, b) { } /** Is the floating point numbers equal enough */ -function eq(a, b, epsilon=0.00000001) { - return Math.abs(a-b) < epsilon; +export function eq(a, b, epsilon = 0.00000001) { + return Math.abs(a - b) < epsilon; } -function swap(array, i, j) { +export function swap(array, i, j) { let temp = array[i]; array[i] = array[j]; array[j] = temp; } -function in_bounds(array, i) { +export function in_bounds(array, i) { return i >= 0 && i < array.length; } -function indent(level, str) { +export function indent(level, str) { let blank = ""; for (let i = 0; i < level; i++) { blank += " "; @@ -76,11 +76,11 @@ function indent(level, str) { return blank + str; } -function sum(array) { +export function sum(array) { return array.reduce((a, b) => a + b, 0); } -function zip(...as) { +export function zip(...as) { let r = []; let minLength = Math.min(...as.map(x => x.length)); for (let i = 0; i < minLength; i++) { From 8bde99a10da4671af6922fa359a159037731897e Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 20:43:55 +1000 Subject: [PATCH 10/50] Ported liveAltTab to ESM imports. --- keybindings.js | 3 ++- liveAltTab.js | 53 ++++++++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/keybindings.js b/keybindings.js index 1783def6..a152e7c9 100644 --- a/keybindings.js +++ b/keybindings.js @@ -12,7 +12,7 @@ import { const Seat = Clutter.get_default_backend().get_default_seat(); const display = global.display; -let KEYBINDINGS_KEY = 'org.gnome.shell.extensions.paperwm.keybindings'; +const KEYBINDINGS_KEY = 'org.gnome.shell.extensions.paperwm.keybindings'; let keybindSettings; export function enable(extension) { @@ -46,6 +46,7 @@ export function disable() { actions.forEach(disableAction); Settings.restoreConflicts(); + keybindSettings = null; actions = null; nameMap = null; actionIdMap = null; diff --git a/liveAltTab.js b/liveAltTab.js index bc6e31f1..142a0493 100644 --- a/liveAltTab.js +++ b/liveAltTab.js @@ -1,17 +1,25 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Settings = Extension.imports.settings; -const Utils = Extension.imports.utils; -const Keybindings = Extension.imports.keybindings; -const Tiling = Extension.imports.tiling; -const Scratch = Extension.imports.scratch; -const Easer = Extension.imports.utils.easer; - -const { Clutter, Meta, Gio, GObject } = imports.gi; -const Main = imports.ui.main; -const AltTab = imports.ui.altTab; - -var LiveAltTab = GObject.registerClass( +import Clutter from 'gi://Clutter'; +import Meta from 'gi://Meta'; +import Gio from 'gi://Gio'; +import GObject from 'gi://GObject'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as AltTab from 'resource:///org/gnome/shell/ui/altTab.js'; + +import { Settings, Utils, Keybindings, Tiling, Scratch, Easer } from './imports.js'; + +let switcherSettings; +export function enable() { + switcherSettings = new Gio.Settings({ + schema_id: 'org.gnome.shell.window-switcher', + }); +} + +export function disable() { + switcherSettings = null; +} + +export const LiveAltTab = GObject.registerClass( class LiveAltTab extends AltTab.WindowSwitcherPopup { _init(reverse) { this.reverse = reverse; @@ -29,9 +37,9 @@ var LiveAltTab = GObject.registerClass( if (Scratch.isScratchWindow(global.display.focus_window)) { // Access scratch windows in mru order with shift-super-tab - return scratch.concat(this.reverse ? tabList.reverse() : tabList); + return scratch.concat(reverse ? tabList.reverse() : tabList); } else { - return tabList.concat(this.reverse ? scratch.reverse() : scratch); + return tabList.concat(reverse ? scratch.reverse() : scratch); } } @@ -157,18 +165,7 @@ var LiveAltTab = GObject.registerClass( } }); -function liveAltTab(meta_window, space, { display, screen, binding }) { +export function liveAltTab(meta_window, space, { display, screen, binding }) { let tabPopup = new LiveAltTab(binding.is_reversed()); tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()); } - -let switcherSettings; -function enable() { - switcherSettings = new Gio.Settings({ - schema_id: 'org.gnome.shell.window-switcher', - }); -} - -function disable() { - switcherSettings = null; -} From 864f8d2a7b44c285af61a495b5d4b362c7b5f717 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 20:49:14 +1000 Subject: [PATCH 11/50] Ported minimap.js to ESM. --- gestures.js | 3 +- grab.js | 3 +- minimap.js | 79 ++++++++++++++++++++++++++--------------------------- 3 files changed, 42 insertions(+), 43 deletions(-) diff --git a/gestures.js b/gestures.js index 3bc66803..7b904a10 100644 --- a/gestures.js +++ b/gestures.js @@ -6,7 +6,8 @@ import Shell from 'gi://Shell'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import { Patches, Settings, Tiling, Utils, Lib, Easer, Navigator } from './imports.js'; +import { Patches, Settings, Tiling, Utils, Lib, Navigator } from './imports.js'; +import { Easer } from './utils.js'; const DIRECTIONS = { Horizontal: true, diff --git a/grab.js b/grab.js index df67eae0..59e8a96f 100644 --- a/grab.js +++ b/grab.js @@ -6,7 +6,8 @@ import St from 'gi://St'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import { Settings, Utils, Tiling, Navigator, Scratch, Easer } from './imports.js'; +import { Settings, Utils, Tiling, Navigator, Scratch } from './imports.js'; +import { Easer } from './utils.js'; /** * Returns a virtual pointer (i.e. mouse) device that can be used to diff --git a/minimap.js b/minimap.js index 86be1d83..6f55340b 100644 --- a/minimap.js +++ b/minimap.js @@ -1,16 +1,13 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Settings = Extension.imports.settings; -const Utils = Extension.imports.utils; -const Lib = Extension.imports.lib; -const Easer = Extension.imports.utils.easer; - -const Clutter = imports.gi.Clutter; -const Main = imports.ui.main; -const St = imports.gi.St; -const Pango = imports.gi.Pango; - -function calcOffset(metaWindow) { +import Clutter from 'gi://Clutter'; +import St from 'gi://St'; +import Pango from 'gi://Pango'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; + +import { Settings, Utils, Lib } from './imports.js'; +import { Easer } from './utils.js'; + +export function calcOffset(metaWindow) { let buffer = metaWindow.get_buffer_rect(); let frame = metaWindow.get_frame_rect(); let x_offset = frame.x - buffer.x; @@ -18,39 +15,39 @@ function calcOffset(metaWindow) { return [x_offset, y_offset]; } -var Minimap = class Minimap extends Array { +export class Minimap extends Array { constructor(space, monitor) { super(); this.space = space; this.monitor = monitor; let actor = new St.Widget({ name: 'minimap', - style_class: 'paperwm-minimap switcher-list' + style_class: 'paperwm-minimap switcher-list', }); this.actor = actor; - actor.height = space.height*0.20; + actor.height = space.height * 0.20; let highlight = new St.Widget({ name: 'minimap-selection', - style_class: 'paperwm-minimap-selection item-box' + style_class: 'paperwm-minimap-selection item-box', }); highlight.add_style_pseudo_class('selected'); this.highlight = highlight; - let label = new St.Label({style_class: 'paperwm-minimap-label'}); + let label = new St.Label({ style_class: 'paperwm-minimap-label' }); label.clutter_text.ellipsize = Pango.EllipsizeMode.END; this.label = label; - let clip = new St.Widget({name: 'container-clip'}); + let clip = new St.Widget({ name: 'container-clip' }); this.clip = clip; - let container = new St.Widget({name: 'minimap-container'}); + let container = new St.Widget({ name: 'minimap-container' }); this.container = container; - container.height = Math.round(space.height*Settings.prefs.minimap_scale) - Settings.prefs.window_gap; + container.height = Math.round(space.height * Settings.prefs.minimap_scale) - Settings.prefs.window_gap; actor.add_actor(highlight); actor.add_actor(label); actor.add_actor(clip); clip.add_actor(container); - clip.set_position(12 + Settings.prefs.window_gap, 12 + Math.round(1.5*Settings.prefs.window_gap)); + clip.set_position(12 + Settings.prefs.window_gap, 12 + Math.round(1.5 * Settings.prefs.window_gap)); highlight.y = clip.y - 10; Main.uiGroup.add_actor(this.actor); this.actor.opacity = 0; @@ -70,8 +67,8 @@ var Minimap = class Minimap extends Array { static get [Symbol.species]() { return Array; } reset() { - this.splice(0,this.length).forEach(c => c.forEach(x => x.destroy())) - this.createClones() + this.splice(0, this.length).forEach(c => c.forEach(x => x.destroy())); + this.createClones(); this.layout(); } @@ -127,7 +124,7 @@ var Minimap = class Minimap extends Array { Easer.addEase(this.actor, { opacity: 0, time, mode: Clutter.AnimationMode.EASE_OUT_EXPO, - onComplete: () => this.actor.hide() + onComplete: () => this.actor.hide(), }); } @@ -142,7 +139,7 @@ var Minimap = class Minimap extends Array { let clone = new Clutter.Clone({ source: windowActor }); let container = new Clutter.Actor({ // layout_manager: new WindowCloneLayout(this), - name: "window-clone-container" + name: "window-clone-container", }); clone.meta_window = mw; container.clone = clone; @@ -159,10 +156,10 @@ var Minimap = class Minimap extends Array { let buffer = meta_window.get_buffer_rect(); let frame = meta_window.get_frame_rect(); let scale = Settings.prefs.minimap_scale; - clone.set_size(buffer.width*scale, buffer.height*scale - Settings.prefs.window_gap); - clone.set_position(((buffer.x - frame.x)*scale), - (buffer.y - frame.y)*scale); - container.set_size(frame.width*scale, frame.height*scale); + clone.set_size(buffer.width * scale, buffer.height * scale - Settings.prefs.window_gap); + clone.set_position((buffer.x - frame.x) * scale, + (buffer.y - frame.y) * scale); + container.set_size(frame.width * scale, frame.height * scale); } layout() { @@ -182,13 +179,13 @@ var Minimap = class Minimap extends Array { } this.clip.width = Math.min(this.container.width, - this.monitor.width - this.clip.x*2 - 24); - this.actor.width = this.clip.width + this.clip.x*2; + this.monitor.width - this.clip.x * 2 - 24); + this.actor.width = this.clip.width + this.clip.x * 2; this.clip.set_clip(0, 0, this.clip.width, this.clip.height); this.label.set_style(`max-width: ${this.clip.width}px;`); this.actor.set_position( - this.monitor.x + Math.floor((this.monitor.width - this.actor.width)/2), - this.monitor.y + Math.floor((this.monitor.height - this.actor.height)/2)); + this.monitor.x + Math.floor((this.monitor.width - this.actor.width) / 2), + this.monitor.y + Math.floor((this.monitor.height - this.actor.height) / 2)); this.select(); } @@ -214,12 +211,12 @@ var Minimap = class Minimap extends Array { if (selected.x + selected.width + container.x > clip.width) { // Align right edge of selected with the clip - container.x = clip.width - (selected.x + selected.width) + container.x = clip.width - (selected.x + selected.width); container.x -= 500; // margin } if (selected.x + container.x < 0) { // Align left edge of selected with the clip - container.x = -selected.x + container.x = -selected.x; container.x += 500; // margin } @@ -231,14 +228,14 @@ var Minimap = class Minimap extends Array { let gap = Settings.prefs.window_gap; highlight.x = Math.round( - clip.x + container.x + selected.x - gap/2); + clip.x + container.x + selected.x - gap / 2); highlight.y = Math.round( clip.y + selected.y - Settings.prefs.window_gap); highlight.set_size(Math.round(selected.width + gap), - Math.round(Math.min(selected.height, this.clip.height + gap) + gap)); + Math.round(Math.min(selected.height, this.clip.height + gap) + gap)); - let x = highlight.x - + (highlight.width - label.width)/2; + let x = highlight.x + + (highlight.width - label.width) / 2; if (x + label.width > clip.x + clip.width) x = clip.x + clip.width - label.width + 5; if (x < 0) @@ -257,7 +254,7 @@ var Minimap = class Minimap extends Array { this.destroyed = true; this.signals.destroy(); this.signals = null; - this.splice(0,this.length); + this.splice(0, this.length); this.actor.destroy(); this.actor = null; } From f8a982a359d07091fecc72f20c2c783a1b845cdf Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 21:03:51 +1000 Subject: [PATCH 12/50] Ported Utils.js to ESM. --- imports.js | 1 + utils.js | 108 ++++++++++++++++++++++++++++------------------------- 2 files changed, 59 insertions(+), 50 deletions(-) diff --git a/imports.js b/imports.js index b7366c57..992b579b 100644 --- a/imports.js +++ b/imports.js @@ -12,3 +12,4 @@ export * as Tiling from './tiling.js'; export * as Topbar from './topbar.js'; export * as Patches from './patches.js'; export * as App from './app.js'; +export * as Lib from './lib.js'; diff --git a/utils.js b/utils.js index 93e6a275..0b4c7e8b 100644 --- a/utils.js +++ b/utils.js @@ -1,28 +1,36 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Lib = Extension.imports.lib; -const { GLib, Clutter, Meta, St, GdkPixbuf, Cogl, Gio } = imports.gi; -const Main = imports.ui.main; -const Ripples = imports.ui.ripples; -const Mainloop = imports.mainloop; -const Display = global.display; +import Clutter from 'gi://Clutter'; +import Cogl from 'gi://Cogl'; +import GdkPixbuf from 'gi://GdkPixbuf'; +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; +import Meta from 'gi://Meta'; +import St from 'gi://St'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as Ripples from 'resource:///org/gnome/shell/ui/ripples.js'; -var version = imports.misc.config.PACKAGE_VERSION.split('.').map(Number); // exported +import Lib from './imports.js'; + +const Display = global.display; +export let version = imports.misc.config.PACKAGE_VERSION.split('.').map(Number); let warpRipple; -function enable() { +export function enable() { warpRipple = new Ripples.Ripples(0.5, 0.5, 'ripple-pointer-location'); warpRipple.addTo(Main.uiGroup); } -function disable() { +export function disable() { warpRipple?.destroy(); warpRipple = null; + debug_all = null; + debug_filter = null; + markNewClonesSignalId = null; } let debug_all = false; // Turn off by default let debug_filter = { '#paperwm': true, '#stacktrace': true }; -function debug() { +export function debug() { let keyword = arguments[0]; let filter = debug_filter[keyword]; if (filter === false) @@ -31,20 +39,20 @@ function debug() { console.debug(Array.prototype.join.call(arguments, " | ")); } -function assert(condition, message, ...dump) { +export function assert(condition, message, ...dump) { if (!condition) { throw new Error(`${message}\n`, dump); } } -function withTimer(message, fn) { +export function withTimer(message, fn) { let start = GLib.get_monotonic_time(); let ret = fn(); let stop = GLib.get_monotonic_time(); console.debug(`${message} ${((stop - start) / 1000).toFixed(1)}ms`); } -function print_stacktrace(error) { +export function print_stacktrace(error) { let trace; if (!error) { trace = new Error().stack.split("\n"); @@ -64,18 +72,18 @@ function print_stacktrace(error) { * Pretty prints args using JSON.stringify. * @param {...any} arugs */ -function prettyPrintToLog(...args) { +export function prettyPrintToLog(...args) { console.log(args.map(v => JSON.stringify(v, null), 2)); } -function framestr(rect) { +export function framestr(rect) { return `[ x:${rect.x}, y:${rect.y} w:${rect.width} h:${rect.height} ]`; } /** * Returns a human-readable enum value representation */ -function ppEnumValue(value, genum) { +export function ppEnumValue(value, genum) { let entry = Object.entries(genum).find(([k, v]) => v === value); if (entry) { return `${entry[0]} (${entry[1]})`; @@ -84,7 +92,7 @@ function ppEnumValue(value, genum) { } } -function ppModiferState(state) { +export function ppModiferState(state) { let mods = []; for (let [mod, mask] of Object.entries(Clutter.ModifierType)) { if (mask & state) { @@ -99,19 +107,19 @@ function ppModiferState(state) { * redefine the function without re-registering all signal handler, keybindings, * etc. (this is like a function symbol in lisp) */ -function dynamic_function_ref(handler_name, owner_obj) { +export function dynamic_function_ref(handler_name, owner_obj) { owner_obj = owner_obj || window; return function() { owner_obj[handler_name].apply(this, arguments); }; } -function isPointInsideActor(actor, x, y) { +export function isPointInsideActor(actor, x, y) { return (actor.x <= x && x <= actor.x + actor.width) && (actor.y <= y && y <= actor.y + actor.height); } -function setBackgroundImage(actor, resource_path) { +export function setBackgroundImage(actor, resource_path) { // resource://{resource_path} let image = new Clutter.Image(); @@ -133,7 +141,7 @@ function setBackgroundImage(actor, resource_path) { /** * Visualize the frame and buffer bounding boxes of a meta window */ -function toggleWindowBoxes(metaWindow) { +export function toggleWindowBoxes(metaWindow) { metaWindow = metaWindow || Display.focus_window; if (metaWindow._paperDebugBoxes) { @@ -144,11 +152,11 @@ function toggleWindowBoxes(metaWindow) { return []; } - let frame = metaWindow.get_frame_rect(); - let inputFrame = metaWindow.get_buffer_rect(); - let actor = metaWindow.get_compositor_private(); + const frame = metaWindow.get_frame_rect(); + const inputFrame = metaWindow.get_buffer_rect(); + const actor = metaWindow.get_compositor_private(); - makeFrameBox = function({ x, y, width, height }, color) { + const makeFrameBox = ({ x, y, width, height }, color) => { let frameBox = new St.Widget(); frameBox.set_position(x, y); frameBox.set_size(width, height); @@ -173,7 +181,7 @@ function toggleWindowBoxes(metaWindow) { } let markNewClonesSignalId = null; -function toggleCloneMarks() { +export function toggleCloneMarks() { // NB: doesn't clean up signal on disable function markCloneOf(metaWindow) { @@ -205,7 +213,7 @@ function toggleCloneMarks() { } } -function isInRect(x, y, r) { +export function isInRect(x, y, r) { return r.x <= x && x < r.x + r.width && r.y <= y && y < r.y + r.height; } @@ -213,7 +221,7 @@ function isInRect(x, y, r) { /** * Returns monitor a pointer co-ordinates. */ -function monitorAtPoint(gx, gy) { +export function monitorAtPoint(gx, gy) { for (let monitor of Main.layoutManager.monitors) { if (isInRect(gx, gy, monitor)) return monitor; @@ -224,7 +232,7 @@ function monitorAtPoint(gx, gy) { /** * Returns the monitor current pointer coordinates. */ -function monitorAtCurrentPoint() { +export function monitorAtCurrentPoint() { let [gx, gy, $] = global.get_pointer(); return monitorAtPoint(gx, gy); } @@ -232,7 +240,7 @@ function monitorAtCurrentPoint() { /** * Warps pointer to the center of a monitor. */ -function warpPointerToMonitor(monitor, center = false) { +export function warpPointerToMonitor(monitor, center = false) { // no need to warp if already on this monitor let currMonitor = monitorAtCurrentPoint(); if (currMonitor === monitor) { @@ -259,7 +267,7 @@ function warpPointerToMonitor(monitor, center = false) { /** * Warps pointer to x, y coordinates. */ -function warpPointer(x, y) { +export function warpPointer(x, y) { let backend = Clutter.get_default_backend(); let seat = backend.get_default_seat(); seat.warp_pointer(x, y); @@ -269,12 +277,12 @@ function warpPointer(x, y) { /** * Return current modifiers state (or'ed Clutter.ModifierType.*) */ -function getModiferState() { +export function getModiferState() { let [x, y, mods] = global.get_pointer(); return mods; } -function monitorOfPoint(x, y) { +export function monitorOfPoint(x, y) { // get_monitor_index_for_rect "helpfully" returns the primary monitor index for out of bounds rects.. for (let monitor of Main.layoutManager.monitors) { if ((monitor.x <= x && x <= monitor.x + monitor.width) && @@ -287,7 +295,7 @@ function monitorOfPoint(x, y) { return null; } -function mkFmt({ nameOnly } = { nameOnly: false }) { +export function mkFmt({ nameOnly } = { nameOnly: false }) { function defaultFmt(actor, prefix = "") { const fmtNum = num => num.toFixed(0); let extra = [ @@ -313,7 +321,7 @@ function mkFmt({ nameOnly } = { nameOnly: false }) { return defaultFmt; } -function printActorTree(node, fmt = mkFmt(), options = {}, state = null) { +export function printActorTree(node, fmt = mkFmt(), options = {}, state = null) { state = Object.assign({}, state || { level: 0, actorPrefix: "" }); const defaultOptions = { limit: 9999, @@ -361,11 +369,11 @@ function printActorTree(node, fmt = mkFmt(), options = {}, state = null) { } } -function isMetaWindow(obj) { +export function isMetaWindow(obj) { return obj && obj.window_type && obj.get_compositor_private; } -function shortTrace(skip = 0) { +export function shortTrace(skip = 0) { let trace = new Error().stack.split("\n").map(s => { let words = s.split(/[@/]/); let cols = s.split(":"); @@ -379,7 +387,7 @@ function shortTrace(skip = 0) { return trace.slice(skip + 1, skip + 5); } -function actor_raise(actor, above) { +export function actor_raise(actor, above) { const parent = actor.get_parent(); if (!parent) { return; @@ -389,7 +397,7 @@ function actor_raise(actor, above) { parent.set_child_above_sibling(actor, above); } -function actor_reparent(actor, newParent) { +export function actor_reparent(actor, newParent) { const parent = actor.get_parent(); if (parent) { parent.remove_child(actor); @@ -400,7 +408,7 @@ function actor_reparent(actor, newParent) { /** * Backwards compatible later_add function. */ -function later_add(...args) { +export function later_add(...args) { // Gnome 44+ uses global.compositor.get_laters() if (global.compositor?.get_laters) { global.compositor.get_laters().add(...args); @@ -414,7 +422,7 @@ function later_add(...args) { /** * Backwards compatible Display.grab_accelerator function. */ -function grab_accelerator(keystr, keyBindingFlags = Meta.KeyBindingFlags.NONE) { +export function grab_accelerator(keystr, keyBindingFlags = Meta.KeyBindingFlags.NONE) { if (Display.grab_accelerator.length > 1) { return Display.grab_accelerator(keystr, keyBindingFlags); } else { @@ -425,15 +433,15 @@ function grab_accelerator(keystr, keyBindingFlags = Meta.KeyBindingFlags.NONE) { /** * Convenience method for removing timeout source(s) from Mainloop. */ -function timeout_remove(...timeouts) { +export function timeout_remove(...timeouts) { timeouts.forEach(t => { if (t) { - Mainloop.source_remove(t); + GLib.source_remove(t); } }); } -var Signals = class Signals extends Map { +export class Signals extends Map { static get [Symbol.species]() { return Map; } _getOrCreateSignals(object) { @@ -483,14 +491,14 @@ var Signals = class Signals extends Map { this.delete(object); } } -}; +} /** * Note the name 'Tweener' used previously was just a legacy name, we're actually using * Widget.ease here. This was renamed to avoid confusion with the deprecated `Tweener` * module. */ -var easer = { +export let Easer = { addEase(actor, params) { if (params.time) { params.duration = params.time * 1000; @@ -510,7 +518,7 @@ var easer = { }, }; -var DisplayConfig = class DisplayConfig { +export class DisplayConfig { static get proxyWrapper() { return Gio.DBusProxy.makeProxyWrapper('\ \ @@ -586,4 +594,4 @@ var DisplayConfig = class DisplayConfig { get gnomeMonitors() { return Main.layoutManager.monitors; } -}; +} From 0e82967f75dcd654be8082cec5d9fe7b57378a8a Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 21:31:33 +1000 Subject: [PATCH 13/50] Ported navigator.js. --- navigator.js | 68 +++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/navigator.js b/navigator.js index 41bfa434..079c10f1 100644 --- a/navigator.js +++ b/navigator.js @@ -1,28 +1,24 @@ +import Clutter from 'gi://Clutter'; +import GLib from 'gi://GLib'; +import Meta from 'gi://Meta'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; + +import { Utils, Tiling, Keybindings, TopBar, Scratch, Minimap } from './imports.js'; + /** Navigation and previewing functionality. This is a somewhat messy tangle of functionality relying on `SwitcherPopup.SwitcherPopup` when we really should just take full control. */ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Utils = Extension.imports.utils; -const Tiling = Extension.imports.tiling; -const Keybindings = Extension.imports.keybindings; -const TopBar = Extension.imports.topbar; -const Scratch = Extension.imports.scratch; -const Minimap = Extension.imports.minimap; - -const { Meta, Clutter } = imports.gi; -const Main = imports.ui.main; -const Mainloop = imports.mainloop; -const Signals = imports.signals; +const { Signals } = imports; const display = global.display; -var navigating; // exported +export let navigating; // exported let grab, dispatcher, signals; -function enable() { +export function enable() { navigating = false; /** @@ -38,19 +34,21 @@ function enable() { }); } -function disable() { +export function disable() { navigating = false; grab = null; dispatcher = null; signals.destroy(); signals = null; + index = null; } -function dec2bin(dec) { +export function dec2bin(dec) { return (dec >>> 0).toString(2); } -const modMask = Clutter.ModifierType.SUPER_MASK | +const modMask = + Clutter.ModifierType.SUPER_MASK | Clutter.ModifierType.HYPER_MASK | Clutter.ModifierType.META_MASK | Clutter.ModifierType.CONTROL_MASK | @@ -59,8 +57,7 @@ const modMask = Clutter.ModifierType.SUPER_MASK | Clutter.ModifierType.MOD3_MASK | Clutter.ModifierType.MOD4_MASK | Clutter.ModifierType.MOD5_MASK; - -function getModLock(mods) { +export function getModLock(mods) { return mods & modMask; } @@ -136,7 +133,8 @@ class ActionDispatcher { _resetNoModsTimeout() { Utils.timeout_remove(this._noModsTimeoutId); - this._noModsTimeoutId = Mainloop.timeout_add( + this._noModsTimeoutId = GLib.timeout_add( + GLib.PRIORITY_DEFAULT, 0, () => { this._finish(global.get_current_time()); this._noModsTimeoutId = null; @@ -156,7 +154,7 @@ class ActionDispatcher { // visual destruction on key-press and signal to the release handler // that we should destroy the dispactcher too // https://github.com/paperwm/PaperWM/issues/70 - if (keysym == Clutter.KEY_Escape) { + if (keysym === Clutter.KEY_Escape) { this._destroy = true; getNavigator().accept(); getNavigator().destroy(); @@ -177,7 +175,7 @@ class ActionDispatcher { let [x, y, mods] = global.get_pointer(); let state = mods & this._modifierMask; - if (state == 0) + if (state === 0) this._finish(event.get_time()); } else { this._resetNoModsTimeout(); @@ -192,7 +190,7 @@ class ActionDispatcher { let metaWindow = space.selectedWindow; const nav = getNavigator(); - if (mutterActionId == Meta.KeyBindingAction.MINIMIZE) { + if (mutterActionId === Meta.KeyBindingAction.MINIMIZE) { metaWindow.minimize(); } else if (action && action.options.activeInNavigator) { // action is performed while navigator is open (e.g. switch-left) @@ -206,7 +204,7 @@ class ActionDispatcher { action.handler(metaWindow, space, { navigator: this.navigator }); if (space !== Tiling.spaces.selectedSpace) { this.navigator.minimaps.forEach(m => typeof m === 'number' - ? Mainloop.source_remove(m) : m.hide()); + ? GLib.source_remove(m) : m.hide()); } if (Tiling.inGrab && !Tiling.inGrab.dnd && Tiling.inGrab.window) { Tiling.inGrab.beginDnD(); @@ -215,7 +213,7 @@ class ActionDispatcher { // closes navigator and action is performed afterwards // (e.g. switch-monitor-left) this._resetNoModsTimeout(); - this._doActionTimeout = Mainloop.timeout_add(0, () => { + this._doActionTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 0, () => { action.handler(metaWindow, space); this._doActionTimeout = null; return false; // on return false destroys timeout @@ -262,7 +260,7 @@ class ActionDispatcher { } let index = 0; -var navigator; // exported +export let navigator; class NavigatorClass { constructor() { Utils.debug("#navigator", "nav created"); @@ -291,7 +289,7 @@ class NavigatorClass { _showMinimap(space) { let minimap = this.minimaps.get(space); if (!minimap) { - let minimapId = Mainloop.timeout_add(200, () => { + let minimapId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, () => { minimap = new Minimap.Minimap(space, this.monitor); space.startAnimate(); minimap.show(false); @@ -318,7 +316,7 @@ class NavigatorClass { destroy(space, focus) { this.minimaps.forEach(m => { if (typeof m === 'number') { - Mainloop.source_remove(m); + GLib.source_remove(m); } else { m.destroy(); @@ -413,10 +411,10 @@ class NavigatorClass { navigator = false; } } -var Navigator = NavigatorClass; +export let Navigator = NavigatorClass; Signals.addSignalMethods(Navigator.prototype); -function getNavigator() { +export function getNavigator() { if (navigator) return navigator; @@ -428,7 +426,7 @@ function getNavigator() { * Finishes navigation if navigator exists. * Useful to call before disabling other modules. */ -function finishNavigation() { +export function finishNavigation() { if (navigator) { navigator.finish(); } @@ -439,7 +437,7 @@ function finishNavigation() { * @param {import('@gi-types/clutter10').GrabState} mode * @returns {ActionDispatcher} */ -function getActionDispatcher(mode) { +export function getActionDispatcher(mode) { if (dispatcher) { dispatcher.mode |= mode; return dispatcher; @@ -452,7 +450,7 @@ function getActionDispatcher(mode) { * * @param {import('@gi-types/clutter10').GrabState} mode */ -function dismissDispatcher(mode) { +export function dismissDispatcher(mode) { if (!dispatcher) { return; } @@ -463,7 +461,7 @@ function dismissDispatcher(mode) { } } -function preview_navigate(meta_window, space, { display, screen, binding }) { +export function preview_navigate(meta_window, space, { display, screen, binding }) { let tabPopup = getActionDispatcher(Clutter.GrabState.KEYBOARD); tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()); } From 461910543465474665ed63f186af195fb01feb3f Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 21:48:29 +1000 Subject: [PATCH 14/50] Ported scratch.js. --- scratch.js | 99 ++++++++++++++++++++++++++---------------------------- 1 file changed, 48 insertions(+), 51 deletions(-) diff --git a/scratch.js b/scratch.js index 122692b6..98e0e18f 100644 --- a/scratch.js +++ b/scratch.js @@ -1,15 +1,37 @@ -const Extension = imports.misc.extensionUtils.getCurrentExtension(); -const Meta = imports.gi.Meta; -const Main = imports.ui.main; -const PopupMenu = imports.ui.popupMenu; -const WindowMenu = imports.ui.windowMenu; - -const Settings = Extension.imports.settings; -const utils = Extension.imports.utils; -const Easer = Extension.imports.utils.easer; -const Tiling = Extension.imports.tiling; -const TopBar = Extension.imports.topbar; +import Meta from 'gi://Meta'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; +import * as WindowMenu from 'resource:///org/gnome/shell/ui/windowMenu.js'; + +import { Settings, Utils, Tiling, Topbar } from './imports.js'; +import { Easer } from './utils.js'; + let float, scratchFrame; // symbols used for expando properties on metawindow +let originalBuildMenu; +export function enable() { + originalBuildMenu = WindowMenu.WindowMenu.prototype._buildMenu; + float = Symbol(); + scratchFrame = Symbol(); + WindowMenu.WindowMenu.prototype._buildMenu = + function (window) { + let item; + item = this.addAction(_('Scratch'), () => { + toggle(window); + }); + if (isScratchWindow(window)) + item.setOrnament(PopupMenu.Ornament.CHECK); + + originalBuildMenu.call(this, window); + }; +} + +export function disable() { + WindowMenu.WindowMenu.prototype._buildMenu = originalBuildMenu; + originalBuildMenu = null; + float = null; + scratchFrame = null; +} /** Tween window to "frame-coordinate" (targetX, targetY). @@ -18,7 +40,7 @@ let float, scratchFrame; // symbols used for expando properties on metawindow The actual window actor (not clone) is tweened to ensure it's on top of the other windows/clones (clones if the space animates) */ -function easeScratch(metaWindow, targetX, targetY, tweenParams = {}) { +export function easeScratch(metaWindow, targetX, targetY, tweenParams = {}) { let f = metaWindow.get_frame_rect(); let b = metaWindow.get_buffer_rect(); let dx = f.x - b.x; @@ -39,7 +61,7 @@ function easeScratch(metaWindow, targetX, targetY, tweenParams = {}) { })); } -function makeScratch(metaWindow) { +export function makeScratch(metaWindow) { let fromNonScratch = !metaWindow[float]; let fromTiling = false; // Relevant when called while navigating. Use the position the user actually sees. @@ -69,7 +91,7 @@ function makeScratch(metaWindow) { if (metaWindow[scratchFrame]) { let sf = metaWindow[scratchFrame]; - if (utils.monitorOfPoint(sf.x, sf.y) === Tiling.focusMonitor()) { + if (Utils.monitorOfPoint(sf.x, sf.y) === Tiling.focusMonitor()) { targetFrame = sf; } } @@ -108,7 +130,7 @@ function makeScratch(metaWindow) { monitor.clickOverlay.hide(); } -function unmakeScratch(metaWindow) { +export function unmakeScratch(metaWindow) { if (!metaWindow[scratchFrame]) metaWindow[scratchFrame] = metaWindow.get_frame_rect(); metaWindow[float] = false; @@ -116,7 +138,7 @@ function unmakeScratch(metaWindow) { metaWindow.unstick(); } -function toggle(metaWindow) { +export function toggle(metaWindow) { if (isScratchWindow(metaWindow)) { unmakeScratch(metaWindow); } else { @@ -129,28 +151,28 @@ function toggle(metaWindow) { } } -function isScratchWindow(metaWindow) { +export function isScratchWindow(metaWindow) { return metaWindow && metaWindow[float]; } /** Return scratch windows in MRU order */ -function getScratchWindows() { +export function getScratchWindows() { return global.display.get_tab_list(Meta.TabList.NORMAL, null) .filter(isScratchWindow); } -function isScratchActive() { +export function isScratchActive() { return getScratchWindows().some(metaWindow => !metaWindow.minimized); } -function toggleScratch() { +export function toggleScratch() { if (isScratchActive()) hide(); else show(); } -function toggleScratchWindow() { +export function toggleScratchWindow() { let focus = global.display.focus_window; if (isScratchWindow(focus)) hide(); @@ -158,7 +180,7 @@ function toggleScratchWindow() { show(true); } -function show(top) { +export function show(top) { let windows = getScratchWindows(); if (windows.length === 0) { return; @@ -166,7 +188,7 @@ function show(top) { if (top) windows = windows.slice(0, 1); - TopBar.fixTopBar(); + Topbar.fixTopBar(); windows.slice().reverse() .map(function(meta_window) { @@ -181,14 +203,14 @@ function show(top) { monitor.clickOverlay.hide(); } -function hide() { +export function hide() { let windows = getScratchWindows(); windows.map(function(meta_window) { meta_window.minimize(); }); } -function animateWindows() { +export function animateWindows() { let ws = getScratchWindows().filter(w => !w.minimized); ws = global.display.sort_windows_by_stacking(ws); for (let w of ws) { @@ -201,32 +223,7 @@ function animateWindows() { } } -function showWindows() { +export function showWindows() { let ws = getScratchWindows().filter(w => !w.minimized); ws.forEach(Tiling.showWindow); } - -let originalBuildMenu; -function enable() { - originalBuildMenu = WindowMenu.WindowMenu.prototype._buildMenu; - float = Symbol(); - scratchFrame = Symbol(); - WindowMenu.WindowMenu.prototype._buildMenu = - function (window) { - let item; - item = this.addAction(_('Scratch'), () => { - toggle(window); - }); - if (isScratchWindow(window)) - item.setOrnament(PopupMenu.Ornament.CHECK); - - originalBuildMenu.call(this, window); - }; -} - -function disable() { - WindowMenu.WindowMenu.prototype._buildMenu = originalBuildMenu; - originalBuildMenu = null; - float = null; - scratchFrame = null; -} From bc38265b1dd3075fbaebe070f3b431b0b2fd6a21 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 21:59:29 +1000 Subject: [PATCH 15/50] Ported patches.js. --- patches.js | 125 +++++++++++++++++++++++++++-------------------------- scratch.js | 2 +- 2 files changed, 64 insertions(+), 63 deletions(-) diff --git a/patches.js b/patches.js index 1c37ff2a..1a48c343 100644 --- a/patches.js +++ b/patches.js @@ -1,3 +1,16 @@ +import Meta from 'gi://Meta'; +import Gio from 'gi://Gio'; +import Shell from 'gi://Shell'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as Workspace from 'resource:///org/gnome/shell/ui/workspace.js'; +import * as WorkspaceThumbnail from 'resource:///org/gnome/shell/ui/workspaceThumbnail.js'; +import * as WorkspaceAnimation from 'resource:///org/gnome/shell/ui/workspaceAnimation.js'; +import * as WindowManager from 'resource:///org/gnome/shell/ui/windowManager.js'; +import * as Params from 'resource:///org/gnome/shell/misc/params.js'; + +import { Utils, Tiling, Scratch } from './imports.js'; + /** Some of Gnome Shell's default behavior is really sub-optimal when using paperWM. Other features are simply not possible to implement without monkey @@ -5,21 +18,37 @@ around these problems and facilitates new features. */ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Utils = Extension.imports.utils; -const Tiling = Extension.imports.tiling; -const Scratch = Extension.imports.scratch; - -const { Meta, Gio, Shell } = imports.gi; -const Main = imports.ui.main; -const Workspace = imports.ui.workspace; -const WorkspaceThumbnail = imports.ui.workspaceThumbnail; -const WorkspaceAnimation = imports.ui.workspaceAnimation; -const WindowManager = imports.ui.windowManager; -const Params = imports.misc.params; - -function registerOverrideProp(obj, name, override) { +let savedProps, signals; +let gsettings, mutterSettings; +export function enable(extension) { + savedProps = new Map(); + gsettings = extension.getSettings(); + mutterSettings = new Gio.Settings({ schema_id: 'org.gnome.mutter' }); + signals = new Utils.Signals(); + setupSwipeTrackers(); + setupOverrides(); + enableOverrides(); + setupRuntimeDisables(); + setupActions(); +} + +export function disable() { + disableOverrides(); + restoreRuntimeDisables(); + actions.forEach(a => global.stage.add_action(a)); + actions = null; + + signals.destroy(); + signals = null; + + savedProps = null; + swipeTrackers = null; + gsettings = null; + mutterSettings = null; + actions = null; +} + +export function registerOverrideProp(obj, name, override) { if (!obj) return; @@ -35,7 +64,7 @@ function registerOverrideProp(obj, name, override) { }; } -function registerOverridePrototype(obj, name, override) { +export function registerOverridePrototype(obj, name, override) { if (!obj) return; @@ -48,12 +77,12 @@ function registerOverridePrototype(obj, name, override) { registerOverrideProp(obj.prototype, name, override); } -function makeFallback(obj, method, ...args) { +export function makeFallback(obj, method, ...args) { let fallback = getSavedPrototype(obj, method); return fallback.bind(...args); } -function overrideWithFallback(obj, method, body) { +export function overrideWithFallback(obj, method, body) { registerOverridePrototype( obj, method, function(...args) { let fallback = makeFallback(obj, method, this, ...args); @@ -62,7 +91,7 @@ function overrideWithFallback(obj, method, body) { ); } -function getSavedProp(obj, name) { +export function getSavedProp(obj, name) { let props = savedProps.get(obj); if (!props) return undefined; @@ -72,15 +101,15 @@ function getSavedProp(obj, name) { return prop.saved; } -function getSavedPrototype(obj, name) { +export function getSavedPrototype(obj, name) { return getSavedProp(obj.prototype, name); } -function disableOverride(obj, name) { +export function disableOverride(obj, name) { obj[name] = getSavedProp(obj, name); } -function enableOverride(obj, name) { +export function enableOverride(obj, name) { let props = savedProps.get(obj); let override = props[name].override; if (override !== undefined) { @@ -92,7 +121,7 @@ function enableOverride(obj, name) { * Sets up PaperWM overrides (needed for operations). These overrides are registered and restored * on PaperWM disable. */ -function setupOverrides() { +export function setupOverrides() { registerOverridePrototype(WorkspaceAnimation.WorkspaceAnimationController, 'animateSwitch', // WorkspaceAnimation.WorkspaceAnimationController.animateSwitch // Disable the workspace switching animation in Gnome 40+ @@ -203,7 +232,7 @@ function setupOverrides() { /** * Enables any registered overrides. */ -function enableOverrides() { +export function enableOverrides() { for (let [obj, props] of savedProps) { for (let name in props) { enableOverride(obj, name); @@ -211,7 +240,7 @@ function enableOverrides() { } } -function disableOverrides() { +export function disableOverrides() { for (let [obj, props] of savedProps) { for (let name in props) { obj[name] = props[name].saved; @@ -227,7 +256,7 @@ function disableOverrides() { * @param key */ let runtimeDisables = []; -function saveRuntimeDisable(schemaSettings, key, disableValue) { +export function saveRuntimeDisable(schemaSettings, key, disableValue) { try { let origValue = schemaSettings.get_boolean(key); schemaSettings.set_boolean(key, disableValue); @@ -271,7 +300,7 @@ function saveRuntimeDisable(schemaSettings, key, disableValue) { * purposes (we save to PaperWM's setting just in gnome terminates before PaperWM can * restore the original user settings). These settings are then restored on disable(). */ -function setupRuntimeDisables() { +export function setupRuntimeDisables() { saveRuntimeDisable(mutterSettings, 'attach-modal-dialogs', false); saveRuntimeDisable(mutterSettings, 'workspaces-only-on-primary', false); saveRuntimeDisable(mutterSettings, 'edge-tiling', false); @@ -281,7 +310,7 @@ function setupRuntimeDisables() { * Restores the runtime settings that were disabled when * PaperWM was enabled. */ -function restoreRuntimeDisables() { +export function restoreRuntimeDisables() { if (Main.sessionMode.isLocked) { return; } @@ -300,7 +329,7 @@ function restoreRuntimeDisables() { * below are the gnome versions when they were first (or last) seen. */ var swipeTrackers; // exported -function setupSwipeTrackers() { +export function setupSwipeTrackers() { swipeTrackers = [ Main?.overview?._swipeTracker, // gnome 40+ Main?.overview?._overview?._controls?._workspacesDisplay?._swipeTracker, // gnome 40+ @@ -310,7 +339,7 @@ function setupSwipeTrackers() { } let actions; -function setupActions() { +export function setupActions() { /* * Some actions work rather poorly. * In particular the 3-finger hold + tap can randomly activate a minimized @@ -325,37 +354,9 @@ function setupActions() { actions.forEach(a => global.stage.remove_action(a)); } -let savedProps, signals; -let gsettings, mutterSettings; -function enable() { - savedProps = new Map(); - gsettings = ExtensionUtils.getSettings(); - mutterSettings = new Gio.Settings({ schema_id: 'org.gnome.mutter' }); - signals = new Utils.Signals(); - setupSwipeTrackers(); - setupOverrides(); - enableOverrides(); - setupRuntimeDisables(); - setupActions(); -} -function disable() { - disableOverrides(); - restoreRuntimeDisables(); - actions.forEach(a => global.stage.add_action(a)); - actions = null; - - signals.destroy(); - signals = null; - - savedProps = null; - swipeTrackers = null; - gsettings = null; - mutterSettings = null; - actions = null; -} -function sortWindows(a, b) { +export function sortWindows(a, b) { let aw = a.metaWindow; let bw = b.metaWindow; let spaceA = Tiling.spaces.spaceOfWindow(aw); @@ -374,7 +375,7 @@ function sortWindows(a, b) { return ia - ib; } -function computeLayout40(windows, layoutParams) { +export function computeLayout40(windows, layoutParams) { layoutParams = Params.parse(layoutParams, { numRows: 0, }); @@ -440,7 +441,7 @@ function computeLayout40(windows, layoutParams) { }; } -function _checkWorkspaces() { +export function _checkWorkspaces() { let workspaceManager = global.workspace_manager; let i; let emptyWorkspaces = []; @@ -536,7 +537,7 @@ function _checkWorkspaces() { return false; } -function addWindow(window, metaWindow) { +export function addWindow(window, metaWindow) { if (this._windows.has(window)) return; diff --git a/scratch.js b/scratch.js index 98e0e18f..0214e0f4 100644 --- a/scratch.js +++ b/scratch.js @@ -7,8 +7,8 @@ import * as WindowMenu from 'resource:///org/gnome/shell/ui/windowMenu.js'; import { Settings, Utils, Tiling, Topbar } from './imports.js'; import { Easer } from './utils.js'; -let float, scratchFrame; // symbols used for expando properties on metawindow let originalBuildMenu; +let float, scratchFrame; // symbols used for expando properties on metawindow export function enable() { originalBuildMenu = WindowMenu.WindowMenu.prototype._buildMenu; float = Symbol(); From ebbb5b8da85830fce58ba48a2284cdb100a8220c Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 22:04:37 +1000 Subject: [PATCH 16/50] Ported workspace.js. --- virtTiling.js | 57 ++++++++++++++++++++++++--------------------------- workspace.js | 36 ++++++++++++++++---------------- 2 files changed, 45 insertions(+), 48 deletions(-) diff --git a/virtTiling.js b/virtTiling.js index 12d49929..49425268 100644 --- a/virtTiling.js +++ b/virtTiling.js @@ -1,9 +1,6 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Utils = Extension.imports.utils; -const Tiling = Extension.imports.tiling; +import St from 'gi://St'; -const St = imports.gi.St; +import { Utils, Tiling } from './imports.js'; let fitProportionally = Tiling.fitProportionally; let prefs = { @@ -13,7 +10,7 @@ let prefs = { let virtStage = null; -function repl() { +export function repl() { if (virtStage) { virtStage.destroy(); } @@ -31,7 +28,7 @@ function repl() { width: monitorWidth * 3, }); - let monitorStyle = `background-color: blue;` + let monitorStyle = `background-color: blue;`; let monitor = new St.Widget({ name: "monitor0", style: monitorStyle, @@ -53,10 +50,10 @@ function repl() { y: panel.height, width: monitor.width, height: monitor.height - panel.height, - } + }; - let tilingStyle = `background-color: rgba(190, 190, 0, 0.3);` - let tilingContainer = new St.Widget({name: "tiling", style: tilingStyle}); + let tilingStyle = `background-color: rgba(190, 190, 0, 0.3);`; + let tilingContainer = new St.Widget({ name: "tiling", style: tilingStyle }); global.stage.add_actor(virtStage); virtStage.x = 3000; @@ -79,9 +76,9 @@ function repl() { tilingContainer.x = space_.targetX * scale; } - sync() + sync(); - Utils.printActorTree(virtStage, Utils.mkFmt({nameOnly: true})); + Utils.printActorTree(virtStage, Utils.mkFmt({ nameOnly: true })); movecolumntoviewportposition(tilingContainer, monitor, columns[1][0], 30); @@ -95,7 +92,7 @@ function repl() { w_m: window position (relative to monitor) w_t: window position (relative to tiling) */ -function t_s(m_s, w_m, w_t) { +export function t_s(m_s, w_m, w_t) { return w_m - w_t + m_s; } @@ -103,11 +100,11 @@ function t_s(m_s, w_m, w_t) { Calculates the tiling position such that column `k` is positioned at `x` relative to the viewport (or workArea?) */ -function movecolumntoviewportposition(tilingActor, viewport, window, x) { +export function movecolumntoviewportposition(tilingActor, viewport, window, x) { tilingActor.x = t_s(viewport.x, x, window.x); } -function renderAndView(container, columns) { +export function renderAndView(container, columns) { for (let child of container.get_children()) { child.destroy(); } @@ -115,7 +112,7 @@ function renderAndView(container, columns) { render(columns, container); } -function fromSpace(space, scale = 1) { +export function fromSpace(space, scale = 1) { return space.map( col => col.map( metaWindow => { @@ -126,11 +123,11 @@ function fromSpace(space, scale = 1) { }; } ) - ) + ); } /** Render a dummy view of the windows */ -function render(columns, tiling) { +export function render(columns, tiling) { const windowStyle = `border: black solid 1px; background-color: red`; function createWindowActor(window) { @@ -151,7 +148,7 @@ function render(columns, tiling) { } } -function allocateDefault(column, availableHeight, preAllocatedWindow) { +export function allocateDefault(column, availableHeight, preAllocatedWindow) { if (column.length === 1) { return [availableHeight]; } else { @@ -159,9 +156,9 @@ function allocateDefault(column, availableHeight, preAllocatedWindow) { const gap = prefs.window_gap; const minHeight = 15; - function heightOf(window) { + const heightOf = window => { return window.height; - } + }; const k = preAllocatedWindow && column.indexOf(preAllocatedWindow); const selectedHeight = preAllocatedWindow && heightOf(preAllocatedWindow); @@ -195,12 +192,12 @@ function allocateDefault(column, availableHeight, preAllocatedWindow) { } } -function allocateEqualHeight(column, available) { +export function allocateEqualHeight(column, available) { available -= (column.length - 1) * prefs.window_gap; return column.map(_ => Math.floor(available / column.length)); } -function layoutGrabColumn(column, x, y0, targetWidth, availableHeight, grabWindow) { +export function layoutGrabColumn(column, x, y0, targetWidth, availableHeight, grabWindow) { function mosh(windows, height, y0) { let targetHeights = fitProportionally( windows.map(mw => mw.rect.height), @@ -212,7 +209,7 @@ function layoutGrabColumn(column, x, y0, targetWidth, availableHeight, grabWindo const k = column.indexOf(grabWindow); if (k < 0) { - throw new Error("Anchor doesn't exist in column " + grabWindow.title); + throw new Error(`Anchor doesn't exist in column ${grabWindow.title}`); } const gap = prefs.window_gap; @@ -224,13 +221,13 @@ function layoutGrabColumn(column, x, y0, targetWidth, availableHeight, grabWindo const H2 = availableHeight - (yGrabRel + f.height - y0) - gap - (column.length - k - 2) * gap; k > 0 && mosh(column.slice(0, k), H1, y0); let y = mosh(column.slice(k, k + 1), f.height, yGrabRel); - k+1 < column.length && mosh(column.slice(k + 1), H2, y); + k + 1 < column.length && mosh(column.slice(k + 1), H2, y); return targetWidth; } -function layoutColumnSimple(windows, x, y0, targetWidth, targetHeights, time) { +export function layoutColumnSimple(windows, x, y0, targetWidth, targetHeights, time) { let y = y0; for (let i = 0; i < windows.length; i++) { @@ -251,19 +248,19 @@ function layoutColumnSimple(windows, x, y0, targetWidth, targetHeights, time) { /** Mutates columns */ -function layout(columns, workArea, prefs, options = {}) { +export function layout(columns, workArea, prefs, options = {}) { let gap = prefs.window_gap; let availableHeight = workArea.height; - let {inGrab, selectedWindow} = options; + let { inGrab, selectedWindow } = options; let selectedIndex = -1; if (selectedWindow) { selectedIndex = columns.findIndex(col => col.includes(selectedWindow)); } - let y0 = workArea.y - let x = 0 + let y0 = workArea.y; + let x = 0; for (let i = 0; i < columns.length; i++) { let column = columns[i]; diff --git a/workspace.js b/workspace.js index c59a6029..76346c6a 100644 --- a/workspace.js +++ b/workspace.js @@ -1,7 +1,7 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Lib = Extension.imports.lib; -const { Gio, GLib } = imports.gi; +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; + +import Lib from './imports.js'; /** * Workspace related utility functions used by other modules. @@ -11,11 +11,11 @@ const WORKSPACE_KEY = 'org.gnome.shell.extensions.paperwm.workspace'; let workspaceSettingsCache; let schemaSource, workspaceList; -function enable() { +export function enable(extension) { workspaceSettingsCache = {}; schemaSource = Gio.SettingsSchemaSource.new_from_directory( - GLib.build_filenamev([Extension.path, "schemas"]), + GLib.build_filenamev([extension.path, "schemas"]), Gio.SettingsSchemaSource.get_default(), false ); @@ -25,17 +25,17 @@ function enable() { }); } -function disable() { +export function disable() { workspaceSettingsCache = null; schemaSource = null; workspaceList = null; } -function getSchemaSource() { +export function getSchemaSource() { return schemaSource; } -function getWorkspaceName(settings, index) { +export function getWorkspaceName(settings, index) { let name = settings.get_string('name') ?? `Workspace ${index + 1}`; if (!name || name === '') { name = `Workspace ${index + 1}`; @@ -43,18 +43,18 @@ function getWorkspaceName(settings, index) { return name; } -function getWorkspaceList() { +export function getWorkspaceList() { return workspaceList; } /** * Returns list of ordered workspace UUIDs. */ -function getListUUID() { +export function getListUUID() { return getWorkspaceList().get_strv('list'); } -function getWorkspaceSettings(index) { +export function getWorkspaceSettings(index) { let list = getListUUID(); for (let uuid of list) { let settings = getWorkspaceSettingsByUUID(uuid); @@ -65,7 +65,7 @@ function getWorkspaceSettings(index) { return getNewWorkspaceSettings(index); } -function getNewWorkspaceSettings(index) { +export function getNewWorkspaceSettings(index) { let uuid = GLib.uuid_string_random(); let settings = getWorkspaceSettingsByUUID(uuid); let list = getListUUID(); @@ -75,7 +75,7 @@ function getNewWorkspaceSettings(index) { return [uuid, settings]; } -function getWorkspaceSettingsByUUID(uuid) { +export function getWorkspaceSettingsByUUID(uuid) { if (!workspaceSettingsCache[uuid]) { let settings = new Gio.Settings({ settings_schema: getSchemaSource().lookup(WORKSPACE_KEY, true), @@ -87,7 +87,7 @@ function getWorkspaceSettingsByUUID(uuid) { } /** Returns [[uuid, settings, name], ...] (Only used for debugging/development atm.) */ -function findWorkspaceSettingsByName(regex) { +export function findWorkspaceSettingsByName(regex) { let list = getListUUID(); let settings = list.map(getWorkspaceSettingsByUUID); return Lib.zip(list, settings, settings.map(s => s.get_string('name'))) @@ -95,7 +95,7 @@ function findWorkspaceSettingsByName(regex) { } /** Only used for debugging/development atm. */ -function deleteWorkspaceSettingsByName(regex, dryrun = true) { +export function deleteWorkspaceSettingsByName(regex, dryrun = true) { let out = ""; function rprint(...args) { console.debug(...args); out += `${args.join(" ")}\n`; } let n = global.workspace_manager.get_n_workspaces(); @@ -114,7 +114,7 @@ function deleteWorkspaceSettingsByName(regex, dryrun = true) { } /** Only used for debugging/development atm. */ -function deleteWorkspaceSettings(uuid) { +export function deleteWorkspaceSettings(uuid) { // NB! Does not check if the settings is currently in use. Does not reindex subsequent settings. let list = getListUUID(); let i = list.indexOf(uuid); @@ -129,7 +129,7 @@ function deleteWorkspaceSettings(uuid) { } // Useful for debugging -function printWorkspaceSettings() { +export function printWorkspaceSettings() { let list = getListUUID(); let settings = list.map(getWorkspaceSettingsByUUID); let zipped = Lib.zip(list, settings); From 2ff0c71fdd2b637be088550141f64aa7b8de67b1 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 22:22:00 +1000 Subject: [PATCH 17/50] Ported topbar.js. --- topbar.js | 264 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 135 insertions(+), 129 deletions(-) diff --git a/topbar.js b/topbar.js index c1e771c2..0cc6ca5b 100644 --- a/topbar.js +++ b/topbar.js @@ -1,28 +1,29 @@ -/* - Functionality related to the top bar, often called the statusbar. - */ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const ExtensionModule = Extension.imports.extension; -const Settings = Extension.imports.settings; -const Utils = Extension.imports.utils; -const Tiling = Extension.imports.tiling; -const Navigator = Extension.imports.navigator; -const Scratch = Extension.imports.scratch; -const Easer = Extension.imports.utils.easer; - -const { Clutter, St, Graphene, GLib, Meta, Gio, GObject } = imports.gi; -const { panelMenu, popupMenu } = imports.ui; -const Main = imports.ui.main; -const Path = Extension.path; +import { Settings, Utils, Tiling, Navigator, Scratch } from './imports.js'; +import { Easer } from './utils.js'; + +import Clutter from 'gi://Clutter'; +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import Graphene from 'gi://Graphene'; +import Meta from 'gi://Meta'; +import St from 'gi://St'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as panelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js'; +import * as popupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; const workspaceManager = global.workspace_manager; const display = global.display; -var panelBox = Main.layoutManager.panelBox; // exported +/* + Functionality related to the top bar, often called the statusbar. + */ + +export let panelBox = Main.layoutManager.panelBox; // From https://developer.gnome.org/hig-book/unstable/design-color.html.en -let colors = [ +const colors = [ '#9DB8D2', '#7590AE', '#4B6983', '#314E6C', '#EAE8E3', '#BAB5AB', '#807D74', '#565248', '#C5D2C8', '#83A67F', '#5D7555', '#445632', @@ -33,7 +34,100 @@ let colors = [ '#46A046', '#267726', '#ffffff', '#000000', ]; -function createButton(icon_name, accessible_name) { +export let menu, focusButton; +let path, openPrefs, orginalActivitiesText, screenSignals, signals, gsettings; +export function enable (extension) { + path = extension.path; + openPrefs = () => extension.openPreferences(); + gsettings = extension.getSettings(); + + let label = Main.panel.statusArea.activities.first_child; + orginalActivitiesText = label.text; + screenSignals = []; + signals = new Utils.Signals(); + + Main.panel.statusArea.activities.hide(); + + menu = new WorkspaceMenu(); + focusButton = new FocusButton(); + + Main.panel.addToStatusArea('WorkspaceMenu', menu, 0, 'left'); + Main.panel.addToStatusArea('FocusButton', focusButton, 1, 'left'); + + Tiling.spaces.forEach(s => { + s.workspaceLabel.clutter_text.set_font_description(menu.label.clutter_text.font_description); + }); + fixWorkspaceIndicator(); + fixFocusModeIcon(); + fixStyle(); + + screenSignals.push( + workspaceManager.connect_after('workspace-switched', + (workspaceManager, from, to) => updateWorkspaceIndicator(to))); + + signals.connect(Main.overview, 'showing', fixTopBar); + signals.connect(Main.overview, 'hidden', () => { + if (Tiling.spaces.selectedSpace.showTopBar) + return; + fixTopBar(); + }); + + signals.connect(gsettings, 'changed::disable-topbar-styling', (settings, key) => { + const status = Settings.prefs.disable_topbar_styling ? 'DISABLED' : 'ENABLED'; + Main.notify( + `PaperWM: TopBar styling has been ${status}`, + `A restart of Gnome is required! (e.g. logout then login again)`); + }); + + signals.connect(gsettings, 'changed::show-window-position-bar', (settings, key) => { + const spaces = Tiling.spaces; + spaces.setSpaceTopbarElementsVisible(); + spaces.forEach(s => s.layout(false)); + spaces.showWindowPositionBarChanged(); + }); + + signals.connect(gsettings, 'changed::show-workspace-indicator', (settings, key) => { + fixWorkspaceIndicator(); + }); + + signals.connect(gsettings, 'changed::show-focus-mode-icon', (settings, key) => { + fixFocusModeIcon(); + }); + + signals.connect(panelBox, 'show', () => { + fixTopBar(); + }); + signals.connect(panelBox, 'hide', () => { + fixTopBar(); + }); + /** + * Set clear-style when hiding overview. + */ + signals.connect(Main.overview, 'hiding', () => { + fixStyle(); + }); +} + +export function disable() { + signals.destroy(); + signals = null; + focusButton.destroy(); + focusButton = null; + menu.destroy(); + menu = null; + Main.panel.statusArea.activities.show(); + // remove PaperWM style classes names for Main.panel + removeStyles(); + + screenSignals.forEach(id => workspaceManager.disconnect(id)); + screenSignals = []; + panelBox.scale_y = 1; + path = null; + openPrefs = null; + gsettings = null; +} + +export function createButton(icon_name, accessible_name) { return new St.Button({ reactive: true, can_focus: true, @@ -44,7 +138,7 @@ function createButton(icon_name, accessible_name) { }); } -function popupMenuEntryHelper(text) { +export function popupMenuEntryHelper(text) { this.label = new St.Entry({ text, // While not a search entry, this looks much better @@ -81,7 +175,7 @@ function popupMenuEntryHelper(text) { } // registerClass, breaking our somewhat lame registerClass polyfill. -var PopupMenuEntry = GObject.registerClass( +export const PopupMenuEntry = GObject.registerClass( class PopupMenuEntry extends popupMenu.PopupBaseMenuItem { _init(text) { super._init({ @@ -161,7 +255,7 @@ class ColorEntry { /** * FocusMode icon class. */ -var FocusIcon = GObject.registerClass( +export const FocusIcon = GObject.registerClass( class FocusIcon extends St.Icon { _init(properties = {}, tooltip_parent, tooltip_x_point = 0) { super._init(properties); @@ -172,8 +266,8 @@ var FocusIcon = GObject.registerClass( this.tooltip_x_point = tooltip_x_point; // read in focus icons from resources folder - this.gIconDefault = Gio.icon_new_for_string(`${Path}/resources/focus-mode-default-symbolic.svg`); - this.gIconCenter = Gio.icon_new_for_string(`${Path}/resources/focus-mode-center-symbolic.svg`); + this.gIconDefault = Gio.icon_new_for_string(`${path}/resources/focus-mode-default-symbolic.svg`); + this.gIconCenter = Gio.icon_new_for_string(`${path}/resources/focus-mode-center-symbolic.svg`); this._initToolTip(); this.setMode(); @@ -266,7 +360,7 @@ Current mode: ${mode}`); } ); -var FocusButton = GObject.registerClass( +export const FocusButton = GObject.registerClass( class FocusButton extends panelMenu.Button { _init() { super._init(0.0, 'FocusMode'); @@ -292,7 +386,7 @@ var FocusButton = GObject.registerClass( } _onClicked(actor, event) { - if (Tiling.inPreview != Tiling.PreviewMode.NONE || Main.overview.visible) { + if (Tiling.inPreview !== Tiling.PreviewMode.NONE || Main.overview.visible) { return Clutter.EVENT_PROPAGATE; } @@ -364,7 +458,7 @@ var WorkspaceMenu = GObject.registerClass( let wi = workspaceManager.get_active_workspace_index(); let temp_file = Gio.File.new_for_path(GLib.get_tmp_dir()).get_child('paperwm.workspace'); temp_file.replace_contents(wi.toString(), null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null); - ExtensionUtils.openPrefs(); + openPrefs(); }); // this.iconBox = new St.BoxLayout(); @@ -398,8 +492,8 @@ var WorkspaceMenu = GObject.registerClass( let type = event.type(); - if (type == Clutter.EventType.TOUCH_END || - type == Clutter.EventType.BUTTON_RELEASE) { + if (type === Clutter.EventType.TOUCH_END || + type === Clutter.EventType.BUTTON_RELEASE) { if (Navigator.navigating) { Navigator.getNavigator().finish(); } else { @@ -584,99 +678,11 @@ var WorkspaceMenu = GObject.registerClass( } }); -var menu, focusButton; // exported -let orginalActivitiesText, screenSignals, signals, gsettings; -function enable () { - gsettings = ExtensionUtils.getSettings(); - let label = Main.panel.statusArea.activities.first_child; - orginalActivitiesText = label.text; - screenSignals = []; - signals = new Utils.Signals(); - - Main.panel.statusArea.activities.hide(); - - menu = new WorkspaceMenu(); - focusButton = new FocusButton(); - - Main.panel.addToStatusArea('WorkspaceMenu', menu, 0, 'left'); - Main.panel.addToStatusArea('FocusButton', focusButton, 1, 'left'); - - Tiling.spaces.forEach(s => { - s.workspaceLabel.clutter_text.set_font_description(menu.label.clutter_text.font_description); - }); - fixWorkspaceIndicator(); - fixFocusModeIcon(); - fixStyle(); - - screenSignals.push( - workspaceManager.connect_after('workspace-switched', - (workspaceManager, from, to) => updateWorkspaceIndicator(to))); - - signals.connect(Main.overview, 'showing', fixTopBar); - signals.connect(Main.overview, 'hidden', () => { - if (Tiling.spaces.selectedSpace.showTopBar) - return; - fixTopBar(); - }); - - signals.connect(gsettings, 'changed::disable-topbar-styling', (settings, key) => { - const status = Settings.prefs.disable_topbar_styling ? 'DISABLED' : 'ENABLED'; - ExtensionModule.notify( - `PaperWM: TopBar styling has been ${status}`, - `A restart of Gnome is required! (e.g. logout then login again)`); - }); - - signals.connect(gsettings, 'changed::show-window-position-bar', (settings, key) => { - const spaces = Tiling.spaces; - spaces.setSpaceTopbarElementsVisible(); - spaces.forEach(s => s.layout(false)); - spaces.showWindowPositionBarChanged(); - }); - - signals.connect(gsettings, 'changed::show-workspace-indicator', (settings, key) => { - fixWorkspaceIndicator(); - }); - - signals.connect(gsettings, 'changed::show-focus-mode-icon', (settings, key) => { - fixFocusModeIcon(); - }); - - signals.connect(panelBox, 'show', () => { - fixTopBar(); - }); - signals.connect(panelBox, 'hide', () => { - fixTopBar(); - }); - /** - * Set clear-style when hiding overview. - */ - signals.connect(Main.overview, 'hiding', () => { - fixStyle(); - }); -} - -function disable() { - signals.destroy(); - signals = null; - focusButton.destroy(); - focusButton = null; - menu.destroy(); - menu = null; - Main.panel.statusArea.activities.show(); - // remove PaperWM style classes names for Main.panel - removeStyles(); - - screenSignals.forEach(id => workspaceManager.disconnect(id)); - screenSignals = []; - panelBox.scale_y = 1; - gsettings = null; -} - -function panelMonitor() { +export function panelMonitor() { return Main.layoutManager.primaryMonitor; } -function setNoBackgroundStyle() { +export function setNoBackgroundStyle() { if (Settings.prefs.disable_topbar_styling) { return; } @@ -684,7 +690,7 @@ function setNoBackgroundStyle() { Main.panel.add_style_class_name('topbar-no-background'); } -function setTransparentStyle() { +export function setTransparentStyle() { if (Settings.prefs.disable_topbar_styling) { return; } @@ -692,7 +698,7 @@ function setTransparentStyle() { Main.panel.add_style_class_name('topbar-transparent-background'); } -function removeStyles() { +export function removeStyles() { ['topbar-no-background', 'topbar-transparent-background'].forEach(s => { Main.panel.remove_style_class_name(s); }); @@ -701,11 +707,11 @@ function removeStyles() { /** * Applies correct style based on whether we use the windowPositionBar or not. */ -function fixStyle() { +export function fixStyle() { Settings.prefs.show_window_position_bar ? setNoBackgroundStyle() : setTransparentStyle(); } -function fixTopBar() { +export function fixTopBar() { let space = Tiling?.spaces?.monitors?.get(panelMonitor()) ?? false; if (!space) return; @@ -731,12 +737,12 @@ function fixTopBar() { } } -function fixWorkspaceIndicator() { +export function fixWorkspaceIndicator() { Settings.prefs.show_workspace_indicator ? menu.show() : menu.hide(); Tiling.spaces.forEach(s => s.showWorkspaceIndicator()); } -function fixFocusModeIcon() { +export function fixFocusModeIcon() { Settings.prefs.show_focus_mode_icon ? focusButton.show() : focusButton.hide(); Tiling.spaces.forEach(s => s.showFocusModeIcon()); } @@ -745,7 +751,7 @@ function fixFocusModeIcon() { Override the activities label with the workspace name. let workspaceIndex = 0 */ -function updateWorkspaceIndicator(index) { +export function updateWorkspaceIndicator(index) { let spaces = Tiling.spaces; let space = spaces?.spaceOf(workspaceManager.get_workspace_by_index(index)); if (space && space.monitor === panelMonitor()) { @@ -759,11 +765,11 @@ function updateWorkspaceIndicator(index) { /** * Refreshes topbar workspace indicator. */ -function refreshWorkspaceIndicator() { +export function refreshWorkspaceIndicator() { let panelSpace = Tiling.spaces.monitors.get(panelMonitor()); updateWorkspaceIndicator(panelSpace.index); } -function setWorkspaceName (name) { +export function setWorkspaceName (name) { menu && menu.setName(name); } From 6b46b84def6b6594ef2756e1988531e1b2035b6e Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 22:39:01 +1000 Subject: [PATCH 18/50] Ported stackoverlay.js --- extension.js | 12 ++++++++-- stackoverlay.js | 58 ++++++++++++++++++++++++------------------------- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/extension.js b/extension.js index efcf735f..b68486a1 100644 --- a/extension.js +++ b/extension.js @@ -62,14 +62,22 @@ export default class PaperWM extends Extension { this.enableUserStylesheet(); // run enable method (with extension argument on all modules) - this.modules.forEach(m => m.enable(this)); + this.modules.forEach(m => { + if (m['enable']) { + m.enable(this); + } + }); } disable() { console.log('#PaperWM disabled'); this.prepareForDisable(); this.run('disable', true); - [...this.modules].reverse().forEach(m => m.disable()); + [...this.modules].reverse().forEach(m => { + if (m['disable']) { + m.disable(); + } + }); this.disableUserStylesheet(); } diff --git a/stackoverlay.js b/stackoverlay.js index 29f13a33..84d261af 100644 --- a/stackoverlay.js +++ b/stackoverlay.js @@ -1,17 +1,14 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Settings = Extension.imports.settings; -const Utils = Extension.imports.utils; -const Grab = Extension.imports.grab; -const Tiling = Extension.imports.tiling; -const Navigator = Extension.imports.navigator; +import Clutter from 'gi://Clutter'; +import GLib from 'gi://GLib'; +import Meta from 'gi://Meta'; +import Shell from 'gi://Shell'; +import St from 'gi://St'; -const { Clutter, Shell, Meta, St } = imports.gi; -const Main = imports.ui.main; -const Mainloop = imports.mainloop; -const Layout = imports.ui.layout; -const PointerWatcher = imports.ui.pointerWatcher; +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as Layout from 'resource:///org/gnome/shell/ui/layout.js'; +import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.js'; +import { Settings, Utils, Tiling, Navigator } from './imports.js'; /* The stack overlay decorates the top stacked window with its icon and @@ -47,8 +44,12 @@ const PointerWatcher = imports.ui.pointerWatcher; restack loops) */ -let pointerWatch; -function disable() { +let gsettings, pointerWatch; +export function enable(extension) { + gsettings = extension.getSettings(); +} + +export function disable() { disableMultimonitorDragDropSupport(); } @@ -56,7 +57,7 @@ function disable() { * Checks for multiple monitors and if so, then enables multimonitor * drag/drop support in PaperWM. */ -function multimonitorDragDropSupport() { +export function multimonitorDragDropSupport() { // if only one monitor, return if (Tiling.spaces.monitors?.size > 1) { enableMultimonitorDragDropSupport(); @@ -66,7 +67,7 @@ function multimonitorDragDropSupport() { } } -function enableMultimonitorDragDropSupport() { +export function enableMultimonitorDragDropSupport() { pointerWatch = PointerWatcher.getPointerWatcher().addWatch(100, () => { Tiling.spaces?.clickOverlays?.forEach(c => { @@ -76,13 +77,13 @@ function enableMultimonitorDragDropSupport() { console.debug('paperwm multimonitor drag/drop support is ENABLED'); } -function disableMultimonitorDragDropSupport() { +export function disableMultimonitorDragDropSupport() { pointerWatch?.remove(); pointerWatch = null; console.debug('paperwm multimonitor drag/drop support is DISABLED'); } -function createAppIcon(metaWindow, size) { +export function createAppIcon(metaWindow, size) { let tracker = Shell.WindowTracker.get_default(); let app = tracker.get_window_app(metaWindow); let appIcon = app ? app.create_icon_texture(size) @@ -96,7 +97,7 @@ function createAppIcon(metaWindow, size) { return appIcon; } -var ClickOverlay = class ClickOverlay { +export class ClickOverlay { constructor(monitor, onlyOnPrimary) { this.monitor = monitor; this.onlyOnPrimary = onlyOnPrimary; @@ -253,9 +254,9 @@ var ClickOverlay = class ClickOverlay { Main.layoutManager.untrackChrome(this.enterMonitor); this.enterMonitor.destroy(); } -}; +} -var StackOverlay = class StackOverlay { +export class StackOverlay { constructor(direction, monitor) { this._direction = direction; @@ -281,7 +282,7 @@ var StackOverlay = class StackOverlay { Main.activateWindow(this.target); // remove/cleanup the previous preview this.removePreview(); - this.triggerPreviewTimeout = Mainloop.timeout_add(200, () => { + this.triggerPreviewTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, () => { // if pointer is still at edge (within 2px), trigger preview let [x, y, mask] = global.get_pointer(); if (x <= 2 || x >= this.monitor.width - 2) { @@ -292,7 +293,6 @@ var StackOverlay = class StackOverlay { }); }); - let gsettings = ExtensionUtils.getSettings(); this.signals.connect(overlay, 'enter-event', this.triggerPreview.bind(this)); this.signals.connect(overlay, 'leave-event', this.removePreview.bind(this)); this.signals.connect(gsettings, 'changed::pressure-barrier', @@ -312,7 +312,7 @@ var StackOverlay = class StackOverlay { return; if (!this.target) return; - this._previewId = Mainloop.timeout_add(100, () => { + this._previewId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, () => { delete this._previewId; this.removePreview(); this.showPreview(); @@ -332,11 +332,11 @@ var StackOverlay = class StackOverlay { removePreview() { if ("_previewId" in this) { - Mainloop.source_remove(this._previewId); + GLib.source_remove(this._previewId); delete this._previewId; } if ("_removeId" in this) { - Mainloop.source_remove(this._removeId); + GLib.source_remove(this._removeId); delete this._removeId; } @@ -412,9 +412,9 @@ var StackOverlay = class StackOverlay { this.pressureBarrier._reset(); this.pressureBarrier._isTriggered = false; if (this._removeBarrierTimeoutId) { - Mainloop.source_remove(this._removeBarrierTimeoutId); + GLib.source_remove(this._removeBarrierTimeoutId); } - this._removeBarrierTimeoutId = Mainloop.timeout_add(100, () => { + this._removeBarrierTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, () => { this.removeBarrier(); this._removeBarrierTimeoutId = null; return false; @@ -534,4 +534,4 @@ var StackOverlay = class StackOverlay { getWorkArea() { return Main.layoutManager.getWorkAreaForMonitor(this.monitor.index); } -}; +} From 6bfd7edfa86fdcab9d1904c787444258789ad506 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 16 Sep 2023 22:54:32 +1000 Subject: [PATCH 19/50] First attempt at porting tiling.js to ESM. --- navigator.js | 2 +- tiling.js | 500 +++++++++++++++++++++++++-------------------------- 2 files changed, 248 insertions(+), 254 deletions(-) diff --git a/navigator.js b/navigator.js index 079c10f1..81a25f3f 100644 --- a/navigator.js +++ b/navigator.js @@ -13,7 +13,7 @@ import { Utils, Tiling, Keybindings, TopBar, Scratch, Minimap } from './imports. `SwitcherPopup.SwitcherPopup` when we really should just take full control. */ -const { Signals } = imports; +const { signals: Signals } = imports; const display = global.display; export let navigating; // exported diff --git a/tiling.js b/tiling.js index fefa6ea6..5aa82a29 100644 --- a/tiling.js +++ b/tiling.js @@ -1,45 +1,39 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Settings = Extension.imports.settings; -const Utils = Extension.imports.utils; -const Lib = Extension.imports.lib; -const Workspace = Extension.imports.workspace; -const Gestures = Extension.imports.gestures; -const Navigator = Extension.imports.navigator; -const Grab = Extension.imports.grab; -const TopBar = Extension.imports.topbar; -const Scratch = Extension.imports.scratch; -const Easer = Extension.imports.utils.easer; -const StackOverlay = Extension.imports.stackoverlay; -const ClickOverlay = StackOverlay.ClickOverlay; - -const { Clutter, St, Graphene, Meta, Gio, GDesktopEnums } = imports.gi; -const Main = imports.ui.main; -const Mainloop = imports.mainloop; -const Signals = imports.signals; -const debug = Extension.imports.utils.debug; +import Clutter from 'gi://Clutter'; +import GDesktopEnums from 'gi://GDesktopEnums'; +import GLib from 'gi://GLib'; +import Gio from 'gi://Gio'; +import Graphene from 'gi://Graphene'; +import Meta from 'gi://Meta'; +import St from 'gi://St'; +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; + +import { Settings, Utils, Lib, Workspace, Gestures, Navigator, Grab, Topbar, Scratch, Stackoverlay } from './imports.js'; +import { debug, Easer } from './utils.js'; +import { ClickOverlay } from './stackoverlay'; + +const { signals: Signals } = imports; const workspaceManager = global.workspace_manager; const display = global.display; /** @type {Spaces} */ -var spaces; // export +export let spaces; let borderWidth = 8; // Mutter prevints windows from being placed further off the screen than 75 pixels. -var stack_margin = 75; // export +export const stack_margin = 75; // Some features use this to determine if to sizes is considered equal. ie. `abs(w1 - w2) < sizeSlack` let sizeSlack = 30; -var PreviewMode = { NONE: 0, STACK: 1, SEQUENTIAL: 2 }; // export -var inPreview = PreviewMode.NONE; // export +export const PreviewMode = { NONE: 0, STACK: 1, SEQUENTIAL: 2 }; // export +export let inPreview = PreviewMode.NONE; // export // DEFAULT mode is normal/original PaperWM window focus behaviour -var FocusModes = { DEFAULT: 0, CENTER: 1 }; // export +export const FocusModes = { DEFAULT: 0, CENTER: 1 }; // export -var CycleWindowSizesDirection = { FORWARD: 0, BACKWARDS: 1 }; +export const CycleWindowSizesDirection = { FORWARD: 0, BACKWARDS: 1 }; /** Scrolled and tiled per monitor workspace. @@ -87,7 +81,127 @@ var CycleWindowSizesDirection = { FORWARD: 0, BACKWARDS: 1 }; To transform a stage point to space coordinates: `space.actor.transform_stage_point(aX, aY)` */ -var Space = class Space extends Array { + +let signals, backgroundGroup, grabSignals; +let gsettings, backgroundSettings, interfaceSettings; +let displayConfig; +let saveState; +let startupTimeoutId, timerId; +var inGrab; // exported +export function enable(extension) { + inGrab = false; + + displayConfig = new Utils.DisplayConfig(); + saveState = saveState ?? new SaveState(); + + gsettings = extension.getSettings(); + backgroundSettings = new Gio.Settings({ + schema_id: 'org.gnome.desktop.background', + }); + interfaceSettings = new Gio.Settings({ + schema_id: "org.gnome.desktop.interface", + }); + + signals = new Utils.Signals(); + grabSignals = new Utils.Signals(); + + let setVerticalMargin = () => { + let vMargin = gsettings.get_int('vertical-margin'); + let gap = gsettings.get_int('window-gap'); + Settings.prefs.vertical_margin = Math.max(Math.round(gap / 2), vMargin); + }; + setVerticalMargin(); + + // setup actions on gap changes + let onWindowGapChanged = () => { + setVerticalMargin(); + Utils.timeout_remove(timerId); + timerId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, () => { + spaces.mru().forEach(space => { + space.layout(); + }); + timerId = null; + return false; // on return false destroys timeout + }); + }; + gsettings.connect('changed::vertical-margin', onWindowGapChanged); + gsettings.connect('changed::vertical-margin-bottom', onWindowGapChanged); + gsettings.connect('changed::window-gap', onWindowGapChanged); + + backgroundGroup = Main.layoutManager._backgroundGroup; + + spaces = new Spaces(); + let initWorkspaces = () => { + try { + spaces.init(); + } catch (e) { + console.error(new Error('#paperwm startup failed')); + } + + // Fix the stack overlay + spaces.mru().reverse().forEach(s => { + // if s.selectedWindow exists and is in view, then use option moveto: false + if (s.selectedWindow) { + let options = s.isFullyVisible(s.selectedWindow) ? { moveto: false } : { force: true }; + ensureViewport(s.selectedWindow, s, options); + } + s.monitor.clickOverlay.show(); + }); + Topbar.fixTopBar(); + + // on idle update space topbar elements and name + Utils.later_add(Meta.LaterType.IDLE, () => { + spaces.forEach(s => { + s.setSpaceTopbarElementsVisible(); + s.updateName(); + }); + }); + }; + + if (Main.layoutManager._startingUp) { + // Defer workspace initialization until existing windows are accessible. + // Otherwise we're unable to restore the tiling-order. (when restarting + // gnome-shell) + signals.connectOneShot(Main.layoutManager, 'startup-complete', + () => displayConfig.upgradeGnomeMonitors(initWorkspaces)); + } else { + /** + * Upgrade gnome monitor info objects by add "connector" information, and + * when done (async) callback to initworkspaces. + */ + // NOTE: this should happen after Patches.enable() have run, so we do + // it in a timeout + startupTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 0, () => { + displayConfig.upgradeGnomeMonitors(initWorkspaces); + startupTimeoutId = null; + return false; // on return false destroys timeout + }); + } +} + +export function disable () { + Utils.timeout_remove(startupTimeoutId); + startupTimeoutId = null; + Utils.timeout_remove(timerId); + timerId = null; + + grabSignals.destroy(); + grabSignals = null; + signals.destroy(); + signals = null; + + saveState.prepare(); + displayConfig.downgradeGnomeMonitors(); + displayConfig = null; + spaces.destroy(); + inGrab = null; + gsettings = null; + backgroundGroup = null; + backgroundSettings = null; + interfaceSettings = null; +} + +export class Space extends Array { /** @type {import('@gi-types/clutter10').Actor} */ actor; @@ -106,7 +220,7 @@ var Space = class Space extends Array { // default focusMode (can be overriden by saved user pref in Space.init method) this.focusMode = FocusModes.DEFAULT; - this.focusModeIcon = new TopBar.FocusIcon({ + this.focusModeIcon = new Topbar.FocusIcon({ name: 'panel', style_class: 'space-focus-mode-icon', }) @@ -211,7 +325,7 @@ var Space = class Space extends Array { this._populated = true; // init window position bar and space topbar elements - this.windowPositionBarBackdrop.height = TopBar.panelBox.height; + this.windowPositionBarBackdrop.height = Topbar.panelBox.height; this.setSpaceTopbarElementsVisible(); // apply default focus mode @@ -241,10 +355,9 @@ var Space = class Space extends Array { setFocusMode(getDefaultFocusMode(), this); }); - const settings = ExtensionUtils.getSettings(); this.signals.connect(interfaceSettings, "changed::color-scheme", this.updateBackground.bind(this)); - this.signals.connect(settings, 'changed::default-background', this.updateBackground.bind(this)); - this.signals.connect(settings, 'changed::use-default-background', this.updateBackground.bind(this)); + this.signals.connect(gsettings, 'changed::default-background', this.updateBackground.bind(this)); + this.signals.connect(gsettings, 'changed::use-default-background', this.updateBackground.bind(this)); this.signals.connect(backgroundSettings, 'changed::picture-uri', this.updateBackground.bind(this)); this.signals.connect(backgroundSettings, "changed::picture-uri-dark", this.updateBackground.bind(this)); } @@ -369,10 +482,10 @@ var Space = class Space extends Array { if (prop.value <= 0) { console.warn("invalid preferredWidth value"); } - else if (prop.unit == 'px') { + else if (prop.unit === 'px') { targetWidth = prop.value; } - else if (prop.unit == '%') { + else if (prop.unit === '%') { let availableWidth = space.workArea().width - Settings.prefs.horizontal_margin * 2 - Settings.prefs.window_gap; targetWidth = Math.floor(availableWidth * Math.min(prop.value / 100.0, 1.0)); } @@ -467,7 +580,7 @@ var Space = class Space extends Array { // compensate to keep window position bar on all monitors if (Settings.prefs.show_window_position_bar) { - const panelBoxHeight = TopBar.panelBox.height; + const panelBoxHeight = Topbar.panelBox.height; const monitor = Main.layoutManager.primaryMonitor; if (monitor !== this.monitor) { workArea.y += panelBoxHeight; @@ -811,7 +924,7 @@ var Space = class Space extends Array { if (!column) return false; let row = column.indexOf(this.selectedWindow); - if (Lib.in_bounds(column, row + dir) == false) { + if (Lib.in_bounds(column, row + dir) === false) { index += dir; if (dir === 1) { if (index < this.length) @@ -1164,7 +1277,7 @@ var Space = class Space extends Array { } else { this.showTopBar = 0; } - this._populated && TopBar.fixTopBar(); + this._populated && Topbar.fixTopBar(); this.layout(); } @@ -1173,7 +1286,7 @@ var Space = class Space extends Array { * Returns true if this space has the topbar. */ get hasTopBar() { - return this.monitor && this.monitor === TopBar.panelMonitor(); + return this.monitor && this.monitor === Topbar.panelMonitor(); } updateColor() { @@ -1224,7 +1337,7 @@ border-radius: ${borderWidth}px; this.name = name; if (this.workspace === workspaceManager.get_active_workspace()) { - TopBar.updateWorkspaceIndicator(this.index); + Topbar.updateWorkspaceIndicator(this.index); } } @@ -1295,7 +1408,7 @@ border-radius: ${borderWidth}px; this.windowPositionBarBackdrop.width = width; let segments = width / cols; this.windowPositionBar.width = segments; - this.windowPositionBar.height = TopBar.panelBox.height; + this.windowPositionBar.height = Topbar.panelBox.height; // index of currently selected window let windex = this.indexOf(this.selectedWindow); @@ -1313,10 +1426,10 @@ border-radius: ${borderWidth}px; if (Settings.prefs.show_window_position_bar) { if (changeTopBarStyle) { if (visible && this.hasTopBar) { - TopBar.setTransparentStyle(); + Topbar.setTransparentStyle(); } else { - TopBar.setNoBackgroundStyle(); + Topbar.setNoBackgroundStyle(); } } @@ -1325,7 +1438,7 @@ border-radius: ${borderWidth}px; visible = true; } - // don't show elements on spaces with actual TopBar (unless inPreview) + // don't show elements on spaces with actual Topbar (unless inPreview) if (this.hasTopBar && !inPreview) { visible = false; } @@ -1348,8 +1461,8 @@ border-radius: ${borderWidth}px; updateSpaceIconPositions() { // get positions of topbar elements to replicate positions in spaces const vertex = new Graphene.Point3D({ x: 0, y: 0 }); - const labelPosition = TopBar.menu.label.apply_relative_transform_to_point(Main.panel, vertex); - const focusPosition = TopBar.focusButton.apply_relative_transform_to_point(Main.panel, vertex); + const labelPosition = Topbar.menu.label.apply_relative_transform_to_point(Main.panel, vertex); + const focusPosition = Topbar.focusButton.apply_relative_transform_to_point(Main.panel, vertex); this.workspaceLabel.set_position(labelPosition.x, labelPosition.y); this.focusModeIcon.set_position(focusPosition.x, focusPosition.y); @@ -1624,7 +1737,7 @@ border-radius: ${borderWidth}px; this.clip.destroy(); this.clip = null; } -}; +} Signals.addSignalMethods(Space.prototype); @@ -1771,9 +1884,9 @@ var Spaces = class Spaces extends Map { this.spaceContainer.show(); activeSpace.monitor.clickOverlay.deactivate(); - TopBar.refreshWorkspaceIndicator(); + Topbar.refreshWorkspaceIndicator(); this.setSpaceTopbarElementsVisible(); - StackOverlay.multimonitorDragDropSupport(); + Stackoverlay.multimonitorDragDropSupport(); }; if (this.onlyOnPrimary) { @@ -2098,7 +2211,7 @@ var Spaces = class Spaces extends Map { _animateToSpaceOrdered(toSpace, animate = true) { // Always show the topbar when using the workspace stack - TopBar.fixTopBar(); + Topbar.fixTopBar(); toSpace = toSpace || this.selectedSpace; let monitorSpaces = this._getOrderedSpaces(toSpace.monitor); @@ -2208,8 +2321,8 @@ var Spaces = class Spaces extends Map { this.selectedSpace = newSpace; // if active (source space) is panelMonitor update indicator - if (currentSpace.monitor === TopBar.panelMonitor()) { - TopBar.updateWorkspaceIndicator(newSpace.index); + if (currentSpace.monitor === Topbar.panelMonitor()) { + Topbar.updateWorkspaceIndicator(newSpace.index); } const scale = 0.825; @@ -2245,7 +2358,7 @@ var Spaces = class Spaces extends Map { inPreview = PreviewMode.STACK; // Always show the topbar when using the workspace stack - TopBar.fixTopBar(); + Topbar.fixTopBar(); this.setSpaceTopbarElementsVisible(true); const scale = 0.9; let space = this.activeSpace; @@ -2369,8 +2482,8 @@ var Spaces = class Spaces extends Map { this.selectedSpace = newSpace; // if active (source space) is panelMonitor update indicator - if (space.monitor === TopBar.panelMonitor()) { - TopBar.updateWorkspaceIndicator(newSpace.index); + if (space.monitor === Topbar.panelMonitor()) { + Topbar.updateWorkspaceIndicator(newSpace.index); } mru.forEach((space, i) => { @@ -2410,7 +2523,7 @@ var Spaces = class Spaces extends Map { let currentPreviewMode = inPreview; inPreview = PreviewMode.NONE; - TopBar.updateWorkspaceIndicator(to.index); + Topbar.updateWorkspaceIndicator(to.index); this.selectedSpace = to; to.show(); @@ -2631,7 +2744,7 @@ var Spaces = class Spaces extends Map { }); } - TopBar.fixStyle(); + Topbar.fixStyle(); } }; Signals.addSignalMethods(Spaces.prototype); @@ -2640,7 +2753,7 @@ Signals.addSignalMethods(Spaces.prototype); * Return true if a window is tiled (e.g. not floating, not scratch, not transient). * @param metaWindow */ -function isTiled(metaWindow) { +export function isTiled(metaWindow) { if (!metaWindow) { return false; } @@ -2661,7 +2774,7 @@ function isTiled(metaWindow) { * @param metaWindow * @returns */ -function isTransient(metaWindow) { +export function isTransient(metaWindow) { if (!metaWindow) { return false; } @@ -2678,7 +2791,7 @@ function isTransient(metaWindow) { * @param metaWindow * @returns */ -function hasTransient(metaWindow) { +export function hasTransient(metaWindow) { if (!metaWindow) { return false; } @@ -2696,7 +2809,7 @@ function hasTransient(metaWindow) { * @param metaWindow * @returns */ -function isFloating(metaWindow) { +export function isFloating(metaWindow) { if (!metaWindow) { return false; } @@ -2704,14 +2817,14 @@ function isFloating(metaWindow) { return space.isFloating?.(metaWindow) ?? false; } -function isScratch(metaWindow) { +export function isScratch(metaWindow) { if (!metaWindow) { return false; } return Scratch.isScratchWindow(metaWindow); } -function is_override_redirect(metaWindow) { +export function is_override_redirect(metaWindow) { // Note: is_overrride_redirect() seem to be false for all wayland windows const windowType = metaWindow.windowType; return ( @@ -2721,7 +2834,7 @@ function is_override_redirect(metaWindow) { ); } -function registerWindow(metaWindow) { +export function registerWindow(metaWindow) { if (is_override_redirect(metaWindow)) { return false; } @@ -2747,7 +2860,7 @@ function registerWindow(metaWindow) { signals.connect(metaWindow, "focus", focus_wrapper); signals.connect(metaWindow, 'size-changed', allocateClone); // Note: runs before gnome-shell's minimize handling code - signals.connect(metaWindow, 'notify::fullscreen', TopBar.fixTopBar); + signals.connect(metaWindow, 'notify::fullscreen', Topbar.fixTopBar); signals.connect(metaWindow, 'notify::minimized', minimizeWrapper); signals.connect(actor, 'show', showWrapper); signals.connect(actor, 'destroy', destroyHandler); @@ -2755,7 +2868,7 @@ function registerWindow(metaWindow) { return true; } -function allocateClone(metaWindow) { +export function allocateClone(metaWindow) { let frame = metaWindow.get_frame_rect(); let buffer = metaWindow.get_buffer_rect(); // Adjust the clone's origin to the north-west, so it will line up @@ -2779,11 +2892,11 @@ function allocateClone(metaWindow) { } } -function destroyHandler(actor) { +export function destroyHandler(actor) { signals.disconnect(actor); } -function resizeHandler(metaWindow) { +export function resizeHandler(metaWindow) { // if navigator is showing, reset/refresh it after a window has resized if (Navigator.navigating) { Navigator.getNavigator().minimaps.forEach(m => typeof m !== 'number' && m.reset()); @@ -2819,129 +2932,10 @@ function resizeHandler(metaWindow) { } } -let signals, backgroundGroup, grabSignals; -let gsettings, backgroundSettings, interfaceSettings; -let displayConfig; -let saveState; -let startupTimeoutId, timerId; -var inGrab; // exported -function enable(extension) { - inGrab = false; - - displayConfig = new Utils.DisplayConfig(); - saveState = saveState ?? new SaveState(); - - gsettings = ExtensionUtils.getSettings(); - backgroundSettings = new Gio.Settings({ - schema_id: 'org.gnome.desktop.background', - }); - interfaceSettings = new Gio.Settings({ - schema_id: "org.gnome.desktop.interface", - }); - - signals = new Utils.Signals(); - grabSignals = new Utils.Signals(); - - let setVerticalMargin = () => { - let vMargin = gsettings.get_int('vertical-margin'); - let gap = gsettings.get_int('window-gap'); - Settings.prefs.vertical_margin = Math.max(Math.round(gap / 2), vMargin); - }; - setVerticalMargin(); - - // setup actions on gap changes - let onWindowGapChanged = () => { - setVerticalMargin(); - Utils.timeout_remove(timerId); - timerId = Mainloop.timeout_add(500, () => { - spaces.mru().forEach(space => { - space.layout(); - }); - timerId = null; - return false; // on return false destroys timeout - }); - }; - gsettings.connect('changed::vertical-margin', onWindowGapChanged); - gsettings.connect('changed::vertical-margin-bottom', onWindowGapChanged); - gsettings.connect('changed::window-gap', onWindowGapChanged); - - backgroundGroup = Main.layoutManager._backgroundGroup; - - spaces = new Spaces(); - let initWorkspaces = () => { - try { - spaces.init(); - } catch (e) { - console.error(new Error('#paperwm startup failed')); - } - - // Fix the stack overlay - spaces.mru().reverse().forEach(s => { - // if s.selectedWindow exists and is in view, then use option moveto: false - if (s.selectedWindow) { - let options = s.isFullyVisible(s.selectedWindow) ? { moveto: false } : { force: true }; - ensureViewport(s.selectedWindow, s, options); - } - s.monitor.clickOverlay.show(); - }); - TopBar.fixTopBar(); - - // on idle update space topbar elements and name - Utils.later_add(Meta.LaterType.IDLE, () => { - spaces.forEach(s => { - s.setSpaceTopbarElementsVisible(); - s.updateName(); - }); - }); - }; - - if (Main.layoutManager._startingUp) { - // Defer workspace initialization until existing windows are accessible. - // Otherwise we're unable to restore the tiling-order. (when restarting - // gnome-shell) - signals.connectOneShot(Main.layoutManager, 'startup-complete', - () => displayConfig.upgradeGnomeMonitors(initWorkspaces)); - } else { - /** - * Upgrade gnome monitor info objects by add "connector" information, and - * when done (async) callback to initworkspaces. - */ - // NOTE: this should happen after Patches.enable() have run, so we do - // it in a timeout - startupTimeoutId = Mainloop.timeout_add(0, () => { - displayConfig.upgradeGnomeMonitors(initWorkspaces); - startupTimeoutId = null; - return false; // on return false destroys timeout - }); - } -} - -function disable () { - Utils.timeout_remove(startupTimeoutId); - startupTimeoutId = null; - Utils.timeout_remove(timerId); - timerId = null; - - grabSignals.destroy(); - grabSignals = null; - signals.destroy(); - signals = null; - - saveState.prepare(); - displayConfig.downgradeGnomeMonitors(); - displayConfig = null; - spaces.destroy(); - inGrab = null; - gsettings = null; - backgroundGroup = null; - backgroundSettings = null; - interfaceSettings = null; -} - /** * Saves current state for controlled restarts of PaperWM. */ -let SaveState = class SaveState { +class SaveState { constructor() { this.prevMonitors = new Map(); this.prevSpaces = new Map(); @@ -3014,20 +3008,20 @@ let SaveState = class SaveState { } }); } -}; +} /** * Return the currently focused monitor (or more specifically, the current * active space's monitor). */ -function focusMonitor() { +export function focusMonitor() { return spaces?.activeSpace?.monitor; } /** Types of windows which never should be tiled. */ -function add_filter(meta_window) { +export function add_filter(meta_window) { if (isTransient(meta_window)) { // Never add transient windows return false; @@ -3050,7 +3044,7 @@ function add_filter(meta_window) { /** Handle windows leaving workspaces. */ -function remove_handler(workspace, meta_window) { +export function remove_handler(workspace, meta_window) { debug("window-removed", meta_window, meta_window.title, workspace.index()); // Note: If `meta_window` was closed and had focus at the time, the next // window has already received the `focus` signal at this point. @@ -3072,7 +3066,7 @@ function remove_handler(workspace, meta_window) { /** Handle windows entering workspaces. */ -function add_handler(ws, metaWindow) { +export function add_handler(ws, metaWindow) { debug("window-added", metaWindow, metaWindow.title, metaWindow.window_type, ws.index(), metaWindow.on_all_workspaces); // Do not handle grabbed windows @@ -3096,7 +3090,7 @@ function add_handler(ws, metaWindow) { and `Display::window-created` through `WindowActor::show` if window is newly created to ensure that the WindowActor exists. */ -function insertWindow(metaWindow, { existing }) { +export function insertWindow(metaWindow, { existing }) { // Add newly created windows to the space being previewed if (!existing && !metaWindow.is_on_all_workspaces() && @@ -3240,7 +3234,7 @@ function insertWindow(metaWindow, { existing }) { } } -function animateDown(metaWindow) { +export function animateDown(metaWindow) { let space = spaces.spaceOfWindow(metaWindow); let workArea = space.workArea(); Easer.addEase(metaWindow.clone, { @@ -3249,7 +3243,7 @@ function animateDown(metaWindow) { }); } -function ensuredX(meta_window, space) { +export function ensuredX(meta_window, space) { let index = space.indexOf(meta_window); let last = space.selectedWindow; let lastIndex = space.indexOf(last); @@ -3303,7 +3297,7 @@ function ensuredX(meta_window, space) { * @param {boolean} options.moveto if true, executes a move_to animated action * @returns */ -function ensureViewport(meta_window, space, options = {}) { +export function ensureViewport(meta_window, space, options = {}) { space = space || spaces.spaceOfWindow(meta_window); let force = options?.force ?? false; let moveto = options?.moveto ?? true; @@ -3349,7 +3343,7 @@ function ensureViewport(meta_window, space, options = {}) { space.emit('select'); } -function updateSelection(space, metaWindow) { +export function updateSelection(space, metaWindow) { if (!metaWindow) { return; } @@ -3383,7 +3377,7 @@ function updateSelection(space, metaWindow) { * Move the column containing @meta_window to x, y and propagate the change * in @space. Coordinates are relative to monitor and y is optional. */ -function move_to(space, metaWindow, { x, y, force, instant }) { +export function move_to(space, metaWindow, { x, y, force, instant }) { if (space.indexOf(metaWindow) === -1) return; @@ -3414,7 +3408,7 @@ function move_to(space, metaWindow, { x, y, force, instant }) { space.fixOverlays(metaWindow); } -function grabBegin(metaWindow, type) { +export function grabBegin(metaWindow, type) { switch (type) { case Meta.GrabOp.COMPOSITOR: case Meta.GrabOp.FRAME_BUTTON: @@ -3472,7 +3466,7 @@ function grabBegin(metaWindow, type) { } } -function grabEnd(metaWindow, type) { +export function grabEnd(metaWindow, type) { if (!inGrab || inGrab.dnd || inGrab.grabbed) return; @@ -3484,14 +3478,14 @@ function grabEnd(metaWindow, type) { * Sets the selected window on other workspaces inactive. * Particularly noticable with multi-monitor setups. */ -function setAllWorkspacesInactive() { +export function setAllWorkspacesInactive() { spaces.forEach(s => s.setSelectionInactive()); } /** * Returns the default focus mode (can be user-defined). */ -function getDefaultFocusMode() { +export function getDefaultFocusMode() { // find matching focus mode const mode = Settings.prefs.default_focus_mode; const modes = FocusModes; @@ -3511,12 +3505,12 @@ function getDefaultFocusMode() { } // `MetaWindow::focus` handling -function focus_handler(metaWindow, user_data) { +export function focus_handler(metaWindow, user_data) { console.debug("focus:", metaWindow.title, Utils.framestr(metaWindow.get_frame_rect())); if (Scratch.isScratchWindow(metaWindow)) { setAllWorkspacesInactive(); Scratch.makeScratch(metaWindow); - TopBar.fixTopBar(); + Topbar.fixTopBar(); return; } @@ -3572,27 +3566,27 @@ function focus_handler(metaWindow, user_data) { */ ensureViewport(metaWindow, space, { moveto: !Main.overview.visible }); - TopBar.fixTopBar(); + Topbar.fixTopBar(); } -var focus_wrapper = Utils.dynamic_function_ref('focus_handler', this); +export const focus_wrapper = Utils.dynamic_function_ref('focus_handler', this); /** Push all minimized windows to the scratch layer */ -function minimizeHandler(metaWindow) { +export function minimizeHandler(metaWindow) { debug('minimized', metaWindow.title); if (metaWindow.minimized) { Scratch.makeScratch(metaWindow); } } -var minimizeWrapper = Utils.dynamic_function_ref('minimizeHandler', this); +export const minimizeWrapper = Utils.dynamic_function_ref('minimizeHandler', this); /** `WindowActor::show` handling Kill any falsely shown WindowActor. */ -function showHandler(actor) { +export function showHandler(actor) { let metaWindow = actor.meta_window; let onActive = metaWindow.get_workspace() === workspaceManager.get_active_workspace(); @@ -3613,9 +3607,9 @@ function showHandler(actor) { animateWindow(metaWindow); } } -var showWrapper = Utils.dynamic_function_ref('showHandler', this); +export const showWrapper = Utils.dynamic_function_ref('showHandler', this); -function showWindow(metaWindow) { +export function showWindow(metaWindow) { let actor = metaWindow.get_compositor_private(); if (!actor) return false; @@ -3627,7 +3621,7 @@ function showWindow(metaWindow) { return true; } -function animateWindow(metaWindow) { +export function animateWindow(metaWindow) { let actor = metaWindow.get_compositor_private(); if (!actor) return false; @@ -3639,12 +3633,12 @@ function animateWindow(metaWindow) { return true; } -function isWindowAnimating(metaWindow) { +export function isWindowAnimating(metaWindow) { let clone = metaWindow.clone; return clone.get_parent() && clone.cloneActor.visible; } -function toggleMaximizeHorizontally(metaWindow) { +export function toggleMaximizeHorizontally(metaWindow) { metaWindow = metaWindow || display.focus_window; if (metaWindow.get_maximized() === Meta.MaximizeFlags.BOTH) { @@ -3677,7 +3671,7 @@ function toggleMaximizeHorizontally(metaWindow) { } } -function resizeHInc(metaWindow) { +export function resizeHInc(metaWindow) { metaWindow = metaWindow || display.focus_window; let frame = metaWindow.get_frame_rect(); let space = spaces.spaceOfWindow(metaWindow); @@ -3697,7 +3691,7 @@ function resizeHInc(metaWindow) { metaWindow.move_resize_frame(true, frame.x, targetY, frame.width, targetHeight); } -function resizeHDec(metaWindow) { +export function resizeHDec(metaWindow) { metaWindow = metaWindow || display.focus_window; let frame = metaWindow.get_frame_rect(); let space = spaces.spaceOfWindow(metaWindow); @@ -3718,7 +3712,7 @@ function resizeHDec(metaWindow) { metaWindow.move_resize_frame(true, frame.x, targetY, frame.width, targetHeight); } -function resizeWInc(metaWindow) { +export function resizeWInc(metaWindow) { metaWindow = metaWindow || display.focus_window; let frame = metaWindow.get_frame_rect(); let space = spaces.spaceOfWindow(metaWindow); @@ -3738,7 +3732,7 @@ function resizeWInc(metaWindow) { metaWindow.move_resize_frame(true, targetX, frame.y, targetWidth, frame.height); } -function resizeWDec(metaWindow) { +export function resizeWDec(metaWindow) { metaWindow = metaWindow || display.focus_window; let frame = metaWindow.get_frame_rect(); let space = spaces.spaceOfWindow(metaWindow); @@ -3759,7 +3753,7 @@ function resizeWDec(metaWindow) { metaWindow.move_resize_frame(true, targetX, frame.y, targetWidth, frame.height); } -function getCycleWindowWidths(metaWindow) { +export function getCycleWindowWidths(metaWindow) { let steps = Settings.prefs.cycle_width_steps; let space = spaces.spaceOfWindow(metaWindow); let workArea = space.workArea(); @@ -3774,15 +3768,15 @@ function getCycleWindowWidths(metaWindow) { return steps; } -function cycleWindowWidth(metawindow) { +export function cycleWindowWidth(metawindow) { return cycleWindowWidthDirection(metawindow, CycleWindowSizesDirection.FORWARD); } -function cycleWindowWidthBackwards(metawindow) { +export function cycleWindowWidthBackwards(metawindow) { return cycleWindowWidthDirection(metawindow, CycleWindowSizesDirection.BACKWARDS); } -function cycleWindowWidthDirection(metaWindow, direction) { +export function cycleWindowWidthDirection(metaWindow, direction) { let frame = metaWindow.get_frame_rect(); let space = spaces.spaceOfWindow(metaWindow); let workArea = space.workArea(); @@ -3813,15 +3807,15 @@ function cycleWindowWidthDirection(metaWindow, direction) { metaWindow.move_resize_frame(true, targetX, frame.y, targetWidth, frame.height); } -function cycleWindowHeight(metawindow) { +export function cycleWindowHeight(metawindow) { return cycleWindowHeightDirection(metawindow, CycleWindowSizesDirection.FORWARD); } -function cycleWindowHeightBackwards(metawindow) { +export function cycleWindowHeightBackwards(metawindow) { return cycleWindowHeightDirection(metawindow, CycleWindowSizesDirection.BACKWARDS); } -function cycleWindowHeightDirection(metaWindow, direction) { +export function cycleWindowHeightDirection(metaWindow, direction) { let steps = Settings.prefs.cycle_height_steps; let frame = metaWindow.get_frame_rect(); @@ -3868,18 +3862,18 @@ function cycleWindowHeightDirection(metaWindow, direction) { } } -function activateNthWindow(n, space) { +export function activateNthWindow(n, space) { space = space || spaces.activeSpace; let nth = space[n][0]; ensureViewport(nth, space); } -function activateFirstWindow(mw, space) { +export function activateFirstWindow(mw, space) { space = space || spaces.activeSpace; activateNthWindow(0, space); } -function activateLastWindow(mw, space) { +export function activateLastWindow(mw, space) { space = space || spaces.activeSpace; activateNthWindow(space.length - 1, space); } @@ -3891,7 +3885,7 @@ function activateLastWindow(mw, space) { * programmatically before it's rendered, see * https://github.com/paperwm/PaperWM/issues/448 for details). */ -function activateWindowAfterRendered(actor, mw) { +export function activateWindowAfterRendered(actor, mw) { signals.connectOneShot(actor, 'show', () => { Main.activateWindow(mw); }); @@ -3900,7 +3894,7 @@ function activateWindowAfterRendered(actor, mw) { /** * Centers the currently selected window. */ -function centerWindowHorizontally(metaWindow) { +export function centerWindowHorizontally(metaWindow) { const frame = metaWindow.get_frame_rect(); const space = spaces.spaceOfWindow(metaWindow); const monitor = space.monitor; @@ -3932,12 +3926,12 @@ function centerWindowHorizontally(metaWindow) { * @param {FocusModes} mode * @param {Space} space */ -function setFocusMode(mode, space) { +export function setFocusMode(mode, space) { space = space ?? spaces.activeSpace; space.focusMode = mode; space.focusModeIcon.setMode(mode); if (space.hasTopBar) { - TopBar.focusButton.setFocusMode(mode); + Topbar.focusButton.setFocusMode(mode); } const workArea = space.workArea(); @@ -3983,7 +3977,7 @@ function setFocusMode(mode, space) { * Switches to the next focus mode for a space. * @param {Space} space */ -function switchToNextFocusMode(space) { +export function switchToNextFocusMode(space) { space = space ?? spaces.activeSpace; const numModes = Object.keys(FocusModes).length; // for currMode we switch to 1-based to use it validly in remainder operation @@ -3995,7 +3989,7 @@ function switchToNextFocusMode(space) { /** * "Fit" values such that they sum to `targetSum` */ -function fitProportionally(values, targetSum) { +export function fitProportionally(values, targetSum) { let sum = Lib.sum(values); let weights = values.map(v => v / sum); @@ -4007,7 +4001,7 @@ function fitProportionally(values, targetSum) { return fitted; } -function allocateDefault(column, availableHeight, selectedWindow) { +export function allocateDefault(column, availableHeight, selectedWindow) { if (column.length === 1) { return [availableHeight]; } else { @@ -4015,9 +4009,9 @@ function allocateDefault(column, availableHeight, selectedWindow) { const gap = Settings.prefs.window_gap; const minHeight = 50; - function heightOf(mw) { + const heightOf = mw => { return mw._targetHeight || mw.get_frame_rect().height; - } + }; const k = selectedWindow && column.indexOf(selectedWindow); const selectedHeight = selectedWindow && heightOf(selectedWindow); @@ -4049,7 +4043,7 @@ function allocateDefault(column, availableHeight, selectedWindow) { } } -function allocateEqualHeight(column, available) { +export function allocateEqualHeight(column, available) { available -= (column.length - 1) * Settings.prefs.window_gap; return column.map(_ => Math.floor(available / column.length)); } @@ -4060,7 +4054,7 @@ function allocateEqualHeight(column, available) { * this allows freshly created windows to be stacked without * having to change focus */ -function slurp(metaWindow) { +export function slurp(metaWindow) { let space = spaces.spaceOfWindow(metaWindow); let index = space.indexOf(metaWindow); @@ -4102,7 +4096,7 @@ function slurp(metaWindow) { ensureViewport(metaWindowToEnsure, space, { force: true }); } -function barf(metaWindow) { +export function barf(metaWindow) { if (!metaWindow) return; @@ -4125,35 +4119,35 @@ function barf(metaWindow) { ensureViewport(space.selectedWindow, space, { force: true }); } -function selectPreviousSpace(mw, space) { +export function selectPreviousSpace(mw, space) { spaces.selectStackSpace(Meta.MotionDirection.DOWN); } -function selectPreviousSpaceBackwards(mw, space) { +export function selectPreviousSpaceBackwards(mw, space) { spaces.selectStackSpace(Meta.MotionDirection.UP); } -function movePreviousSpace(mw, space) { +export function movePreviousSpace(mw, space) { spaces.selectStackSpace(Meta.MotionDirection.DOWN, true); } -function movePreviousSpaceBackwards(mw, space) { +export function movePreviousSpaceBackwards(mw, space) { spaces.selectStackSpace(Meta.MotionDirection.UP, true); } -function selectDownSpace(mw, space) { +export function selectDownSpace(mw, space) { spaces.selectSequenceSpace(Meta.MotionDirection.DOWN); } -function selectUpSpace(mw, space) { +export function selectUpSpace(mw, space) { spaces.selectSequenceSpace(Meta.MotionDirection.UP); } -function moveDownSpace(mw, space) { +export function moveDownSpace(mw, space) { spaces.selectSequenceSpace(Meta.MotionDirection.DOWN, true); } -function moveUpSpace(mw, space) { +export function moveUpSpace(mw, space) { spaces.selectSequenceSpace(Meta.MotionDirection.UP, true); } @@ -4162,7 +4156,7 @@ function moveUpSpace(mw, space) { navigating. When done, insert all the detached windows again. Activates last taken window when navigator operation complete. */ -function takeWindow(metaWindow, space, { navigator }) { +export function takeWindow(metaWindow, space, { navigator }) { space = space || spaces.selectedSpace; metaWindow = metaWindow || space.selectedWindow; navigator = navigator || Navigator.getNavigator(); @@ -4224,7 +4218,7 @@ function takeWindow(metaWindow, space, { navigator }) { Sort the @windows based on their clone's stacking order in @space.cloneContainer. */ -function sortWindows(space, windows) { +export function sortWindows(space, windows) { if (windows.length === 1) return windows; let clones = windows.map(w => w.clone); @@ -4233,14 +4227,14 @@ function sortWindows(space, windows) { .map(c => c.meta_window); } -function rotated(list, dir = 1) { +export function rotated(list, dir = 1) { return [].concat( list.slice(dir), list.slice(0, dir) ); } -function cycleWorkspaceSettings(dir = 1) { +export function cycleWorkspaceSettings(dir = 1) { let n = workspaceManager.get_n_workspaces(); let N = Workspace.getWorkspaceList().get_strv('list').length; let space = spaces.selectedSpace; @@ -4277,6 +4271,6 @@ function cycleWorkspaceSettings(dir = 1) { } // Backward compatibility -function defwinprop(...args) { +export function defwinprop(...args) { return Settings.defwinprop(...args); } From 65725797d4ec0b886ee21368cd10c64569a8de0e Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 17 Sep 2023 22:05:44 +1000 Subject: [PATCH 20/50] Updated shell version to "45". --- metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metadata.json b/metadata.json index 098895c4..1b91dd96 100644 --- a/metadata.json +++ b/metadata.json @@ -4,5 +4,5 @@ "description": "Tiling window manager with a twist", "url": "https://github.com/paperwm/PaperWM", "settings-schema": "org.gnome.shell.extensions.paperwm", - "shell-version": [ "42", "43", "44" ] + "shell-version": [ "45" ] } From 40e6ad34f9391bba04cd81a404305a277a2c5c87 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 17 Sep 2023 22:47:26 +1000 Subject: [PATCH 21/50] Lots of import related fixes. --- app.js | 6 ++++-- extension.js | 7 +++---- imports.js | 3 +++ liveAltTab.js | 3 ++- navigator.js | 8 ++++---- settings.js | 2 +- tiling.js | 7 +++++-- topbar.js | 6 +++--- utils.js | 5 +++-- workspace.js | 2 +- 10 files changed, 29 insertions(+), 20 deletions(-) diff --git a/app.js b/app.js index b3b009d9..d82d3817 100644 --- a/app.js +++ b/app.js @@ -2,7 +2,9 @@ import GLib from 'gi://GLib'; import Gio from 'gi://Gio'; import Shell from 'gi://Shell'; -import { ExtensionModule, Patches, Tiling } from './imports.js'; +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; + +import { Patches, Tiling } from './imports.js'; /* Application functionality, like global new window actions etc. @@ -176,7 +178,7 @@ export function mkCommandLineSpawner(commandlineTemplate, spawnInWorkspaceDir = success = GLib.spawn_async(workingDir, cmdArgs, GLib.get_environ(), GLib.SpawnFlags.SEARCH_PATH, null); } if (!success) { - ExtensionModule.notify( + Main.notify( `Failed to run custom spawn handler for ${app.id}`, `Attempted to run '${commandline}'`); } diff --git a/extension.js b/extension.js index b68486a1..e3cb058f 100644 --- a/extension.js +++ b/extension.js @@ -11,7 +11,7 @@ import { Stackoverlay, Scratch, Workspace, Tiling, Topbar, Patches, App } from './imports.js'; -import { Extension, dir } from 'resource:///org/gnome/shell/extensions/extension.js'; +import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js'; /** The currently used modules @@ -72,7 +72,6 @@ export default class PaperWM extends Extension { disable() { console.log('#PaperWM disabled'); this.prepareForDisable(); - this.run('disable', true); [...this.modules].reverse().forEach(m => { if (m['disable']) { m.disable(); @@ -120,7 +119,7 @@ export default class PaperWM extends Extension { try { const configDir = this.getConfigDir(); - const metadata = dir.get_child("metadata.json"); + const metadata = this.dir.get_child("metadata.json"); metadata.copy(configDir.get_child("metadata.json"), Gio.FileCopyFlags.OVERWRITE, null, null); } catch (error) { console.error('PaperWM', `could not update user config metadata.json: ${error}`); @@ -135,7 +134,7 @@ export default class PaperWM extends Extension { } // Copy the user.js template to the config directory - const user = dir.get_child("config/user.js"); + const user = this.dir.get_child("config/user.js"); user.copy(configDir.get_child("user.js"), Gio.FileCopyFlags.NONE, null, null); } diff --git a/imports.js b/imports.js index 992b579b..251155db 100644 --- a/imports.js +++ b/imports.js @@ -13,3 +13,6 @@ export * as Topbar from './topbar.js'; export * as Patches from './patches.js'; export * as App from './app.js'; export * as Lib from './lib.js'; +export * as Minimap from './minimap.js'; +export * as Grab from './grab.js'; + diff --git a/liveAltTab.js b/liveAltTab.js index 142a0493..3f3da088 100644 --- a/liveAltTab.js +++ b/liveAltTab.js @@ -6,7 +6,8 @@ import GObject from 'gi://GObject'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import * as AltTab from 'resource:///org/gnome/shell/ui/altTab.js'; -import { Settings, Utils, Keybindings, Tiling, Scratch, Easer } from './imports.js'; +import { Settings, Utils, Keybindings, Tiling, Scratch } from './imports.js'; +import { Easer } from './utils.js'; let switcherSettings; export function enable() { diff --git a/navigator.js b/navigator.js index 81a25f3f..dcb56912 100644 --- a/navigator.js +++ b/navigator.js @@ -4,7 +4,7 @@ import Meta from 'gi://Meta'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import { Utils, Tiling, Keybindings, TopBar, Scratch, Minimap } from './imports.js'; +import { Utils, Tiling, Keybindings, Topbar, Scratch, Minimap } from './imports.js'; /** Navigation and previewing functionality. @@ -100,7 +100,7 @@ class ActionDispatcher { show(backward, binding, mask) { this._modifierMask = getModLock(mask); this.navigator = getNavigator(); - TopBar.fixTopBar(); + Topbar.fixTopBar(); let actionId = Keybindings.idOf(binding); if (actionId === Meta.KeyBindingAction.NONE) { try { @@ -280,7 +280,7 @@ class NavigatorClass { this.monitor.clickOverlay.hide(); this.minimaps = new Map(); - TopBar.fixTopBar(); + Topbar.fixTopBar(); Scratch.animateWindows(); this.space.startAnimate(); @@ -402,7 +402,7 @@ class NavigatorClass { if (!Tiling.inGrab) Scratch.showWindows(); - TopBar.fixTopBar(); + Topbar.fixTopBar(); Main.wm._blockAnimations = this._block; this.space.moveDone(); diff --git a/settings.js b/settings.js index 9dee5cde..8a7e8d17 100644 --- a/settings.js +++ b/settings.js @@ -1,7 +1,7 @@ import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; -import AcceleratorParse from './imports.js'; +import { AcceleratorParse } from './imports.js'; /** Settings utility shared between the running extension and the preference UI. diff --git a/tiling.js b/tiling.js index 5aa82a29..08a72dc1 100644 --- a/tiling.js +++ b/tiling.js @@ -8,9 +8,12 @@ import St from 'gi://St'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import { Settings, Utils, Lib, Workspace, Gestures, Navigator, Grab, Topbar, Scratch, Stackoverlay } from './imports.js'; +import { + Settings, Utils, Lib, Workspace, Gestures, Navigator, Grab, Topbar, + Scratch, Stackoverlay +} from './imports.js'; import { debug, Easer } from './utils.js'; -import { ClickOverlay } from './stackoverlay'; +import { ClickOverlay } from './stackoverlay.js'; const { signals: Signals } = imports; const workspaceManager = global.workspace_manager; diff --git a/topbar.js b/topbar.js index 0cc6ca5b..5e1c1508 100644 --- a/topbar.js +++ b/topbar.js @@ -1,6 +1,3 @@ -import { Settings, Utils, Tiling, Navigator, Scratch } from './imports.js'; -import { Easer } from './utils.js'; - import Clutter from 'gi://Clutter'; import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; @@ -13,6 +10,9 @@ import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import * as panelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js'; import * as popupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; +import { Settings, Utils, Tiling, Navigator, Scratch } from './imports.js'; +import { Easer } from './utils.js'; + const workspaceManager = global.workspace_manager; const display = global.display; diff --git a/utils.js b/utils.js index 0b4c7e8b..f1218431 100644 --- a/utils.js +++ b/utils.js @@ -8,11 +8,12 @@ import St from 'gi://St'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import * as Ripples from 'resource:///org/gnome/shell/ui/ripples.js'; +import * as Config from 'resource:///org/gnome/shell/misc/config.js'; -import Lib from './imports.js'; +import { Lib } from './imports.js'; const Display = global.display; -export let version = imports.misc.config.PACKAGE_VERSION.split('.').map(Number); +export let version = Config.PACKAGE_VERSION.split('.').map(Number); let warpRipple; export function enable() { diff --git a/workspace.js b/workspace.js index 76346c6a..f5a2c799 100644 --- a/workspace.js +++ b/workspace.js @@ -1,7 +1,7 @@ import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; -import Lib from './imports.js'; +import { Lib } from './imports.js'; /** * Workspace related utility functions used by other modules. From a513392e7e151c3ad2401130df12c359748f6355 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 18 Sep 2023 01:50:07 +1000 Subject: [PATCH 22/50] Migrated all debug calls to `console.debug`. --- grab.js | 6 +++--- keybindings.js | 2 +- liveAltTab.js | 2 +- navigator.js | 10 +++++----- patches.js | 2 +- tiling.js | 23 ++++++++++++----------- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/grab.js b/grab.js index 59e8a96f..d4171ff8 100644 --- a/grab.js +++ b/grab.js @@ -42,7 +42,7 @@ export class MoveGrab { } begin({ center } = {}) { - Utils.debug("#grab", "begin"); + console.debug("#grab", "begin"); this.center = center; if (this.grabbed) @@ -107,7 +107,7 @@ export class MoveGrab { return; this.center = center; this.dnd = true; - Utils.debug("#grab", "begin DnD"); + console.debug("#grab", "begin DnD"); Navigator.getNavigator().minimaps.forEach(m => typeof m === 'number' ? GLib.source_remove(m) : m.hide()); global.display.set_cursor(Meta.Cursor.MOVE_OR_RESIZE_WINDOW); @@ -349,7 +349,7 @@ export class MoveGrab { } end() { - Utils.debug("#grab", "end"); + console.debug("#grab", "end"); this.signals.destroy(); this.signals = null; diff --git a/keybindings.js b/keybindings.js index a152e7c9..22c3fbdd 100644 --- a/keybindings.js +++ b/keybindings.js @@ -455,7 +455,7 @@ export function getBoundActionId(keystr) { export function handleAccelerator(display, actionId, deviceId, timestamp) { const action = actionIdMap[actionId]; if (action) { - Utils.debug("#keybindings", "Schemaless keybinding activated", + console.debug("#keybindings", "Schemaless keybinding activated", actionId, action.name); if (global.screen) { action.keyHandler(display, null, display.focus_window); diff --git a/liveAltTab.js b/liveAltTab.js index 3f3da088..3dcb3445 100644 --- a/liveAltTab.js +++ b/liveAltTab.js @@ -141,7 +141,7 @@ export const LiveAltTab = GObject.registerClass( _onDestroy() { super._onDestroy(); - Utils.debug('#preview', 'onDestroy', this.was_accepted); + console.debug('#preview', 'onDestroy', this.was_accepted); Easer.addEase(this.fog, { time: Settings.prefs.animation_time, opacity: 0, diff --git a/navigator.js b/navigator.js index dcb56912..f8b41367 100644 --- a/navigator.js +++ b/navigator.js @@ -71,14 +71,14 @@ class ActionDispatcher { mode; constructor() { - Utils.debug("#dispatch", "created"); + console.debug("#dispatch", "created"); this.signals = new Utils.Signals(); this.actor = Tiling.spaces.spaceContainer; this.actor.set_flags(Clutter.ActorFlags.REACTIVE); this.navigator = getNavigator(); if (grab) { - Utils.debug("#dispatch", "already in grab"); + console.debug("#dispatch", "already in grab"); return; } @@ -107,7 +107,7 @@ class ActionDispatcher { // Check for built-in actions actionId = Meta.prefs_get_keybinding_action(binding); } catch (e) { - Utils.debug("Couldn't resolve action name"); + console.debug("Couldn't resolve action name"); return false; } } @@ -247,7 +247,7 @@ class ActionDispatcher { grab = null; } } catch (e) { - Utils.debug("Failed to release grab: ", e); + console.debug("Failed to release grab: ", e); } this.actor.unset_flags(Clutter.ActorFlags.REACTIVE); @@ -263,7 +263,7 @@ let index = 0; export let navigator; class NavigatorClass { constructor() { - Utils.debug("#navigator", "nav created"); + console.debug("#navigator", "nav created"); navigating = true; this.was_accepted = false; diff --git a/patches.js b/patches.js index 1a48c343..883b5654 100644 --- a/patches.js +++ b/patches.js @@ -328,7 +328,7 @@ export function restoreRuntimeDisables() { * move from gnome version to gnome version. Next to the swipe tracker locations * below are the gnome versions when they were first (or last) seen. */ -var swipeTrackers; // exported +export let swipeTrackers; // exported export function setupSwipeTrackers() { swipeTrackers = [ Main?.overview?._swipeTracker, // gnome 40+ diff --git a/tiling.js b/tiling.js index 08a72dc1..df5ba72c 100644 --- a/tiling.js +++ b/tiling.js @@ -12,7 +12,7 @@ import { Settings, Utils, Lib, Workspace, Gestures, Navigator, Grab, Topbar, Scratch, Stackoverlay } from './imports.js'; -import { debug, Easer } from './utils.js'; +import { Easer } from './utils.js'; import { ClickOverlay } from './stackoverlay.js'; const { signals: Signals } = imports; @@ -2049,7 +2049,7 @@ var Spaces = class Spaces extends Map { let workspace = workspaceManager.get_workspace_by_index(i); workspaces[workspace] = true; if (this.spaceOf(workspace) === undefined) { - debug('workspace added', workspace); + console.debug('workspace added', workspace); this.addSpace(workspace); } } @@ -2057,7 +2057,7 @@ var Spaces = class Spaces extends Map { let nextUnusedWorkspaceIndex = nWorkspaces; for (let [workspace, space] of this) { if (workspaces[space.workspace] !== true) { - debug('workspace removed', space.workspace); + console.debug('workspace removed', space.workspace); this.removeSpace(space); // Maps in javascript (and thus Spaces) remember insertion order @@ -2713,7 +2713,7 @@ var Spaces = class Spaces extends Map { metaWindow.unmapped = true; - debug('window-created', metaWindow.title); + console.debug('window-created', metaWindow.title); let actor = metaWindow.get_compositor_private(); animateWindow(metaWindow); @@ -2865,7 +2865,9 @@ export function registerWindow(metaWindow) { // Note: runs before gnome-shell's minimize handling code signals.connect(metaWindow, 'notify::fullscreen', Topbar.fixTopBar); signals.connect(metaWindow, 'notify::minimized', minimizeWrapper); - signals.connect(actor, 'show', showWrapper); + signals.connect(actor, 'show', actor => { + showHandler(actor); + }); signals.connect(actor, 'destroy', destroyHandler); return true; @@ -3048,7 +3050,7 @@ export function add_filter(meta_window) { Handle windows leaving workspaces. */ export function remove_handler(workspace, meta_window) { - debug("window-removed", meta_window, meta_window.title, workspace.index()); + console.debug("window-removed", meta_window, meta_window.title, workspace.index()); // Note: If `meta_window` was closed and had focus at the time, the next // window has already received the `focus` signal at this point. // Not sure if we can check directly if _this_ window had focus when closed. @@ -3070,7 +3072,7 @@ export function remove_handler(workspace, meta_window) { Handle windows entering workspaces. */ export function add_handler(ws, metaWindow) { - debug("window-added", metaWindow, metaWindow.title, metaWindow.window_type, ws.index(), metaWindow.on_all_workspaces); + console.debug("window-added", metaWindow, metaWindow.title, metaWindow.window_type, ws.index(), metaWindow.on_all_workspaces); // Do not handle grabbed windows if (inGrab && inGrab.window === metaWindow) @@ -3132,7 +3134,7 @@ export function insertWindow(metaWindow, { existing }) { Settings.winprops.splice(Settings.winprops.indexOf(winprop), 1); } if (winprop.scratch_layer) { - debug("#winprops", `Move ${metaWindow.title} to scratch`); + console.debug("#winprops", `Move ${metaWindow.title} to scratch`); addToScratch = true; } if (winprop.focus) { @@ -3309,7 +3311,7 @@ export function ensureViewport(meta_window, space, options = {}) { if (index === -1 || space.length === 0) return undefined; - debug('Moving', meta_window.title); + console.debug('Moving', meta_window.title); if (space.selectedWindow.fullscreen && !meta_window.fullscreen) { @@ -3577,7 +3579,7 @@ export const focus_wrapper = Utils.dynamic_function_ref('focus_handler', this); Push all minimized windows to the scratch layer */ export function minimizeHandler(metaWindow) { - debug('minimized', metaWindow.title); + console.debug('minimized', metaWindow.title); if (metaWindow.minimized) { Scratch.makeScratch(metaWindow); } @@ -3610,7 +3612,6 @@ export function showHandler(actor) { animateWindow(metaWindow); } } -export const showWrapper = Utils.dynamic_function_ref('showHandler', this); export function showWindow(metaWindow) { let actor = metaWindow.get_compositor_private(); From 75b7bb78874bb47a38ebff672eb1d47aee6d9d5e Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 18 Sep 2023 01:58:56 +1000 Subject: [PATCH 23/50] Removed old/unused debug functions. --- utils.js | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) diff --git a/utils.js b/utils.js index f1218431..ece4cca6 100644 --- a/utils.js +++ b/utils.js @@ -24,35 +24,15 @@ export function enable() { export function disable() { warpRipple?.destroy(); warpRipple = null; - debug_all = null; - debug_filter = null; markNewClonesSignalId = null; } -let debug_all = false; // Turn off by default -let debug_filter = { '#paperwm': true, '#stacktrace': true }; -export function debug() { - let keyword = arguments[0]; - let filter = debug_filter[keyword]; - if (filter === false) - return; - if (debug_all || filter === true) - console.debug(Array.prototype.join.call(arguments, " | ")); -} - export function assert(condition, message, ...dump) { if (!condition) { throw new Error(`${message}\n`, dump); } } -export function withTimer(message, fn) { - let start = GLib.get_monotonic_time(); - let ret = fn(); - let stop = GLib.get_monotonic_time(); - console.debug(`${message} ${((stop - start) / 1000).toFixed(1)}ms`); -} - export function print_stacktrace(error) { let trace; if (!error) { @@ -62,10 +42,6 @@ export function print_stacktrace(error) { } else { trace = error.stack.split("\n"); } - // Remove some uninteresting frames - let filtered = trace.filter(frame => { - return frame !== "wrapper@resource:///org/gnome/gjs/modules/lang.js:178"; - }); console.error(`JS ERROR: ${error}\n ${trace.join('\n')}`); } @@ -81,28 +57,6 @@ export function framestr(rect) { return `[ x:${rect.x}, y:${rect.y} w:${rect.width} h:${rect.height} ]`; } -/** - * Returns a human-readable enum value representation - */ -export function ppEnumValue(value, genum) { - let entry = Object.entries(genum).find(([k, v]) => v === value); - if (entry) { - return `${entry[0]} (${entry[1]})`; - } else { - return ` (${value})`; - } -} - -export function ppModiferState(state) { - let mods = []; - for (let [mod, mask] of Object.entries(Clutter.ModifierType)) { - if (mask & state) { - mods.push(mod); - } - } - return mods.join(", "); -} - /** * Look up the function by name at call time. This makes it convenient to * redefine the function without re-registering all signal handler, keybindings, From e6316fe8be4328131dbf0ffa3eb97e201bb79bc0 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 18 Sep 2023 03:40:40 +1000 Subject: [PATCH 24/50] Fixes for exports and also now that ESM, only parent modules can change it's exported values (other modules can't). --- grab.js | 2 +- settings.js | 2 +- tiling.js | 14 +++++++++++--- topbar.js | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/grab.js b/grab.js index d4171ff8..59af72bc 100644 --- a/grab.js +++ b/grab.js @@ -459,7 +459,7 @@ export class MoveGrab { // // If the window is transient this will take care of its parent too. // metaWindow.change_workspace(space.workspace) // space.activate(true); - Tiling.inGrab = false; + Tiling.setInGrab(false); if (this.dispatcher) { Navigator.dismissDispatcher(Clutter.GrabState.POINTER); } diff --git a/settings.js b/settings.js index 8a7e8d17..4173e2c7 100644 --- a/settings.js +++ b/settings.js @@ -55,7 +55,7 @@ export function enable(extension) { 'gesture-horizontal-fingers', 'gesture-workspace-fingers'] .forEach(k => setState(null, k)); prefs.__defineGetter__("minimum_margin", () => { - return Math.min(15, this.horizontal_margin); + return Math.min(15, prefs.horizontal_margin); }); gsettings.connect('changed', setState); diff --git a/tiling.js b/tiling.js index df5ba72c..4d56758b 100644 --- a/tiling.js +++ b/tiling.js @@ -90,7 +90,7 @@ let gsettings, backgroundSettings, interfaceSettings; let displayConfig; let saveState; let startupTimeoutId, timerId; -var inGrab; // exported +export let inGrab; export function enable(extension) { inGrab = false; @@ -204,6 +204,14 @@ export function disable () { interfaceSettings = null; } +/** + * Exported inGrab is read-only from other modules. + * This method allows other modules to change inGrab. + */ +export function setInGrab(value) { + inGrab = value; +} + export class Space extends Array { /** @type {import('@gi-types/clutter10').Actor} */ actor; @@ -1745,7 +1753,7 @@ border-radius: ${borderWidth}px; Signals.addSignalMethods(Space.prototype); // static object -var StackPositions = { +export const StackPositions = { top: 0.01, up: 0.035, selected: 0.1, @@ -1756,7 +1764,7 @@ var StackPositions = { /** A `Map` to store all `Spaces`'s, indexed by the corresponding workspace. */ -var Spaces = class Spaces extends Map { +export const Spaces = class Spaces extends Map { // Fix for eg. space.map, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Species static get [Symbol.species]() { return Map; } constructor() { diff --git a/topbar.js b/topbar.js index 5e1c1508..9256f2db 100644 --- a/topbar.js +++ b/topbar.js @@ -401,7 +401,7 @@ export const FocusButton = GObject.registerClass( } ); -var WorkspaceMenu = GObject.registerClass( +export const WorkspaceMenu = GObject.registerClass( class WorkspaceMenu extends panelMenu.Button { _init() { super._init(0.5, 'Workspace', false); From 7efa78a19a100d8212aac068a9af986c7460052c Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 18 Sep 2023 04:02:32 +1000 Subject: [PATCH 25/50] FIXES: exports, and replace Meta.Rectangle. Also removed several dynamic function ref wrappers. --- scratch.js | 3 ++- tiling.js | 18 ++++++++++-------- utils.js | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/scratch.js b/scratch.js index 0214e0f4..8f7e3f0e 100644 --- a/scratch.js +++ b/scratch.js @@ -1,4 +1,5 @@ import Meta from 'gi://Meta'; +import Mtk from 'gi://Mtk'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; @@ -101,7 +102,7 @@ export function makeScratch(metaWindow) { let vDisplacement = 30; let [x, y] = windowPositionSeen; // The window could be non-placable so can't use frame - targetFrame = new Meta.Rectangle({ + targetFrame = new Mtk.Rectangle({ x, y: y + vDisplacement, width: f.width, height: Math.min(f.height - vDisplacement, Math.floor(f.height * 0.9)), diff --git a/tiling.js b/tiling.js index 4d56758b..86b7b7c9 100644 --- a/tiling.js +++ b/tiling.js @@ -1785,12 +1785,12 @@ export const Spaces = class Spaces extends Map { this.addSpace(workspace); } this.signals.connect(workspaceManager, 'notify::n-workspaces', - Utils.dynamic_function_ref('workspacesChanged', this).bind(this)); + () => this.workspacesChanged()); if (workspaceManager.reorder_workspace) { // Compatibility: only in recent gnome-shell versions this.signals.connect(workspaceManager, 'workspaces-reordered', - Utils.dynamic_function_ref('workspacesChanged', this).bind(this)); + () => this.workspacesChanged()); } let OVERRIDE_SCHEMA; @@ -2868,11 +2868,15 @@ export function registerWindow(metaWindow) { metaWindow.clone = clone; metaWindow.clone.cloneActor = cloneActor; - signals.connect(metaWindow, "focus", focus_wrapper); + signals.connect(metaWindow, "focus", (metaWindow, user_data) => { + focus_handler(metaWindow, user_data); + }); signals.connect(metaWindow, 'size-changed', allocateClone); // Note: runs before gnome-shell's minimize handling code signals.connect(metaWindow, 'notify::fullscreen', Topbar.fixTopBar); - signals.connect(metaWindow, 'notify::minimized', minimizeWrapper); + signals.connect(metaWindow, 'notify::minimized', metaWindow => { + minimizeHandler(metaWindow); + }); signals.connect(actor, 'show', actor => { showHandler(actor); }); @@ -3058,7 +3062,7 @@ export function add_filter(meta_window) { Handle windows leaving workspaces. */ export function remove_handler(workspace, meta_window) { - console.debug("window-removed", meta_window, meta_window.title, workspace.index()); + console.debug("window-removed", meta_window.title, workspace.index()); // Note: If `meta_window` was closed and had focus at the time, the next // window has already received the `focus` signal at this point. // Not sure if we can check directly if _this_ window had focus when closed. @@ -3080,7 +3084,7 @@ export function remove_handler(workspace, meta_window) { Handle windows entering workspaces. */ export function add_handler(ws, metaWindow) { - console.debug("window-added", metaWindow, metaWindow.title, metaWindow.window_type, ws.index(), metaWindow.on_all_workspaces); + console.debug("window-added", metaWindow.title, metaWindow.window_type, ws.index(), metaWindow.on_all_workspaces); // Do not handle grabbed windows if (inGrab && inGrab.window === metaWindow) @@ -3581,7 +3585,6 @@ export function focus_handler(metaWindow, user_data) { Topbar.fixTopBar(); } -export const focus_wrapper = Utils.dynamic_function_ref('focus_handler', this); /** Push all minimized windows to the scratch layer @@ -3592,7 +3595,6 @@ export function minimizeHandler(metaWindow) { Scratch.makeScratch(metaWindow); } } -export const minimizeWrapper = Utils.dynamic_function_ref('minimizeHandler', this); /** `WindowActor::show` handling diff --git a/utils.js b/utils.js index ece4cca6..e9915975 100644 --- a/utils.js +++ b/utils.js @@ -63,8 +63,8 @@ export function framestr(rect) { * etc. (this is like a function symbol in lisp) */ export function dynamic_function_ref(handler_name, owner_obj) { - owner_obj = owner_obj || window; return function() { + console.debug("dynamic_function_ref name", handler_name); owner_obj[handler_name].apply(this, arguments); }; } From 210b96ec2d52850276a0b22624e26ce41e407919 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 18 Sep 2023 04:16:00 +1000 Subject: [PATCH 26/50] Removed deprecated `global.screen` (pre gnome 40). --- grab.js | 3 +-- keybindings.js | 6 +----- tiling.js | 19 ++++--------------- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/grab.js b/grab.js index 59af72bc..74d6b107 100644 --- a/grab.js +++ b/grab.js @@ -89,8 +89,7 @@ export class MoveGrab { this.signals.connect(this.actor, "button-release-event", this.end.bind(this)); this.signals.connect(this.actor, "motion-event", this.motion.bind(this)); - this.signals.connect( - global.screen || global.display, "window-entered-monitor", + this.signals.connect(global.display, "window-entered-monitor", this.beginDnD.bind(this) ); diff --git a/keybindings.js b/keybindings.js index 22c3fbdd..2338ccb5 100644 --- a/keybindings.js +++ b/keybindings.js @@ -457,11 +457,7 @@ export function handleAccelerator(display, actionId, deviceId, timestamp) { if (action) { console.debug("#keybindings", "Schemaless keybinding activated", actionId, action.name); - if (global.screen) { - action.keyHandler(display, null, display.focus_window); - } else { - action.keyHandler(display, display.focus_window); - } + action.keyHandler(display, display.focus_window); } } diff --git a/tiling.js b/tiling.js index 86b7b7c9..b30b1b9b 100644 --- a/tiling.js +++ b/tiling.js @@ -1513,10 +1513,7 @@ border-radius: ${borderWidth}px; } let monitor = this.monitor; - let backgroundParams = global.screen - ? { meta_screen: global.screen } - : { meta_display: display }; - + let backgroundParams = { meta_display: display }; let metaBackground = new Meta.Background(backgroundParams); // gnome-shell 3.38 if (Meta.BackgroundActor.prototype.set_background) { @@ -1787,18 +1784,10 @@ export const Spaces = class Spaces extends Map { this.signals.connect(workspaceManager, 'notify::n-workspaces', () => this.workspacesChanged()); - if (workspaceManager.reorder_workspace) { - // Compatibility: only in recent gnome-shell versions - this.signals.connect(workspaceManager, 'workspaces-reordered', - () => this.workspacesChanged()); - } + this.signals.connect(workspaceManager, 'workspaces-reordered', + () => this.workspacesChanged()); - let OVERRIDE_SCHEMA; - if (global.screen) { - OVERRIDE_SCHEMA = 'org.gnome.shell.overrides'; - } else { // 3.30 now uses per desktop settings, instead of ad-hoc overrides - OVERRIDE_SCHEMA = 'org.gnome.mutter'; - } + const OVERRIDE_SCHEMA = 'org.gnome.mutter'; this.overrideSettings = new Gio.Settings({ schema_id: OVERRIDE_SCHEMA }); } From 36d944a2eb1fafe10cd5b73917b9732a8dd77053 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 18 Sep 2023 08:45:19 +1000 Subject: [PATCH 27/50] Removed `dynamic_funtion_ref` approach and using ESM module references directly. --- keybindings.js | 56 +++++++++++++++++--------------------------------- utils.js | 26 ----------------------- 2 files changed, 19 insertions(+), 63 deletions(-) diff --git a/keybindings.js b/keybindings.js index 2338ccb5..bd51450a 100644 --- a/keybindings.js +++ b/keybindings.js @@ -90,8 +90,7 @@ export function setupActions(settings) { keycomboMap = {}; // keycombo -> action /* Initialize keybindings */ - let dynamic_function_ref = Utils.dynamic_function_ref; - let liveAltTab = dynamic_function_ref('liveAltTab', LiveAltTab); + let liveAltTab = LiveAltTab.liveAltTab; registerAction('live-alt-tab', liveAltTab, { settings }); @@ -173,89 +172,72 @@ export function setupActions(settings) { (mw, space) => space.swap(Meta.MotionDirection.DOWN)); registerPaperAction("toggle-scratch-window", - dynamic_function_ref("toggleScratchWindow", - Scratch)); + Scratch.toggleScratchWindow); registerPaperAction("toggle-scratch-layer", - dynamic_function_ref("toggleScratch", - Scratch)); + Scratch.toggleScratch); registerPaperAction("toggle-scratch", - dynamic_function_ref("toggle", - Scratch), + Scratch.toggle, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction("switch-focus-mode", - dynamic_function_ref("switchToNextFocusMode", - Tiling)); + Tiling.switchToNextFocusMode); registerPaperAction("resize-h-inc", - dynamic_function_ref("resizeHInc", - Tiling), + Tiling.resizeHInc, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction("resize-h-dec", - dynamic_function_ref("resizeHDec", - Tiling), + Tiling.resizeHDec, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction("resize-w-inc", - dynamic_function_ref("resizeWInc", - Tiling), + Tiling.resizeWInc, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction("resize-w-dec", - dynamic_function_ref("resizeWDec", - Tiling), + Tiling.resizeWDec, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction("cycle-width", - dynamic_function_ref("cycleWindowWidth", - Tiling), + Tiling.cycleWindowWidth, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction("cycle-width-backwards", - dynamic_function_ref("cycleWindowWidthBackwards", - Tiling), + Tiling.cycleWindowWidthBackwards, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction("cycle-height", - dynamic_function_ref("cycleWindowHeight", - Tiling), + Tiling.cycleWindowHeight, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction("cycle-height-backwards", - dynamic_function_ref("cycleWindowHeightBackwards", - Tiling), + Tiling.cycleWindowHeightBackwards, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction("center-horizontally", - dynamic_function_ref("centerWindowHorizontally", - Tiling), + Tiling.centerWindowHorizontally, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction('new-window', - dynamic_function_ref('duplicateWindow', App), + App.duplicateWindow, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction('close-window', - metaWindow => - metaWindow.delete(global.get_current_time()), + metaWindow => metaWindow.delete(global.get_current_time()), Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction('slurp-in', - dynamic_function_ref('slurp', - Tiling), + Tiling.slurp, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction('barf-out', - dynamic_function_ref('barf', - Tiling), + Tiling.barf, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction('toggle-maximize-width', - dynamic_function_ref("toggleMaximizeHorizontally", - Tiling), + Tiling.toggleMaximizeHorizontally, Meta.KeyBindingFlags.PER_WINDOW); registerPaperAction('paper-toggle-fullscreen', diff --git a/utils.js b/utils.js index e9915975..b69b301a 100644 --- a/utils.js +++ b/utils.js @@ -57,18 +57,6 @@ export function framestr(rect) { return `[ x:${rect.x}, y:${rect.y} w:${rect.width} h:${rect.height} ]`; } -/** - * Look up the function by name at call time. This makes it convenient to - * redefine the function without re-registering all signal handler, keybindings, - * etc. (this is like a function symbol in lisp) - */ -export function dynamic_function_ref(handler_name, owner_obj) { - return function() { - console.debug("dynamic_function_ref name", handler_name); - owner_obj[handler_name].apply(this, arguments); - }; -} - export function isPointInsideActor(actor, x, y) { return (actor.x <= x && x <= actor.x + actor.width) && (actor.y <= y && y <= actor.y + actor.height); @@ -328,20 +316,6 @@ export function isMetaWindow(obj) { return obj && obj.window_type && obj.get_compositor_private; } -export function shortTrace(skip = 0) { - let trace = new Error().stack.split("\n").map(s => { - let words = s.split(/[@/]/); - let cols = s.split(":"); - let ln = parseInt(cols[2]); - if (ln === null) - ln = "?"; - - return [words[0], ln]; - }); - trace = trace.filter(([f, ln]) => f !== "dynamic_function_ref").map(([f, ln]) => f === "" ? "?" : `${f}:${ln}`); - return trace.slice(skip + 1, skip + 5); -} - export function actor_raise(actor, above) { const parent = actor.get_parent(); if (!parent) { From 6baba3248dc2fb8c6b179449aa253420400c1c93 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 18 Sep 2023 11:57:11 +1000 Subject: [PATCH 28/50] Improved module dependency ordering for `disable` to avoid actioning a `workspaces-only-on-primary` call after PaperWM disable. --- extension.js | 6 +++--- imports.js | 18 +++++++++--------- settings.js | 44 ++++++++++++++++++++++---------------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/extension.js b/extension.js index e3cb058f..d99de495 100644 --- a/extension.js +++ b/extension.js @@ -43,14 +43,14 @@ import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js'; Notes of ordering: - several modules import settings, so settings should be before them; - settings.js should not depend on other paperwm modules; + - Settings should be before Patches (for reverse order disable); */ export default class PaperWM extends Extension { modules = [ - Utils, Settings, + Utils, Settings, Patches, Gestures, Keybindings, LiveAltTab, Navigator, Stackoverlay, Scratch, - Workspace, Tiling, Topbar, - Patches, App, + Workspace, Tiling, Topbar, App, ]; #userStylesheet = null; diff --git a/imports.js b/imports.js index 251155db..e107b3e4 100644 --- a/imports.js +++ b/imports.js @@ -1,18 +1,18 @@ export * as AcceleratorParse from './acceleratorparse.js'; -export * as Utils from './utils.js'; -export * as Settings from './settings.js'; +export * as App from './app.js'; export * as Gestures from './gestures.js'; +export * as Grab from './grab.js'; export * as Keybindings from './keybindings.js'; +export * as Lib from './lib.js'; export * as LiveAltTab from './liveAltTab.js'; +export * as Minimap from './minimap.js'; export * as Navigator from './navigator.js'; -export * as Stackoverlay from './stackoverlay.js'; +export * as Patches from './patches.js'; export * as Scratch from './scratch.js'; -export * as Workspace from './workspace.js'; +export * as Settings from './settings.js'; +export * as Stackoverlay from './stackoverlay.js'; export * as Tiling from './tiling.js'; export * as Topbar from './topbar.js'; -export * as Patches from './patches.js'; -export * as App from './app.js'; -export * as Lib from './lib.js'; -export * as Minimap from './minimap.js'; -export * as Grab from './grab.js'; +export * as Utils from './utils.js'; +export * as Workspace from './workspace.js'; diff --git a/settings.js b/settings.js index 4173e2c7..92d2ff78 100644 --- a/settings.js +++ b/settings.js @@ -15,28 +15,6 @@ const RESTORE_KEYBINDS_KEY = 'restore-keybinds'; // This is the value mutter uses for the keyvalue of above_tab const META_KEY_ABOVE_TAB = 0x2f7259c9; -export function setState($, key) { - let value = gsettings.get_value(key); - let name = key.replace(/-/g, '_'); - prefs[name] = value.deep_unpack(); -} - -export let conflictSettings; // exported -export function getConflictSettings() { - if (!conflictSettings) { - // 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" }), - ]; - } - - return conflictSettings; -} - export let prefs; let gsettings, keybindSettings, _overriddingConflicts; export function enable(extension) { @@ -86,6 +64,28 @@ export function disable() { conflictSettings = null; } +export function setState($, key) { + let value = gsettings.get_value(key); + let name = key.replace(/-/g, '_'); + prefs[name] = value.deep_unpack(); +} + +export let conflictSettings; // exported +export function getConflictSettings() { + if (!conflictSettings) { + // 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" }), + ]; + } + + return conflictSettings; +} + // / Keybindings export function accelerator_parse(keystr) { From 3c1a69096dad7ab9a562bcff45250628b640c717 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Mon, 18 Sep 2023 18:31:06 +1000 Subject: [PATCH 29/50] WIP: prefs.js --- imports.js | 1 - prefs.js | 126 ++++++++++++++++++++++++--------------------- prefsKeybinding.js | 73 +++++++++++++------------- settings.js | 2 +- winpropsPane.js | 52 +++++++++---------- workspace.js | 2 +- 6 files changed, 127 insertions(+), 129 deletions(-) diff --git a/imports.js b/imports.js index e107b3e4..472e46be 100644 --- a/imports.js +++ b/imports.js @@ -15,4 +15,3 @@ export * as Tiling from './tiling.js'; export * as Topbar from './topbar.js'; export * as Utils from './utils.js'; export * as Workspace from './workspace.js'; - diff --git a/prefs.js b/prefs.js index 834e9f70..3342d654 100644 --- a/prefs.js +++ b/prefs.js @@ -1,13 +1,20 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Settings = Extension.imports.settings; -const AcceleratorParse = Extension.imports.acceleratorparse; -const Workspace = Extension.imports.workspace; -const { Gio, GLib, GObject, Gtk, Gdk } = imports.gi; -const { KeybindingsPane } = Extension.imports.prefsKeybinding; -const { WinpropsPane } = Extension.imports.winpropsPane; +import Gdk from 'gi://Gdk'; +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; -let _ = s => s; +import { + ExtensionPreferences +} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; + +import * as Settings from './settings.js'; +import * as AcceleratorParse from './acceleratorparse.js'; +import * as Workspace from './workspace.js'; +import * as KeybindingsPane from './prefsKeybinding.js'; +import * as WinpropsPane from './winpropsPane.js'; + +const _ = s => s; // TreeStore model const COLUMN_ID = 0; @@ -20,7 +27,47 @@ const COLUMN_RESET = 6; const COLUMN_TOOLTIP = 7; // This is the value mutter uses for the keyvalue of above_tab -let META_KEY_ABOVE_TAB = 0x2f7259c9; +const META_KEY_ABOVE_TAB = 0x2f7259c9; + +export default class MyExtensionPreferences extends ExtensionPreferences { + fillPreferencesWindow(window) { + const provider = new Gtk.CssProvider(); + provider.load_from_path(`${this.path}/resources/prefs.css`); + Gtk.StyleContext.add_provider_for_display( + Gdk.Display.get_default(), + provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ); + + Workspace.enable(this); + AcceleratorParse.initKeycodeMap(); + // cleanup on prefs window close request + window.connect('close-request', () => { + Workspace.disable(); + AcceleratorParse.destroyKeycodeMap(); + }); + + let selectedWorkspace = null; + try { + const tempFile = Gio.File.new_for_path(GLib.get_tmp_dir()).get_child('paperwm.workspace'); + [, contents] = tempFile.load_contents(null); + const decoder = new TextDecoder('utf-8'); + const contentsString = decoder.decode(contents); + let workspaceN = parseInt(contentsString); + if (!isNaN(workspaceN)) { + selectedWorkspace = workspaceN; + } + tempFile.delete(null); + } catch (e) { } + + let selectedTab = selectedWorkspace !== null ? 1 : 0; + new SettingsWidget( + this, + window, + selectedTab, + selectedWorkspace || 0); + } +} function range(n) { let r = []; @@ -44,15 +91,16 @@ function getOk(okValue) { } } -var SettingsWidget = class SettingsWidget { +class SettingsWidget { /** selectedWorkspace: index of initially selected workspace in workspace settings tab selectedTab: index of initially shown tab */ - constructor(prefsWindow, selectedPage = 0, selectedWorkspace = 0) { - let wmSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' }); - this._settings = ExtensionUtils.getSettings(); - this.builder = Gtk.Builder.new_from_file(`${Extension.path}/Settings.ui`); + constructor(extension, prefsWindow, selectedPage = 0, selectedWorkspace = 0) { + this.extension = extension; + this._settings = extension.getSettings(); + const wmSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' }); + this.builder = Gtk.Builder.new_from_file(`${extension.path}/Settings.ui`); this.window = prefsWindow; const pages = [ @@ -321,7 +369,7 @@ var SettingsWidget = class SettingsWidget { // About let versionLabel = this.builder.get_object('extension_version'); - let version = Extension.metadata.version?.toString() ?? '?'; + let version = this.extension.metadata.version?.toString() ?? '?'; versionLabel.set_text(version); } @@ -377,7 +425,7 @@ var SettingsWidget = class SettingsWidget { let clearDirectory = new Gtk.Button({ icon_name: 'edit-clear-symbolic', tooltip_text: 'Clear workspace directory', - sensitive: settings.get_string('directory') != '', + sensitive: settings.get_string('directory') !== '', }); directoryBox.append(directoryChooser); directoryBox.append(clearDirectory); @@ -451,7 +499,7 @@ var SettingsWidget = class SettingsWidget { getWorkspaceName(settings, index) { return Workspace.getWorkspaceName(settings, index); } -}; +} function createRow(text, widget, signal, handler) { let margin = 12; @@ -831,45 +879,3 @@ function syncStringSetting(settings, key, callback) { }); callback(settings.get_string(key)); } - -/** - * This init() is called when opening PaperWM settings/pref panes - * (not when initialising the extension on login). - */ -function init() { - -} - -function fillPreferencesWindow(window) { - const provider = new Gtk.CssProvider(); - provider.load_from_path(`${Extension.path}/resources/prefs.css`); - Gtk.StyleContext.add_provider_for_display( - Gdk.Display.get_default(), - provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - ); - - Workspace.enable(); - AcceleratorParse.initKeycodeMap(); - // cleanup on prefs window close request - window.connect('close-request', () => { - Workspace.disable(); - AcceleratorParse.destroyKeycodeMap(); - }); - - let selectedWorkspace = null; - try { - const tempFile = Gio.File.new_for_path(GLib.get_tmp_dir()).get_child('paperwm.workspace'); - [, contents] = tempFile.load_contents(null); - const decoder = new TextDecoder('utf-8'); - const contentsString = decoder.decode(contents); - let workspaceN = parseInt(contentsString); - if (!isNaN(workspaceN)) { - selectedWorkspace = workspaceN; - } - tempFile.delete(null); - } catch (e) { } - - let selectedTab = selectedWorkspace !== null ? 1 : 0; - new SettingsWidget(window, selectedTab, selectedWorkspace || 0); -} diff --git a/prefsKeybinding.js b/prefsKeybinding.js index 6f40aea2..379ac40d 100644 --- a/prefsKeybinding.js +++ b/prefsKeybinding.js @@ -1,16 +1,11 @@ -'use strict'; +import Gdk from 'gi://Gdk'; +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; -const Gdk = imports.gi.Gdk; +import * as Settings from './settings.js'; -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Settings = Extension.imports.settings; - -// TODO gettext translations const _ = s => s; const KEYBINDINGS_KEY = 'org.gnome.shell.extensions.paperwm.keybindings'; @@ -103,7 +98,7 @@ const forbiddenKeyvals = [ ]; function isValidBinding(combo) { - if ((combo.mods == 0 || combo.mods == Gdk.ModifierType.SHIFT_MASK) && combo.keycode != 0) { + if ((combo.mods === 0 || combo.mods === Gdk.ModifierType.SHIFT_MASK) && combo.keycode !== 0) { const keyval = combo.keyval; if ((keyval >= Gdk.KEY_a && keyval <= Gdk.KEY_z) || (keyval >= Gdk.KEY_A && keyval <= Gdk.KEY_Z) || @@ -115,7 +110,7 @@ function isValidBinding(combo) { (keyval >= Gdk.KEY_hebrew_doublelowline && keyval <= Gdk.KEY_hebrew_taf) || (keyval >= Gdk.KEY_Thai_kokai && keyval <= Gdk.KEY_Thai_lekkao) || (keyval >= Gdk.KEY_Hangul_Kiyeog && keyval <= Gdk.KEY_Hangul_J_YeorinHieuh) || - (keyval == Gdk.KEY_space && combo.mods == 0) || + (keyval === Gdk.KEY_space && combo.mods === 0) || forbiddenKeyvals.includes(keyval)) { return false; } @@ -123,7 +118,7 @@ function isValidBinding(combo) { // Allow Tab in addition to accelerators allowed by GTK if (!Gtk.accelerator_valid(combo.keyval, combo.mods) && - (combo.keyval != Gdk.KEY_Tab || combo.mods == 0)) { + (combo.keyval !== Gdk.KEY_Tab || combo.mods === 0)) { return false; } @@ -131,7 +126,7 @@ function isValidBinding(combo) { } function isEmptyBinding(combo) { - return combo.keyval == 0 && combo.mods == 0 && combo.keycode == 0; + return combo.keyval === 0 && combo.mods === 0 && combo.keycode === 0; } const Combo = GObject.registerClass({ @@ -320,7 +315,7 @@ const Keybinding = GObject.registerClass({ .map(c => c.label); let label = ''; - if (labels.length == 0) { + if (labels.length === 0) { label = _('Disabled'); } else { label = labels.join(', '); @@ -338,7 +333,7 @@ const Keybinding = GObject.registerClass({ } get modified() { - return this._settings.get_user_value(this.action) != null; + return this._settings.get_user_value(this.action) !== null; } get enabled() { @@ -372,7 +367,7 @@ const Keybinding = GObject.registerClass({ if (!found) return; this.combos.remove(pos); - if (this.combos.get_n_items() == 0) + if (this.combos.get_n_items() === 0) this.combos.append(new Combo()); this._store(); } @@ -402,7 +397,7 @@ const Keybinding = GObject.registerClass({ find(combo) { const pos = [...this.combos].findIndex(c => c.keystr === combo.keystr); - if (pos == -1) { + if (pos === -1) { return [false]; } else { return [true, pos]; @@ -414,14 +409,14 @@ const Keybinding = GObject.registerClass({ let combos = keystrs .map(this._translateAboveTab) .map(keystr => { - if (keystr != '') + if (keystr !== '') return Settings.accelerator_parse(keystr); else return [true, 0, 0]; }) .map(([, keyval, mods]) => new Combo({ keyval, mods })); - if (combos.length == 0) { + if (combos.length === 0) { combos.push(new Combo()); } @@ -432,7 +427,7 @@ const Keybinding = GObject.registerClass({ let filtered = [...this.combos] .filter(c => !isEmptyBinding(c)) .map(c => c.keystr); - if (filtered.length == 0) { + if (filtered.length === 0) { filtered = ['']; } this._settings.set_strv(this.action, filtered); @@ -452,7 +447,7 @@ const Keybinding = GObject.registerClass({ } }); -var KeybindingsModel = GObject.registerClass({ +export const KeybindingsModel = GObject.registerClass({ GTypeName: 'KeybindingsModel', Implements: [Gio.ListModel], Signals: { @@ -477,7 +472,9 @@ var KeybindingsModel = GObject.registerClass({ this._actionToBinding = new Map(); this._settings = ExtensionUtils.getSettings(KEYBINDINGS_KEY); - GLib.idle_add(0, () => { this.load(); }); + GLib.idle_add(0, () => { + this.load(); + }); } vfunc_get_item_type() { @@ -563,7 +560,7 @@ var KeybindingsModel = GObject.registerClass({ const ComboRow = GObject.registerClass({ GTypeName: 'ComboRow', - Template: Extension.dir.get_child('KeybindingsComboRow.ui').get_uri(), + Template: GLib.uri_resolve_relative(import.meta.url, './KeybindingsComboRow.ui', GLib.UriFlags.NONE), InternalChildren: [ 'stack', 'shortcutPage', @@ -633,7 +630,7 @@ const ComboRow = GObject.registerClass({ } set combo(value) { - if (value && this._combo && this._combo.keystr == value.keystr) + if (value && this._combo && this._combo.keystr === value.keystr) return; this._combo = value; this.notify('combo'); @@ -704,16 +701,16 @@ const ComboRow = GObject.registerClass({ let keyvalLower = Gdk.keyval_to_lower(keyval); // Normalize - if (keyvalLower == Gdk.KEY_ISO_Left_Tab) { + if (keyvalLower === Gdk.KEY_ISO_Left_Tab) { keyvalLower = Gdk.KEY_Tab; } // Put Shift back if it changed the case of the key - if (keyvalLower != keyval) { + if (keyvalLower !== keyval) { modmask |= Gdk.ModifierType.SHIFT_MASK; } - if (keyvalLower == Gdk.KEY_Sys_Req && (modmask & Gdk.ModifierType.ALT_MASK) != 0) { + if (keyvalLower === Gdk.KEY_Sys_Req && (modmask & Gdk.ModifierType.ALT_MASK) !== 0) { // Don't allow SysRq as a keybinding, but allow Alt+Print keyvalLower = Gdk.KEY_Print; } @@ -722,7 +719,7 @@ const ComboRow = GObject.registerClass({ const isModifier = event.is_modifier(); // Escape cancels - if (!isModifier && modmask == 0 && keyvalLower == Gdk.KEY_Escape) { + if (!isModifier && modmask === 0 && keyvalLower === Gdk.KEY_Escape) { this.editing = false; if (this.combo.placeholder) { this.keybinding.remove(this.combo); @@ -731,7 +728,7 @@ const ComboRow = GObject.registerClass({ } // Backspace deletes - if (!isModifier && modmask == 0 && keyvalLower == Gdk.KEY_BackSpace) { + if (!isModifier && modmask === 0 && keyvalLower === Gdk.KEY_BackSpace) { this._updateKeybinding(new Combo()); return Gdk.EVENT_STOP; } @@ -768,7 +765,9 @@ const ComboRow = GObject.registerClass({ } _updateState() { - if (!this._stack) { return; } + if (!this._stack) { + return; + } if (this.editing) { this.add_css_class('editing'); @@ -794,7 +793,7 @@ const ComboRow = GObject.registerClass({ const KeybindingsRow = GObject.registerClass({ GTypeName: 'KeybindingsRow', - Template: Extension.dir.get_child('KeybindingsRow.ui').get_uri(), + Template: GLib.uri_resolve_relative(import.meta.url, './KeybindingsRow.ui', GLib.UriFlags.NONE), InternalChildren: [ 'header', 'descLabel', @@ -895,7 +894,7 @@ const KeybindingsRow = GObject.registerClass({ } get collisions() { - if (this._collisions == undefined) { + if (this._collisions === undefined) { this._collisions = new Map(); } return this._collisions; @@ -961,9 +960,9 @@ const KeybindingsRow = GObject.registerClass({ } }); -var KeybindingsPane = GObject.registerClass({ +export const KeybindingsPane = GObject.registerClass({ GTypeName: 'KeybindingsPane', - Template: Extension.dir.get_child('KeybindingsPane.ui').get_uri(), + Template: GLib.uri_resolve_relative(import.meta.url, './KeybindingsPane.ui', GLib.UriFlags.NONE), InternalChildren: [ 'search', 'listbox', @@ -1045,7 +1044,7 @@ var KeybindingsPane = GObject.registerClass({ _onSetHeader(row, before, data) { const header = row.get_header(); - if (!before || before.keybinding.section != row.keybinding.section) { + if (!before || before.keybinding.section !== row.keybinding.section) { if (!header || header instanceof Gtk.Separator) { row.set_header(this._createHeader(row, before)); } diff --git a/settings.js b/settings.js index 92d2ff78..29066889 100644 --- a/settings.js +++ b/settings.js @@ -1,7 +1,7 @@ import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; -import { AcceleratorParse } from './imports.js'; +import * as AcceleratorParse from './acceleratorparse.js'; /** Settings utility shared between the running extension and the preference UI. diff --git a/winpropsPane.js b/winpropsPane.js index 3677e01c..73e9b120 100644 --- a/winpropsPane.js +++ b/winpropsPane.js @@ -1,17 +1,10 @@ -'use strict'; +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - -const ExtensionUtils = imports.misc.extensionUtils; -const Extension = ExtensionUtils.getCurrentExtension(); -const Settings = Extension.imports.settings; - -var WinpropsPane = GObject.registerClass({ +export const WinpropsPane = GObject.registerClass({ GTypeName: 'WinpropsPane', - Template: Extension.dir.get_child('WinpropsPane.ui').get_uri(), + Template: GLib.uri_resolve_relative(import.meta.url, './WinpropsPane.ui', GLib.UriFlags.NONE), InternalChildren: [ 'search', 'listbox', @@ -20,7 +13,7 @@ var WinpropsPane = GObject.registerClass({ ], Signals: { 'changed': {}, - } + }, }, class WinpropsPane extends Gtk.Box { _init(params = {}) { super._init(params); @@ -67,17 +60,19 @@ var WinpropsPane = GObject.registerClass({ } _createRow(winprop) { - let wp = winprop ?? {wm_class:''}; - const row = new WinpropsRow({winprop : wp}); + let wp = winprop ?? { wm_class: '' }; + const row = new WinpropsRow({ winprop: wp }); this.rows.push(row); - row.connect('notify::expanded', (row) => this._onRowExpanded(row)); - row.connect('row-deleted', (row) => this._removeRow(row)); + row.connect('notify::expanded', row => this._onRowExpanded(row)); + row.connect('row-deleted', row => this._removeRow(row)); row.connect('changed', () => this.emit('changed')); return row; } _onRowActivated(list, row) { - if (!row.is_focus()) return; + if (!row.is_focus()) { + return; + } row.expanded = !row.expanded; } @@ -93,9 +88,9 @@ var WinpropsPane = GObject.registerClass({ } }); -var WinpropsRow = GObject.registerClass({ +export const WinpropsRow = GObject.registerClass({ GTypeName: 'WinpropsRow', - Template: Extension.dir.get_child('WinpropsRow.ui').get_uri(), + Template: GLib.uri_resolve_relative(import.meta.url, './WinpropsRow.ui', GLib.UriFlags.NONE), InternalChildren: [ 'header', 'descLabel', @@ -113,7 +108,7 @@ var WinpropsRow = GObject.registerClass({ 'winprop', 'winprop', 'Winprop', - GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, + GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY ), expanded: GObject.ParamSpec.boolean( 'expanded', @@ -126,14 +121,14 @@ var WinpropsRow = GObject.registerClass({ Signals: { 'changed': {}, 'row-deleted': {}, - } + }, }, class WinpropsRow extends Gtk.ListBoxRow { _init(params = {}) { - super._init(params); + super._init(params); // description label this._setDescLabel(); - + // set the values to current state and connect to 'changed' signal this._wmClass.set_text(this.winprop.wm_class ?? ''); this._wmClass.connect('changed', () => { @@ -148,7 +143,7 @@ var WinpropsRow = GObject.registerClass({ this._title.connect('changed', () => { this.checkHasWmClassOrTitle(); this.winprop.title = this._title.get_text(); - this._setDescLabel(); + this._setDescLabel(); this.emit('changed'); }); @@ -161,7 +156,7 @@ var WinpropsRow = GObject.registerClass({ this._preferredWidth.set_sensitive(!isActive); this.emit('changed'); - }) + }); this._preferredWidth.set_text(this.winprop.preferredWidth ?? ''); // if scratchLayer is active then users can't edit preferredWidth @@ -174,7 +169,7 @@ var WinpropsRow = GObject.registerClass({ let digits = (value.match(/\d+/) ?? [null])[0]; let isPercent = /^.*%$/.test(value); let isPixel = /^.*px$/.test(value); - + // check had valid number if (!digits) { this._setError(this._preferredWidth); @@ -288,10 +283,9 @@ var WinpropsRow = GObject.registerClass({ // if wmClass, use that, otherwise use title (fallback) if (this.winprop.wm_class) { this._descLabel.label = this.winprop.wm_class; - } + } else if (this.winprop.title) { this._descLabel.label = this.winprop.title; - return; } } diff --git a/workspace.js b/workspace.js index f5a2c799..af461e72 100644 --- a/workspace.js +++ b/workspace.js @@ -1,7 +1,7 @@ import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; -import { Lib } from './imports.js'; +import * as Lib from './lib.js'; /** * Workspace related utility functions used by other modules. From d2aaab8e827b92d38751ee745272c2f32c6aef3c Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Tue, 19 Sep 2023 07:48:11 +1000 Subject: [PATCH 30/50] WIP: keybindings_pane, passing keyboard settings schema. --- Settings.ui | 2 +- prefs.js | 8 ++++++++ prefsKeybinding.js | 29 ++++++++++++++++++----------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Settings.ui b/Settings.ui index c61c864d..314ce2e3 100644 --- a/Settings.ui +++ b/Settings.ui @@ -945,7 +945,7 @@ Keybindings emblem-system-symbolic - + diff --git a/prefs.js b/prefs.js index 3342d654..6890a7e6 100644 --- a/prefs.js +++ b/prefs.js @@ -31,6 +31,8 @@ const META_KEY_ABOVE_TAB = 0x2f7259c9; export default class MyExtensionPreferences extends ExtensionPreferences { fillPreferencesWindow(window) { + window.set_default_size(-1, -1); + const provider = new Gtk.CssProvider(); provider.load_from_path(`${this.path}/resources/prefs.css`); Gtk.StyleContext.add_provider_for_display( @@ -338,7 +340,13 @@ class SettingsWidget { workspaceCombo.set_active(selectedWorkspace); + // Keybindings + + let keybindingsPane = this.builder.get_object('keybindings_pane'); + keybindingsPane.init(extension); + // Winprops + let winprops = this._settings.get_value('winprops').deep_unpack() .map(p => JSON.parse(p)); // sort a little nicer diff --git a/prefsKeybinding.js b/prefsKeybinding.js index 379ac40d..904107d0 100644 --- a/prefsKeybinding.js +++ b/prefsKeybinding.js @@ -290,9 +290,9 @@ const Keybinding = GObject.registerClass({ changed: {}, }, }, class Keybinding extends GObject.Object { - _init(params = {}) { + _init(params = {}, settings) { super._init(params); - this._settings = ExtensionUtils.getSettings(KEYBINDINGS_KEY); + this._settings = settings; this._description = _(this._settings.settings_schema.get_key(this.action).get_summary()); this._combos = new Gio.ListStore(); @@ -471,10 +471,11 @@ export const KeybindingsModel = GObject.registerClass({ }); this._actionToBinding = new Map(); - this._settings = ExtensionUtils.getSettings(KEYBINDINGS_KEY); - GLib.idle_add(0, () => { - this.load(); - }); + } + + setSettings(settings) { + this._settings = settings; + this.load(); } vfunc_get_item_type() { @@ -512,7 +513,7 @@ export const KeybindingsModel = GObject.registerClass({ const binding = new Keybinding({ section, action, - }); + }, this._settings); bindings.push(binding); this._actionToBinding.set(action, binding); } @@ -970,8 +971,11 @@ export const KeybindingsPane = GObject.registerClass({ }, class KeybindingsPane extends Gtk.Box { _init(params = {}) { super._init(params); + } - this._bindings = new KeybindingsModel(); + init(extension) { + this._settings = extension.getSettings(KEYBINDINGS_KEY); + this._model = new KeybindingsModel(); this._filter = new Gtk.StringFilter({ expression: Gtk.PropertyExpression.new(Keybinding.$gtype, null, 'description'), @@ -980,7 +984,7 @@ export const KeybindingsPane = GObject.registerClass({ }); const filteredBindings = new Gtk.FilterListModel({ - model: this._bindings, + model: this._model, filter: this._filter, }); @@ -988,6 +992,9 @@ export const KeybindingsPane = GObject.registerClass({ this._listbox.set_header_func((row, before, data) => this._onSetHeader(row, before, data)); this._expandedRow = null; + + // send settings to model (which processes and creates rows) + this._model.setSettings(this._settings); } _createHeader(row, before) { @@ -1008,14 +1015,14 @@ export const KeybindingsPane = GObject.registerClass({ } _createRow(keybinding) { - const row = new KeybindingsRow({ keybindings: this._bindings, keybinding }); + const row = new KeybindingsRow({ keybindings: this._model, keybinding }); row.connect('notify::expanded', row => this._onRowExpanded(row)); row.connect('collision-activated', (_, binding) => this._onCollisionActivated(binding)); return row; } _onCollisionActivated(keybinding) { - const [found, pos] = this._bindings.find(keybinding); + const [found, pos] = this._model.find(keybinding); if (found) { const row = this._listbox.get_row_at_index(pos); row.activate(); From a5709d81b23f7bf2acdf21f5cc01bb459848b3ef Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Tue, 19 Sep 2023 21:57:35 +1000 Subject: [PATCH 31/50] Pres.js window improvements. --- KeybindingsPane.ui | 2 +- Settings.ui | 1191 ++++++++++++++++++++++---------------------- WinpropsPane.ui | 2 +- prefs.js | 3 +- 4 files changed, 604 insertions(+), 594 deletions(-) diff --git a/KeybindingsPane.ui b/KeybindingsPane.ui index 04605bab..bb7d51e6 100644 --- a/KeybindingsPane.ui +++ b/KeybindingsPane.ui @@ -25,7 +25,7 @@ True 36 36 - 12 + 16 36 480 + True - - False - False + + center + 36 + 36 + 16 + 36 + vertical + 12 + 480 - - False - 12 - 12 - 6 - 6 - 32 - - - False - 1 - Gap between windows - 0 - - 0 - 0 - - - - - - 2 - 2 - window_gap - 1 - 1 - if-valid - - 1 - 0 - - - + + start + True + Gaps and margins + + + - - - - - False - False - - + False - The minimum margin to the left and right monitor edge - 12 - 12 - 6 - 6 - 32 - - + none + 16 + + + + False False - 1 - Horizontal margin - 0 - - 0 - 0 - + + + False + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Gap between windows + 0 + + 0 + 0 + + + + + + 2 + 2 + window_gap + 1 + 1 + if-valid + + 1 + 0 + + + + + - - 2 - 2 - 0 - horizontal_margin - 1 - 1 - if-valid - - 1 - 0 - - - - - - - - - - False - False - - - False - 12 - 12 - 6 - 6 - 32 - - + + False False - 1 - Top margin - 0 - - 0 - 0 - - - - - - 2 - 2 - 0 - vertical_margin - 1 - 1 - if-valid - - 1 - 0 - + + + + False + The minimum margin to the left and right monitor edge + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Horizontal margin + 0 + + 0 + 0 + + + + + + 2 + 2 + 0 + horizontal_margin + 1 + 1 + if-valid + + 1 + 0 + + + + + - - - - - - - False - False - - - False - 12 - 12 - 6 - 6 - 32 - + + False False - 1 - Bottom margin - 0 - - 0 - 0 - + + + False + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Top margin + 0 + + 0 + 0 + + + + + + 2 + 2 + 0 + vertical_margin + 1 + 1 + if-valid + + 1 + 0 + + + + + - - 2 - 2 - 0 - vertical_margin_bottom - 1 - 1 - if-valid - - 1 - 0 - - - - - - - - - - False - False - Semicolon separated values of "useful window widths" that will be cycled through. Values types can be either percentage (of available screen width), e.g. "50%" or pixel values, e.g. "500px". Mixed value types are not supported. - - - False - 12 - 12 - 6 - 6 - 32 - - + + False False - 1 - Useful window widths - 0 - - 0 - 0 - - - - - - - 1 - 0 - - - 8 - reset - Resets width values to the default PaperWM width values + + False + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Bottom margin + 0 + + 0 + 0 + + + + + + 2 + 2 + 0 + vertical_margin_bottom + 1 + 1 + if-valid + + 1 + 0 + + + - - - 24 - 24 - - 2 - 0 - - - - - - - - - - - - False - False - Semicolon separated values of "useful window heights" that will be cycled through. Values types can be either percentage (of available screen width), e.g. "50%" or pixel values, e.g. "500px". Mixed value types are not supported. - - - False - 12 - 12 - 6 - 6 - 32 - - - False - 1 - Useful window heights - 0 - - 0 - 0 - - - - 1 - 0 - - - - 8 - reset - Resets height values to the default PaperWM height values - - + + False + False + Semicolon separated values of "useful window widths" that will be cycled through. Values types can be either percentage (of available screen width), e.g. "50%" or pixel values, e.g. "500px". Mixed value types are not supported. - - 24 - 24 - - 1 - 0 - + + False + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Useful window widths + 0 + + 0 + 0 + + + + + + + 1 + 0 + + + + 8 + reset + Resets width values to the default PaperWM width values + + + + + 24 + 24 + + 2 + 0 + + + + + - - - - - - - - - - - start - True - Three-finger swipes - - - - - - - - False - none - 24 - - - - False - False - - - False - 12 - 12 - 6 - 6 - 12 - 32 - - - False - 1 - Horizontal sensitivity - 0 - - 0 - 0 - - - - - - True - True - 2 - 2 - 0 - horizontal-sensitivity-adjustment - 1 - 1 - 1 - if-valid - - 1 - 0 - - + + False False - 1 - Horizontal friction - 0 - - 0 - 1 - - - - - - 2 - 2 - 0,0 - horizontal-friction-adjustment - 1 - 1 - 1 - if-valid - - 1 - 1 - + Semicolon separated values of "useful window heights" that will be cycled through. Values types can be either percentage (of available screen width), e.g. "50%" or pixel values, e.g. "500px". Mixed value types are not supported. + + + False + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Useful window heights + 0 + + 0 + 0 + + + + + + + 1 + 0 + + + + 8 + reset + Resets height values to the default PaperWM height values + + + + + 24 + 24 + + 1 + 0 + + + + + + + - - - - - False - False - - False - 12 - 12 - 6 - 6 - 12 - 32 - - - False - 1 - Vertical sensitivity - 0 - - 0 - 0 - - - - - - 2 - 2 - 0 - vertical-sensitivity-adjustment - 1 - 1 - 1 - if-valid - - 1 - 0 - - - - - - False - 1 - Vertical friction - 0 - - 0 - 1 - - - - - - 2 - 2 - 0,0 - vertical-friction-adjustment - 1 - 1 - 1 - if-valid - - 1 - 1 - - - + + start + True + Three-finger swipes + + + - - - - - - - start - True - Settings - - - - - - - - False - none - - - - False - False - + False - Sets the duration of PaperWM animated transitions (e.g. switching windows, workspaces etc.). Lower values result in faster transitions. - 12 - 12 - 6 - 6 - 32 - - + none + 16 + + + + False False - 1 - Animation / transition time (seconds) - 1 - 0 - - 0 - 0 - + + + False + 12 + 12 + 6 + 6 + 12 + 32 + + + False + 1 + Horizontal sensitivity + 0 + + 0 + 0 + + + + + + True + True + 2 + 2 + 0 + horizontal-sensitivity-adjustment + 1 + 1 + 1 + if-valid + + 1 + 0 + + + + + + False + 1 + Horizontal friction + 0 + + 0 + 1 + + + + + + 2 + 2 + 0,0 + horizontal-friction-adjustment + 1 + 1 + 1 + if-valid + + 1 + 1 + + + + + - - 3 - 3 - animation_time_adjustment - 1 - 2 - 1 - if-valid - - 1 - 0 - + + False + False + + + False + 12 + 12 + 6 + 6 + 12 + 32 + + + False + 1 + Vertical sensitivity + 0 + + 0 + 0 + + + + + + 2 + 2 + 0 + vertical-sensitivity-adjustment + 1 + 1 + 1 + if-valid + + 1 + 0 + + + + + + False + 1 + Vertical friction + 0 + + 0 + 1 + + + + + + 2 + 2 + 0,0 + vertical-friction-adjustment + 1 + 1 + 1 + if-valid + + 1 + 1 + + + + + - - - - - False - False - - False - This setting controls the "size" of mini-map tiles as compared to their actual window size (e.g. "15" corresponds to a mini-map tile size being approximately 15% of the actual window size) - 12 - 12 - 6 - 6 - 32 - - - False - 1 - Mini-map scale <i>(0 hides Mini-map)</i> - 1 - 0 - - 0 - 0 - - - - - - 2 - 2 - minimap_scale - 1 - 1 - if-valid - - 1 - 0 - - - + + start + True + Settings + + + - - - - - False - False - + False - 12 - 12 - 6 - 6 - 32 + none + - + + False False - 1 - Show scratch windows in overview - 0 - - 0 - 0 - + + + False + Sets the duration of PaperWM animated transitions (e.g. switching windows, workspaces etc.). Lower values result in faster transitions. + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Animation / transition time (seconds) + 1 + 0 + + 0 + 0 + + + + + + 3 + 3 + animation_time_adjustment + 1 + 2 + 1 + if-valid + + 1 + 0 + + + + + - + + False False - 0 - - Always - Only - Never - - - 1 - 0 - + + + False + This setting controls the "size" of mini-map tiles as compared to their actual window size (e.g. "15" corresponds to a mini-map tile size being approximately 15% of the actual window size) + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Mini-map scale <i>(0 hides Mini-map)</i> + 1 + 0 + + 0 + 0 + + + + + + 2 + 2 + minimap_scale + 1 + 1 + if-valid + + 1 + 0 + + + + + - - - - - - - False - False - - - False - 12 - 12 - 6 - 6 - 32 - + + False False - 1 - Enable Window Position Bar - 0 - - 0 - 0 - + + + False + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Show scratch windows in overview + 0 + + 0 + 0 + + + + + + False + 0 + + Always + Only + Never + + + 1 + 0 + + + + + - - - 1 - 0 - + + False + False + + + False + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Enable Window Position Bar + 0 + + 0 + 0 + + + + + + + 1 + 0 + + + + + @@ -738,7 +749,7 @@ center 36 36 - 36 + 16 36 vertical 12 @@ -757,7 +768,7 @@ False none - 24 + 16 diff --git a/WinpropsPane.ui b/WinpropsPane.ui index f67c34cf..9bc55713 100644 --- a/WinpropsPane.ui +++ b/WinpropsPane.ui @@ -54,7 +54,7 @@ True 36 36 - 12 + 16 36 480 True diff --git a/prefs.js b/prefs.js index 6890a7e6..3a20bdd9 100644 --- a/prefs.js +++ b/prefs.js @@ -31,8 +31,6 @@ const META_KEY_ABOVE_TAB = 0x2f7259c9; export default class MyExtensionPreferences extends ExtensionPreferences { fillPreferencesWindow(window) { - window.set_default_size(-1, -1); - const provider = new Gtk.CssProvider(); provider.load_from_path(`${this.path}/resources/prefs.css`); Gtk.StyleContext.add_provider_for_display( @@ -63,6 +61,7 @@ export default class MyExtensionPreferences extends ExtensionPreferences { } catch (e) { } let selectedTab = selectedWorkspace !== null ? 1 : 0; + window.set_size_request(626, 700); new SettingsWidget( this, window, From 53155a948945279fc3e6df81d1696b9c2b593962 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Tue, 19 Sep 2023 22:56:04 +1000 Subject: [PATCH 32/50] Large pref.js clean and refactored functions into class. --- prefs.js | 482 +++++++++---------------------------------------------- 1 file changed, 73 insertions(+), 409 deletions(-) diff --git a/prefs.js b/prefs.js index 3a20bdd9..6ec47af0 100644 --- a/prefs.js +++ b/prefs.js @@ -1,14 +1,12 @@ import Gdk from 'gi://Gdk'; import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; import Gtk from 'gi://Gtk'; import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; -import * as Settings from './settings.js'; import * as AcceleratorParse from './acceleratorparse.js'; import * as Workspace from './workspace.js'; import * as KeybindingsPane from './prefsKeybinding.js'; @@ -16,18 +14,9 @@ import * as WinpropsPane from './winpropsPane.js'; const _ = s => s; -// TreeStore model -const COLUMN_ID = 0; -const COLUMN_INDEX = 1; -const COLUMN_DESCRIPTION = 2; -const COLUMN_KEY = 3; -const COLUMN_MODS = 4; -const COLUMN_WARNING = 5; -const COLUMN_RESET = 6; -const COLUMN_TOOLTIP = 7; +export class Prefs { -// This is the value mutter uses for the keyvalue of above_tab -const META_KEY_ABOVE_TAB = 0x2f7259c9; +} export default class MyExtensionPreferences extends ExtensionPreferences { fillPreferencesWindow(window) { @@ -50,7 +39,7 @@ export default class MyExtensionPreferences extends ExtensionPreferences { let selectedWorkspace = null; try { const tempFile = Gio.File.new_for_path(GLib.get_tmp_dir()).get_child('paperwm.workspace'); - [, contents] = tempFile.load_contents(null); + let [, contents] = tempFile.load_contents(null); const decoder = new TextDecoder('utf-8'); const contentsString = decoder.decode(contents); let workspaceN = parseInt(contentsString); @@ -70,28 +59,6 @@ export default class MyExtensionPreferences extends ExtensionPreferences { } } -function range(n) { - let r = []; - for (let i = 0; i < n; i++) - r.push(i); - return r; -} - -function swapArrayElements(array, i, j) { - let iVal = array[i]; - array[i] = array[j]; - array[j] = iVal; - return array; -} - -function getOk(okValue) { - if (okValue[0]) { - return okValue[1]; - } else { - return null; - } -} - class SettingsWidget { /** selectedWorkspace: index of initially selected workspace in workspace settings tab @@ -290,10 +257,10 @@ class SettingsWidget { // stack at construction time.. (!) // Ensure the initially selected workspace is added to the stack // first as a workaround. - let wsIndices = range(nWorkspaces); + let wsIndices = this.range(nWorkspaces); let wsSettingsByIndex = wsIndices.map(i => Workspace.getWorkspaceSettings(i)[1]); let wsIndicesSelectedFirst = - swapArrayElements(wsIndices.slice(), 0, selectedWorkspace); + this.swapArrayElements(wsIndices.slice(), 0, selectedWorkspace); for (let i of wsIndicesSelectedFirst) { let view = this.createWorkspacePage(wsSettingsByIndex[i], i); @@ -380,6 +347,20 @@ class SettingsWidget { versionLabel.set_text(version); } + range(n) { + let r = []; + for (let i = 0; i < n; i++) + r.push(i); + return r; + } + + swapArrayElements(array, i, j) { + let iVal = array[i]; + array[i] = array[j]; + array[j] = iVal; + return array; + } + createWorkspacePage(settings, index) { let list = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, @@ -391,7 +372,7 @@ class SettingsWidget { // Background let backgroundBox = new Gtk.Box({ spacing: 16 }); - let background = createFileChooserButton( + let background = this.createFileChooserButton( settings, 'background', 'image-x-generic', @@ -416,7 +397,7 @@ class SettingsWidget { let hideTopBarSwitch = new Gtk.Switch({ active: !settings.get_boolean('show-top-bar') }); let directoryBox = new Gtk.Box({ spacing: 16 }); - let directoryChooser = createFileChooserButton( + let directoryChooser = this.createFileChooserButton( settings, 'directory', 'folder', @@ -437,11 +418,11 @@ class SettingsWidget { directoryBox.append(directoryChooser); directoryBox.append(clearDirectory); - list.append(createRow('Name', nameEntry)); - list.append(createRow('Color', colorButton)); - list.append(createRow('Background', backgroundBox)); - list.append(createRow('Hide top bar', hideTopBarSwitch)); - list.append(createRow('Directory', directoryBox)); + list.append(this.createRow('Name', nameEntry)); + list.append(this.createRow('Color', colorButton)); + list.append(this.createRow('Background', backgroundBox)); + list.append(this.createRow('Hide top bar', hideTopBarSwitch)); + list.append(this.createRow('Directory', directoryBox)); let rgba = new Gdk.RGBA(); let color = settings.get_string('color'); @@ -506,383 +487,66 @@ class SettingsWidget { getWorkspaceName(settings, index) { return Workspace.getWorkspaceName(settings, index); } -} - -function createRow(text, widget, signal, handler) { - let margin = 12; - let box = new Gtk.Box({ - margin_start: margin, margin_end: margin, - margin_top: margin / 2, margin_bottom: margin / 2, - orientation: Gtk.Orientation.HORIZONTAL, - }); - let label = new Gtk.Label({ - label: text, hexpand: true, xalign: 0, - }); - - box.append(label); - box.append(widget); - - return box; -} - -function createKeybindingSection(settings, searchEntry) { - let model = new Gtk.ListStore(); -} - -function createKeybindingWidget(settings, searchEntry) { - let model = new Gtk.TreeStore(); - let filteredModel = new Gtk.TreeModelFilter({ child_model: model }); - filteredModel.set_visible_func( - (model, iter) => { - let desc = model.get_value(iter, COLUMN_DESCRIPTION); - - if (getOk(model.iter_parent(iter)) || desc === null) { - return true; - } - - let query = searchEntry.get_chars(0, -1).toLowerCase().split(" "); - let descLc = desc.toLowerCase(); - return query.every(word => descLc.indexOf(word) > -1); - } - ); - - model.set_column_types( - [ - // GObject.TYPE_BOOLEAN, // COLUMN_VISIBLE - GObject.TYPE_STRING, // COLUMN_ID - GObject.TYPE_INT, // COLUMN_INDEX - GObject.TYPE_STRING, // COLUMN_DESCRIPTION - GObject.TYPE_INT, // COLUMN_KEY - GObject.TYPE_INT, // COLUMN_MODS - GObject.TYPE_BOOLEAN, // COLUMN_WARNING - GObject.TYPE_BOOLEAN, // COLUMN_RESET - GObject.TYPE_STRING, // COLUMN_TOOLTIP - ]); - - let treeView = new Gtk.TreeView(); - treeView.set_enable_search(false); - treeView.model = filteredModel; - treeView.headers_visible = false; - treeView.margin_start = 12; - treeView.margin_end = 12; - treeView.search_column = COLUMN_DESCRIPTION; - treeView.tooltip_column = COLUMN_TOOLTIP; - - let descriptionRenderer = new Gtk.CellRendererText(); - let descriptionColumn = new Gtk.TreeViewColumn(); - descriptionColumn.expand = true; - descriptionColumn.pack_start(descriptionRenderer, true); - descriptionColumn.add_attribute(descriptionRenderer, "text", COLUMN_DESCRIPTION); - - treeView.append_column(descriptionColumn); - - let warningRenderer = new Gtk.CellRendererPixbuf(); - warningRenderer.mode = Gtk.CellRendererMode.INERT; - warningRenderer.stock_id = 'gtk-dialog-warning'; - let warningColumn = new Gtk.TreeViewColumn(); - warningColumn.pack_start(warningRenderer, true); - warningColumn.add_attribute(warningRenderer, "visible", COLUMN_WARNING); - - treeView.append_column(warningColumn); - - let accelRenderer = new Gtk.CellRendererAccel(); - accelRenderer.accel_mode = Gtk.CellRendererAccelMode.GTK; - accelRenderer.editable = true; - - accelRenderer.connect("accel-edited", - (accelRenderer, path, key, mods, hwCode) => { - let iter = getOk(filteredModel.get_iter_from_string(path)); - if (!iter) - return; - - iter = filteredModel.convert_iter_to_child_iter(iter); - - // Update the UI. - model.set(iter, [COLUMN_KEY, COLUMN_MODS], [key, mods]); - - // Update the stored setting. - let id = model.get_value(iter, COLUMN_ID); - let index = model.get_value(iter, COLUMN_INDEX); - let accelString = Gtk.accelerator_name(key, mods); - - let accels = settings.get_strv(id); - - if (index === -1) { - accels.push(accelString); - } else { - accels[index] = accelString; - } - settings.set_strv(id, accels); - - let newEmptyRow = null, parent; - if (index === -1) { - model.set_value(iter, COLUMN_INDEX, accels.length - 1); - model.set_value(iter, COLUMN_DESCRIPTION, "..."); - - let parent = getOk(model.iter_parent(iter)); - newEmptyRow = model.insert_after(parent, iter); - } else if (index === 0 && !model.iter_has_child(iter)) { - newEmptyRow = model.insert(iter, -1); - } - - if (newEmptyRow) { - model.set(newEmptyRow, ...transpose([ - [COLUMN_ID, id], - [COLUMN_INDEX, -1], - [COLUMN_DESCRIPTION, "New binding"], - [COLUMN_KEY, 0], - [COLUMN_MODS, 0], - ])); - } - - annotateKeybindings(model, settings); + createRow(text, widget) { + let margin = 12; + let box = new Gtk.Box({ + margin_start: margin, margin_end: margin, + margin_top: margin / 2, margin_bottom: margin / 2, + orientation: Gtk.Orientation.HORIZONTAL, }); - - accelRenderer.connect("accel-cleared", - (accelRenderer, path) => { - let iter = getOk(filteredModel.get_iter_from_string(path)); - if (!iter) - return; - - iter = filteredModel.convert_iter_to_child_iter(iter); - - let index = model.get_value(iter, COLUMN_INDEX); - - // Update the UI. - model.set(iter, [COLUMN_KEY, COLUMN_MODS], [0, 0]); - - if (index === -1) { - // Clearing the empty row - return; - } - - let id = model.get_value(iter, COLUMN_ID); - let accels = settings.get_strv(id); - accels.splice(index, 1); - - let parent, nextSibling; - // Simply rebuild the model for this action - if (index === 0) { - parent = iter.copy(); - } else { - parent = getOk(model.iter_parent(iter)); - } - nextSibling = parent.copy(); - - if (!model.iter_next(nextSibling)) - nextSibling = null; - - model.remove(parent); - - // Update the stored setting. - settings.set_strv(id, accels); - - let recreated = addKeybinding(model, settings, id, nextSibling); - let selection = treeView.get_selection(); - selection.select_iter(recreated); - - annotateKeybindings(model, settings); + let label = new Gtk.Label({ + label: text, hexpand: true, xalign: 0, }); - let accelColumn = new Gtk.TreeViewColumn(); - accelColumn.pack_end(accelRenderer, false); - accelColumn.add_attribute(accelRenderer, "accel-key", COLUMN_KEY); - accelColumn.add_attribute(accelRenderer, "accel-mods", COLUMN_MODS); - - treeView.append_column(accelColumn); - - let resetRenderer = new Gtk.CellRendererToggle(); - resetRenderer.mode = Gtk.CellRendererMode.ACTIVATABLE; - let resetColumn = new Gtk.TreeViewColumn(); - resetColumn.clickable = true; - resetColumn.pack_start(resetRenderer, true); - resetColumn.add_attribute(resetRenderer, "visible", COLUMN_RESET); - - resetRenderer.connect('toggled', (renderer, path) => { - let iter = getOk(filteredModel.get_iter_from_string(path)); - if (!iter) - return; - iter = filteredModel.convert_iter_to_child_iter(iter); - - let id = model.get_value(iter, COLUMN_ID); - if (settings.get_user_value(id)) { - settings.reset(id); - model.set_value(iter, COLUMN_RESET, false); - } - - let parent = getOk(model.iter_parent(iter)) || iter.copy(); - let nextSibling = parent.copy(); - if (!model.iter_next(nextSibling)) - nextSibling = null; - - model.remove(parent); - - let recreated = addKeybinding(model, settings, id, nextSibling); - let selection = treeView.get_selection(); - selection.select_iter(recreated); + box.append(label); + box.append(widget); - annotateKeybindings(model, settings); - }); - - treeView.append_column(resetColumn); - - return treeView; -} - -function parseAccelerator(accelerator) { - if (accelerator.match(/Above_Tab/)) { - accelerator = accelerator.replace('Above_Tab', 'grave'); + return box; } - let [ok, key, mods] = AcceleratorParse.accelerator_parse(accelerator); - // log(`PaperWM: parseAccelerator(${accelerator}) -> [${key}, ${mods}]`); - return [key, mods]; -} - -function transpose(colValPairs) { - let colKeys = [], values = []; - colValPairs.forEach(([k, v]) => { - colKeys.push(k); - values.push(v); - }); - return [colKeys, values]; -} - -function addKeybinding(model, settings, id, position = null) { - let accels = settings.get_strv(id); - - let schema = settings.settings_schema; - let schemaKey = schema.get_key(id); - let description = _(schemaKey.get_summary()); - - let accelerator = accels.length > 0 ? accels[0] : null; - // Add a row for the keybinding. - let [key, mods] = accelerator ? parseAccelerator(accelerator) : [0, 0]; - let row = model.insert_before(null, position); - model.set(row, ...transpose([ - [COLUMN_ID, id], - [COLUMN_INDEX, 0], - [COLUMN_DESCRIPTION, description], - [COLUMN_KEY, key], - [COLUMN_MODS, mods], - ])); - - // Add one subrow for each additional keybinding - accels.slice(1).forEach((accelerator, i) => { - let [key, mods] = parseAccelerator(accelerator); - let subrow = model.insert(row, 0); - model.set(subrow, ...transpose([ - [COLUMN_ID, id], - [COLUMN_INDEX, i + 1], - [COLUMN_DESCRIPTION, "..."], - [COLUMN_KEY, key], - [COLUMN_MODS, mods], - ])); - }); - - if (accels.length !== 0) { - // Add an empty row used for adding new bindings - let emptyRow = model.append(row); - model.set(emptyRow, ...transpose([ - [COLUMN_ID, id], - [COLUMN_INDEX, -1], - [COLUMN_DESCRIPTION, "New binding"], - [COLUMN_KEY, 0], - [COLUMN_MODS, 0], - ])); - } - - return row; -} - -function annotateKeybindings(model, settings) { - let conflicts = Settings.findConflicts(); - let warning = (id, c) => { - return conflicts.filter(({ name, combo }) => name === id && combo === c); - }; - - model.foreach((model, path, iter) => { - let id = model.get_value(iter, COLUMN_ID); - if (model.iter_depth(iter) === 0) { - let reset = !!settings.get_user_value(id); - model.set_value(iter, COLUMN_RESET, reset); - } + createFileChooserButton(settings, key, iconName, symbolicIconName, properties) { + const buttonIcon = Gtk.Image.new_from_icon_name(iconName); + const buttonLabel = new Gtk.Label(); + const buttonBox = new Gtk.Box({ + orientation: Gtk.Orientation.HORIZONTAL, + spacing: 8, + }); - let accels = settings.get_strv(id); - let index = model.get_value(iter, COLUMN_INDEX); - if (index === -1 || accels.length === 0) - return true; - let combo = Settings.keystrToKeycombo(accels[index]); - - let conflict = warning(id, combo); - let tooltip = null; - if (conflict.length > 0) { - let keystr = keycomboToKeylab(combo); - tooltip = `${keystr} overrides ${conflict[0].conflicts} in ${conflict[0].settings.path}`; - model.set_value(iter, COLUMN_TOOLTIP, - GLib.markup_escape_text(tooltip, -1)); - model.set_value(iter, COLUMN_WARNING, true); - } else { - model.set_value(iter, COLUMN_WARNING, false); + buttonBox.append(buttonIcon); + buttonBox.append(buttonLabel); + if (symbolicIconName) { + buttonBox.append(new Gtk.Image({ icon_name: symbolicIconName, margin_start: 8 })); } - return false; - }); -} - -function keycomboToKeylab(combo) { - let [mutterKey, mods] = combo.split('|').map(s => Number.parseInt(s)); - let key = mutterKey; - if (mutterKey === META_KEY_ABOVE_TAB) - key = 97; // a - let keylab = Gtk.accelerator_get_label(key, mods); - if (mutterKey === META_KEY_ABOVE_TAB) - keylab = keylab.replace(/a$/, 'Above_Tab'); - return keylab; -} + const button = new Gtk.Button({ child: buttonBox }); -function createFileChooserButton(settings, key, iconName, symbolicIconName, properties) { - const buttonIcon = Gtk.Image.new_from_icon_name(iconName); - const buttonLabel = new Gtk.Label(); - const buttonBox = new Gtk.Box({ - orientation: Gtk.Orientation.HORIZONTAL, - spacing: 8, - }); - - buttonBox.append(buttonIcon); - buttonBox.append(buttonLabel); - if (symbolicIconName) { - buttonBox.append(new Gtk.Image({ icon_name: symbolicIconName, margin_start: 8 })); + this.syncStringSetting(settings, key, path => { + buttonIcon.visible = path !== ''; + buttonLabel.label = path === '' ? '(None)' : GLib.filename_display_basename(path); + }); + button.connect('clicked', () => { + const chooser = new Gtk.FileChooserDialog(properties); + let path = settings.get_string(key); + if (path !== '') + chooser.set_file(Gio.File.new_for_path(path)); + chooser.add_button('Open', Gtk.ResponseType.OK); + chooser.add_button('Cancel', Gtk.ResponseType.CANCEL); + chooser.connect('response', (dialog, response) => { + if (response === Gtk.ResponseType.OK) { + settings.set_string(key, chooser.get_file().get_path()); + } + chooser.destroy(); + }); + chooser.show(); + }); + return button; } - const button = new Gtk.Button({ child: buttonBox }); - - syncStringSetting(settings, key, path => { - buttonIcon.visible = path !== ''; - buttonLabel.label = path === '' ? '(None)' : GLib.filename_display_basename(path); - }); - button.connect('clicked', () => { - const chooser = new Gtk.FileChooserDialog(properties); - let path = settings.get_string(key); - if (path !== '') - chooser.set_file(Gio.File.new_for_path(path)); - chooser.add_button('Open', Gtk.ResponseType.OK); - chooser.add_button('Cancel', Gtk.ResponseType.CANCEL); - chooser.connect('response', (dialog, response) => { - if (response === Gtk.ResponseType.OK) { - settings.set_string(key, chooser.get_file().get_path()); - } - chooser.destroy(); + syncStringSetting(settings, key, callback) { + settings.connect(`changed::${key}`, () => { + callback(settings.get_string(key)); }); - chooser.show(); - }); - return button; -} - -function syncStringSetting(settings, key, callback) { - settings.connect(`changed::${key}`, () => { callback(settings.get_string(key)); - }); - callback(settings.get_string(key)); + } } From 036cadd07938df7dbbfb7a989dadfbf211b6a659 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Tue, 19 Sep 2023 23:20:20 +1000 Subject: [PATCH 33/50] Migrated workspace.js to WorkspaceSettings class. --- prefs.js | 17 ++-- tiling.js | 17 ++-- workspace.js | 213 +++++++++++++++++++++++++-------------------------- 3 files changed, 119 insertions(+), 128 deletions(-) diff --git a/prefs.js b/prefs.js index 6ec47af0..38a1c689 100644 --- a/prefs.js +++ b/prefs.js @@ -8,17 +8,13 @@ import { } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; import * as AcceleratorParse from './acceleratorparse.js'; -import * as Workspace from './workspace.js'; +import { WorkspaceSettings } from './workspace.js'; import * as KeybindingsPane from './prefsKeybinding.js'; import * as WinpropsPane from './winpropsPane.js'; const _ = s => s; -export class Prefs { - -} - -export default class MyExtensionPreferences extends ExtensionPreferences { +export default class PaperWMPrefs extends ExtensionPreferences { fillPreferencesWindow(window) { const provider = new Gtk.CssProvider(); provider.load_from_path(`${this.path}/resources/prefs.css`); @@ -28,11 +24,9 @@ export default class MyExtensionPreferences extends ExtensionPreferences { Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ); - Workspace.enable(this); AcceleratorParse.initKeycodeMap(); // cleanup on prefs window close request window.connect('close-request', () => { - Workspace.disable(); AcceleratorParse.destroyKeycodeMap(); }); @@ -67,6 +61,7 @@ class SettingsWidget { constructor(extension, prefsWindow, selectedPage = 0, selectedWorkspace = 0) { this.extension = extension; this._settings = extension.getSettings(); + this.workspaceSettings = new WorkspaceSettings(extension); const wmSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' }); this.builder = Gtk.Builder.new_from_file(`${extension.path}/Settings.ui`); this.window = prefsWindow; @@ -251,14 +246,14 @@ class SettingsWidget { const workspaceCombo = this.builder.get_object('workspace_combo_text'); const workspaceStack = this.builder.get_object('workspace_stack'); - const nWorkspaces = Workspace.getWorkspaceList().get_strv('list').length; + const nWorkspaces = this.workspaceSettings.getWorkspaceList().get_strv('list').length; // Note: For some reason we can't set the visible child of the workspace // stack at construction time.. (!) // Ensure the initially selected workspace is added to the stack // first as a workaround. let wsIndices = this.range(nWorkspaces); - let wsSettingsByIndex = wsIndices.map(i => Workspace.getWorkspaceSettings(i)[1]); + let wsSettingsByIndex = wsIndices.map(i => this.workspaceSettings.getWorkspaceSettings(i)[1]); let wsIndicesSelectedFirst = this.swapArrayElements(wsIndices.slice(), 0, selectedWorkspace); @@ -485,7 +480,7 @@ class SettingsWidget { } getWorkspaceName(settings, index) { - return Workspace.getWorkspaceName(settings, index); + return this.workspaceSettings.getWorkspaceName(settings, index); } createRow(text, widget) { diff --git a/tiling.js b/tiling.js index b30b1b9b..6effe0b6 100644 --- a/tiling.js +++ b/tiling.js @@ -9,11 +9,11 @@ import St from 'gi://St'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import { - Settings, Utils, Lib, Workspace, Gestures, Navigator, Grab, Topbar, - Scratch, Stackoverlay + Settings, Utils, Lib, Gestures, Navigator, Grab, Topbar, Scratch, Stackoverlay } from './imports.js'; import { Easer } from './utils.js'; import { ClickOverlay } from './stackoverlay.js'; +import { WorkspaceSettings } from './workspace.js'; const { signals: Signals } = imports; const workspaceManager = global.workspace_manager; @@ -90,6 +90,7 @@ let gsettings, backgroundSettings, interfaceSettings; let displayConfig; let saveState; let startupTimeoutId, timerId; +let workspaceSettings; export let inGrab; export function enable(extension) { inGrab = false; @@ -133,6 +134,7 @@ export function enable(extension) { backgroundGroup = Main.layoutManager._backgroundGroup; + workspaceSettings = new WorkspaceSettings(extension); spaces = new Spaces(); let initWorkspaces = () => { try { @@ -202,6 +204,7 @@ export function disable () { backgroundGroup = null; backgroundSettings = null; interfaceSettings = null; + workspaceSettings = null; } /** @@ -296,7 +299,7 @@ export class Space extends Array { monitor = prevMonitor; } - this.setSettings(Workspace.getWorkspaceSettings(this.index)); + this.setSettings(workspaceSettings.getWorkspaceSettings(this.index)); actor.set_pivot_point(0.5, 0); this.selectedWindow = null; @@ -1342,7 +1345,7 @@ border-radius: ${borderWidth}px; } else { this.workspaceLabel.hide(); } - let name = Workspace.getWorkspaceName(this.settings, this.index); + let name = workspaceSettings.getWorkspaceName(this.settings, this.index); Meta.prefs_change_workspace_name(this.index, name); this.workspaceLabel.text = name; this.name = name; @@ -4239,7 +4242,7 @@ export function rotated(list, dir = 1) { export function cycleWorkspaceSettings(dir = 1) { let n = workspaceManager.get_n_workspaces(); - let N = Workspace.getWorkspaceList().get_strv('list').length; + let N = workspaceSettings.getWorkspaceList().get_strv('list').length; let space = spaces.selectedSpace; let wsI = space.index; @@ -4247,11 +4250,11 @@ export function cycleWorkspaceSettings(dir = 1) { // x a b c <-- settings // a b c x <-- rotated settings - let uuids = Workspace.getWorkspaceList().get_strv('list'); + let uuids = workspaceSettings.getWorkspaceList().get_strv('list'); // Work on tuples of [uuid, settings] since we need to uuid association // in the last step let settings = uuids.map( - uuid => [uuid, Workspace.getWorkspaceSettingsByUUID(uuid)] + uuid => [uuid, workspaceSettings.getWorkspaceSettingsByUUID(uuid)] ); settings.sort((a, b) => a[1].get_int('index') - b[1].get_int('index')); diff --git a/workspace.js b/workspace.js index af461e72..73fdf659 100644 --- a/workspace.js +++ b/workspace.js @@ -8,134 +8,127 @@ import * as Lib from './lib.js'; */ const WORKSPACE_LIST_KEY = 'org.gnome.shell.extensions.paperwm.workspacelist'; const WORKSPACE_KEY = 'org.gnome.shell.extensions.paperwm.workspace'; -let workspaceSettingsCache; -let schemaSource, workspaceList; -export function enable(extension) { - workspaceSettingsCache = {}; - - schemaSource = Gio.SettingsSchemaSource.new_from_directory( - GLib.build_filenamev([extension.path, "schemas"]), - Gio.SettingsSchemaSource.get_default(), - false - ); - - workspaceList = new Gio.Settings({ - settings_schema: getSchemaSource().lookup(WORKSPACE_LIST_KEY, true), - }); -} - -export function disable() { - workspaceSettingsCache = null; - schemaSource = null; - workspaceList = null; -} +export class WorkspaceSettings { + constructor(extension) { + this.workspaceSettingsCache = {}; + this.schemaSource = Gio.SettingsSchemaSource.new_from_directory( + GLib.build_filenamev([extension.path, "schemas"]), + Gio.SettingsSchemaSource.get_default(), + false + ); + + this.workspaceList = new Gio.Settings({ + settings_schema: this.getSchemaSource().lookup(WORKSPACE_LIST_KEY, true), + }); + } -export function getSchemaSource() { - return schemaSource; -} + getSchemaSource() { + return this.schemaSource; + } -export function getWorkspaceName(settings, index) { - let name = settings.get_string('name') ?? `Workspace ${index + 1}`; - if (!name || name === '') { - name = `Workspace ${index + 1}`; + getWorkspaceName(settings, index) { + let name = settings.get_string('name') ?? `Workspace ${index + 1}`; + if (!name || name === '') { + name = `Workspace ${index + 1}`; + } + return name; } - return name; -} -export function getWorkspaceList() { - return workspaceList; -} + getWorkspaceList() { + return this.workspaceList; + } -/** - * Returns list of ordered workspace UUIDs. - */ -export function getListUUID() { - return getWorkspaceList().get_strv('list'); -} + /** + * Returns list of ordered workspace UUIDs. + */ + getListUUID() { + return this.getWorkspaceList().get_strv('list'); + } -export function getWorkspaceSettings(index) { - let list = getListUUID(); - for (let uuid of list) { - let settings = getWorkspaceSettingsByUUID(uuid); - if (settings.get_int('index') === index) { - return [uuid, settings]; + getWorkspaceSettings(index) { + let list = this.getListUUID(); + for (let uuid of list) { + let settings = this.getWorkspaceSettingsByUUID(uuid); + if (settings.get_int('index') === index) { + return [uuid, settings]; + } } + return this.getNewWorkspaceSettings(index); } - return getNewWorkspaceSettings(index); -} -export function getNewWorkspaceSettings(index) { - let uuid = GLib.uuid_string_random(); - let settings = getWorkspaceSettingsByUUID(uuid); - let list = getListUUID(); - list.push(uuid); - getWorkspaceList().set_strv('list', list); - settings.set_int('index', index); - return [uuid, settings]; -} + getNewWorkspaceSettings(index) { + let uuid = GLib.uuid_string_random(); + let settings = this.getWorkspaceSettingsByUUID(uuid); + let list = this.getListUUID(); + list.push(uuid); + this.getWorkspaceList().set_strv('list', list); + settings.set_int('index', index); + return [uuid, settings]; + } -export function getWorkspaceSettingsByUUID(uuid) { - if (!workspaceSettingsCache[uuid]) { - let settings = new Gio.Settings({ - settings_schema: getSchemaSource().lookup(WORKSPACE_KEY, true), - path: `/org/gnome/shell/extensions/paperwm/workspaces/${uuid}/`, - }); - workspaceSettingsCache[uuid] = settings; + getWorkspaceSettingsByUUID(uuid) { + if (!this.workspaceSettingsCache[uuid]) { + let settings = new Gio.Settings({ + settings_schema: this.getSchemaSource().lookup(WORKSPACE_KEY, true), + path: `/org/gnome/shell/extensions/paperwm/workspaces/${uuid}/`, + }); + this.workspaceSettingsCache[uuid] = settings; + } + return this.workspaceSettingsCache[uuid]; } - return workspaceSettingsCache[uuid]; -} -/** Returns [[uuid, settings, name], ...] (Only used for debugging/development atm.) */ -export function findWorkspaceSettingsByName(regex) { - let list = getListUUID(); - let settings = list.map(getWorkspaceSettingsByUUID); - return Lib.zip(list, settings, settings.map(s => s.get_string('name'))) - .filter(([uuid, s, name]) => name.match(regex)); -} + /** Returns [[uuid, settings, name], ...] (Only used for debugging/development atm.) */ + findWorkspaceSettingsByName(regex) { + let list = this.getListUUID(); + let settings = list.map(this.getWorkspaceSettingsByUUID); + return Lib.zip(list, settings, settings.map(s => s.get_string('name'))) + .filter(([uuid, s, name]) => name.match(regex)); + } -/** Only used for debugging/development atm. */ -export function deleteWorkspaceSettingsByName(regex, dryrun = true) { - let out = ""; - function rprint(...args) { console.debug(...args); out += `${args.join(" ")}\n`; } - let n = global.workspace_manager.get_n_workspaces(); - for (let [uuid, s, name] of findWorkspaceSettingsByName(regex)) { - let index = s.get_int('index'); - if (index < n) { - rprint("Skipping in-use settings", name, index); - continue; - } - rprint(dryrun ? "[dry]" : "", `Delete settings for '${name}' (${uuid})`); - if (!dryrun) { - deleteWorkspaceSettings(uuid); + /** Only used for debugging/development atm. */ + deleteWorkspaceSettingsByName(regex, dryrun = true) { + let out = ""; + function rprint(...args) { console.debug(...args); out += `${args.join(" ")}\n`; } + let n = global.workspace_manager.get_n_workspaces(); + for (let [uuid, s, name] of this.findWorkspaceSettingsByName(regex)) { + let index = s.get_int('index'); + if (index < n) { + rprint("Skipping in-use settings", name, index); + continue; + } + rprint(dryrun ? "[dry]" : "", `Delete settings for '${name}' (${uuid})`); + if (!dryrun) { + this.deleteWorkspaceSettings(uuid); + } } + return out; } - return out; -} -/** Only used for debugging/development atm. */ -export function deleteWorkspaceSettings(uuid) { - // NB! Does not check if the settings is currently in use. Does not reindex subsequent settings. - let list = getListUUID(); - let i = list.indexOf(uuid); - let settings = getWorkspaceSettingsByUUID(list[i]); - for (let key of settings.list_keys()) { - // Hopefully resetting all keys will delete the relocatable settings from dconf? - settings.reset(key); - } + /** Only used for debugging/development atm. */ + deleteWorkspaceSettings(uuid) { + // NB! Does not check if the settings is currently in use. Does not reindex subsequent settings. + let list = this.getListUUID(); + let i = list.indexOf(uuid); + let settings = this.getWorkspaceSettingsByUUID(list[i]); + for (let key of settings.list_keys()) { + // Hopefully resetting all keys will delete the relocatable settings from dconf? + settings.reset(key); + } - list.splice(i, 1); - getWorkspaceList().set_strv('list', list); -} + list.splice(i, 1); + this.getWorkspaceList().set_strv('list', list); + } -// Useful for debugging -export function printWorkspaceSettings() { - let list = getListUUID(); - let settings = list.map(getWorkspaceSettingsByUUID); - let zipped = Lib.zip(list, settings); - const key = s => s[1].get_int('index'); - zipped.sort((a, b) => key(a) - key(b)); - for (let [uuid, s] of zipped) { - console.log('index:', s.get_int('index'), s.get_string('name'), s.get_string('color'), uuid); + // Useful for debugging + printWorkspaceSettings() { + let list = this.getListUUID(); + let settings = list.map(this.getWorkspaceSettingsByUUID); + let zipped = Lib.zip(list, settings); + const key = s => s[1].get_int('index'); + zipped.sort((a, b) => key(a) - key(b)); + for (let [uuid, s] of zipped) { + console.log('index:', s.get_int('index'), s.get_string('name'), s.get_string('color'), uuid); + } } } From 92dce506905f2bc799cb66bc46656f4a6030cce3 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Tue, 19 Sep 2023 23:56:58 +1000 Subject: [PATCH 34/50] Classifying AccleratorParse. --- acceleratorparse.js | 4731 ++++++++++++++++++++++--------------------- prefs.js | 7 - prefsKeybinding.js | 45 +- settings.js | 9 +- 4 files changed, 2399 insertions(+), 2393 deletions(-) diff --git a/acceleratorparse.js b/acceleratorparse.js index 71001140..b17d8429 100644 --- a/acceleratorparse.js +++ b/acceleratorparse.js @@ -1,2375 +1,2382 @@ /** * Provides replacement for Gtk.accelerator_parse. - * @param {String} keystr */ -export function accelerator_parse(keystr) { - let mask = accelerator_mask(keystr); - const mods = accelerator_mods(keystr); - - // remove mods from keystr - let key = keystr; - mods.forEach(m => { - key = key.replace(m, ''); - }); - key = key.trim(); - - // now lookup key in map - let ok = true; - const mapped = keycodeMap.get(key); - if (mapped) { - key = mapped; - } - else { - ok = false; - key = 0; - mask = 0; +export class AcceleratorParse { + constructor() { + /** + * GDK keystr mask values. + * Refer to: + * https://gitlab.gnome.org/GNOME/gtk/-/blob/4.13.0/gdk/gdkenums.h?ref_type=tags#L115 + */ + this.GDK_SHIFT_MASK = 1 << 0; + this.GDK_CONTROL_MASK = 1 << 2; + this.GDK_ALT_MASK = 1 << 3; + this.GDK_SUPER_MASK = 1 << 26; + this.GDK_HYPER_MASK = 1 << 27; + this.GDK_META_MASK = 1 << 28; } - // console.log(keystr, key, mask); - return [ok, key, mask]; -} + accelerator_parse(keystr) { + let mask = this.accelerator_mask(keystr); + const mods = this.accelerator_mods(keystr); -/** - * Returns array of mods for a keystr, e.g. ['', '', '']. - * @param {String} keystr - */ -export function accelerator_mods(keystr) { - return keystr.match(/<.*?>/g) ?? []; -} + // remove mods from keystr + let key = keystr; + mods.forEach(m => { + key = key.replace(m, ''); + }); + key = key.trim(); -/** - * Returns the GDK mask value for a keystr (keybind string representation). - * Refer to: - * https://gitlab.gnome.org/GNOME/gtk/-/blob/4.13.0/gdk/gdkenums.h?ref_type=tags#L115 - * https://gitlab.gnome.org/GNOME/gtk/-/blob/4.13.0/gtk/gtkaccelgroup.c#L571 - * @param {String} keystr - */ -// GDK keystr mask values. -const GDK_SHIFT_MASK = 1 << 0; -const GDK_CONTROL_MASK = 1 << 2; -const GDK_ALT_MASK = 1 << 3; -const GDK_SUPER_MASK = 1 << 26; -const GDK_HYPER_MASK = 1 << 27; -const GDK_META_MASK = 1 << 28; -export function accelerator_mask(keystr) { - // need to extact all mods from keystr - const mods = accelerator_mods(keystr); - let result = 0; - for (let mod of mods) { - switch (mod.toLowerCase()) { - case '': - result |= GDK_SHIFT_MASK; - break; - case '': - case '': - case '': - result |= GDK_CONTROL_MASK; - break; - case '': - result |= GDK_ALT_MASK; - break; - case '': - result |= GDK_SUPER_MASK; - break; - case '': - result |= GDK_HYPER_MASK; - break; - case '': - result |= GDK_META_MASK; + // now lookup key in map + this._initKeycodeMap(); + let ok = true; + const mapped = this.keycodeMap.get(key); + if (mapped) { + key = mapped; } + else { + ok = false; + key = 0; + mask = 0; + } + + // console.log(keystr, key, mask); + return [ok, key, mask]; } - return result; -} + /** + * Returns array of mods for a keystr, e.g. ['', '', '']. + * @param {String} keystr + */ + accelerator_mods(keystr) { + return keystr.match(/<.*?>/g) ?? []; + } -export function destroyKeycodeMap() { - keycodeMap = null; -} + /** + * Returns the GDK mask value for a keystr (keybind string representation). + * Refer to: + * https://gitlab.gnome.org/GNOME/gtk/-/blob/4.13.0/gdk/gdkenums.h?ref_type=tags#L115 + * https://gitlab.gnome.org/GNOME/gtk/-/blob/4.13.0/gtk/gtkaccelgroup.c#L571 + * @param {String} keystr + */ + accelerator_mask(keystr) { + // need to extact all mods from keystr + const mods = this.accelerator_mods(keystr); + let result = 0; + for (let mod of mods) { + switch (mod.toLowerCase()) { + case '': + result |= this.GDK_SHIFT_MASK; + break; + case '': + case '': + case '': + result |= this.GDK_CONTROL_MASK; + break; + case '': + result |= this.GDK_ALT_MASK; + break; + case '': + result |= this.GDK_SUPER_MASK; + break; + case '': + result |= this.GDK_HYPER_MASK; + break; + case '': + result |= this.GDK_META_MASK; + } + } -/** - * Replicates Gdk full keyset. - * https://gitlab.gnome.org/GNOME/gtk/-/blob/4.13.0/gdk/gdkkeysyms.h?ref_type=tags - */ -let keycodeMap; -export function initKeycodeMap() { - const map = new Map(); - map.set('VoidSymbol', 0xffffff); - map.set('BackSpace', 0xff08); - map.set('Tab', 0xff09); - map.set('Linefeed', 0xff0a); - map.set('Clear', 0xff0b); - map.set('Return', 0xff0d); - map.set('Pause', 0xff13); - map.set('Scroll_Lock', 0xff14); - map.set('Sys_Req', 0xff15); - map.set('Escape', 0xff1b); - map.set('Delete', 0xffff); - map.set('Multi_key', 0xff20); - map.set('Codeinput', 0xff37); - map.set('SingleCandidate', 0xff3c); - map.set('MultipleCandidate', 0xff3d); - map.set('PreviousCandidate', 0xff3e); - map.set('Kanji', 0xff21); - map.set('Muhenkan', 0xff22); - map.set('Henkan_Mode', 0xff23); - map.set('Henkan', 0xff23); - map.set('Romaji', 0xff24); - map.set('Hiragana', 0xff25); - map.set('Katakana', 0xff26); - map.set('Hiragana_Katakana', 0xff27); - map.set('Zenkaku', 0xff28); - map.set('Hankaku', 0xff29); - map.set('Zenkaku_Hankaku', 0xff2a); - map.set('Touroku', 0xff2b); - map.set('Massyo', 0xff2c); - map.set('Kana_Lock', 0xff2d); - map.set('Kana_Shift', 0xff2e); - map.set('Eisu_Shift', 0xff2f); - map.set('Eisu_toggle', 0xff30); - map.set('Kanji_Bangou', 0xff37); - map.set('Zen_Koho', 0xff3d); - map.set('Mae_Koho', 0xff3e); - map.set('Home', 0xff50); - map.set('Left', 0xff51); - map.set('Up', 0xff52); - map.set('Right', 0xff53); - map.set('Down', 0xff54); - map.set('Prior', 0xff55); - map.set('Page_Up', 0xff55); - map.set('Next', 0xff56); - map.set('Page_Down', 0xff56); - map.set('End', 0xff57); - map.set('Begin', 0xff58); - map.set('Select', 0xff60); - map.set('Print', 0xff61); - map.set('Execute', 0xff62); - map.set('Insert', 0xff63); - map.set('Undo', 0xff65); - map.set('Redo', 0xff66); - map.set('Menu', 0xff67); - map.set('Find', 0xff68); - map.set('Cancel', 0xff69); - map.set('Help', 0xff6a); - map.set('Break', 0xff6b); - map.set('Mode_switch', 0xff7e); - map.set('script_switch', 0xff7e); - map.set('Num_Lock', 0xff7f); - map.set('KP_Space', 0xff80); - map.set('KP_Tab', 0xff89); - map.set('KP_Enter', 0xff8d); - map.set('KP_F1', 0xff91); - map.set('KP_F2', 0xff92); - map.set('KP_F3', 0xff93); - map.set('KP_F4', 0xff94); - map.set('KP_Home', 0xff95); - map.set('KP_Left', 0xff96); - map.set('KP_Up', 0xff97); - map.set('KP_Right', 0xff98); - map.set('KP_Down', 0xff99); - map.set('KP_Prior', 0xff9a); - map.set('KP_Page_Up', 0xff9a); - map.set('KP_Next', 0xff9b); - map.set('KP_Page_Down', 0xff9b); - map.set('KP_End', 0xff9c); - map.set('KP_Begin', 0xff9d); - map.set('KP_Insert', 0xff9e); - map.set('KP_Delete', 0xff9f); - map.set('KP_Equal', 0xffbd); - map.set('KP_Multiply', 0xffaa); - map.set('KP_Add', 0xffab); - map.set('KP_Separator', 0xffac); - map.set('KP_Subtract', 0xffad); - map.set('KP_Decimal', 0xffae); - map.set('KP_Divide', 0xffaf); - map.set('KP_0', 0xffb0); - map.set('KP_1', 0xffb1); - map.set('KP_2', 0xffb2); - map.set('KP_3', 0xffb3); - map.set('KP_4', 0xffb4); - map.set('KP_5', 0xffb5); - map.set('KP_6', 0xffb6); - map.set('KP_7', 0xffb7); - map.set('KP_8', 0xffb8); - map.set('KP_9', 0xffb9); - map.set('F1', 0xffbe); - map.set('F2', 0xffbf); - map.set('F3', 0xffc0); - map.set('F4', 0xffc1); - map.set('F5', 0xffc2); - map.set('F6', 0xffc3); - map.set('F7', 0xffc4); - map.set('F8', 0xffc5); - map.set('F9', 0xffc6); - map.set('F10', 0xffc7); - map.set('F11', 0xffc8); - map.set('L1', 0xffc8); - map.set('F12', 0xffc9); - map.set('L2', 0xffc9); - map.set('F13', 0xffca); - map.set('L3', 0xffca); - map.set('F14', 0xffcb); - map.set('L4', 0xffcb); - map.set('F15', 0xffcc); - map.set('L5', 0xffcc); - map.set('F16', 0xffcd); - map.set('L6', 0xffcd); - map.set('F17', 0xffce); - map.set('L7', 0xffce); - map.set('F18', 0xffcf); - map.set('L8', 0xffcf); - map.set('F19', 0xffd0); - map.set('L9', 0xffd0); - map.set('F20', 0xffd1); - map.set('L10', 0xffd1); - map.set('F21', 0xffd2); - map.set('R1', 0xffd2); - map.set('F22', 0xffd3); - map.set('R2', 0xffd3); - map.set('F23', 0xffd4); - map.set('R3', 0xffd4); - map.set('F24', 0xffd5); - map.set('R4', 0xffd5); - map.set('F25', 0xffd6); - map.set('R5', 0xffd6); - map.set('F26', 0xffd7); - map.set('R6', 0xffd7); - map.set('F27', 0xffd8); - map.set('R7', 0xffd8); - map.set('F28', 0xffd9); - map.set('R8', 0xffd9); - map.set('F29', 0xffda); - map.set('R9', 0xffda); - map.set('F30', 0xffdb); - map.set('R10', 0xffdb); - map.set('F31', 0xffdc); - map.set('R11', 0xffdc); - map.set('F32', 0xffdd); - map.set('R12', 0xffdd); - map.set('F33', 0xffde); - map.set('R13', 0xffde); - map.set('F34', 0xffdf); - map.set('R14', 0xffdf); - map.set('F35', 0xffe0); - map.set('R15', 0xffe0); - map.set('Shift_L', 0xffe1); - map.set('Shift_R', 0xffe2); - map.set('Control_L', 0xffe3); - map.set('Control_R', 0xffe4); - map.set('Caps_Lock', 0xffe5); - map.set('Shift_Lock', 0xffe6); - map.set('Meta_L', 0xffe7); - map.set('Meta_R', 0xffe8); - map.set('Alt_L', 0xffe9); - map.set('Alt_R', 0xffea); - map.set('Super_L', 0xffeb); - map.set('Super_R', 0xffec); - map.set('Hyper_L', 0xffed); - map.set('Hyper_R', 0xffee); - map.set('ISO_Lock', 0xfe01); - map.set('ISO_Level2_Latch', 0xfe02); - map.set('ISO_Level3_Shift', 0xfe03); - map.set('ISO_Level3_Latch', 0xfe04); - map.set('ISO_Level3_Lock', 0xfe05); - map.set('ISO_Level5_Shift', 0xfe11); - map.set('ISO_Level5_Latch', 0xfe12); - map.set('ISO_Level5_Lock', 0xfe13); - map.set('ISO_Group_Shift', 0xff7e); - map.set('ISO_Group_Latch', 0xfe06); - map.set('ISO_Group_Lock', 0xfe07); - map.set('ISO_Next_Group', 0xfe08); - map.set('ISO_Next_Group_Lock', 0xfe09); - map.set('ISO_Prev_Group', 0xfe0a); - map.set('ISO_Prev_Group_Lock', 0xfe0b); - map.set('ISO_First_Group', 0xfe0c); - map.set('ISO_First_Group_Lock', 0xfe0d); - map.set('ISO_Last_Group', 0xfe0e); - map.set('ISO_Last_Group_Lock', 0xfe0f); - map.set('ISO_Left_Tab', 0xfe20); - map.set('ISO_Move_Line_Up', 0xfe21); - map.set('ISO_Move_Line_Down', 0xfe22); - map.set('ISO_Partial_Line_Up', 0xfe23); - map.set('ISO_Partial_Line_Down', 0xfe24); - map.set('ISO_Partial_Space_Left', 0xfe25); - map.set('ISO_Partial_Space_Right', 0xfe26); - map.set('ISO_Set_Margin_Left', 0xfe27); - map.set('ISO_Set_Margin_Right', 0xfe28); - map.set('ISO_Release_Margin_Left', 0xfe29); - map.set('ISO_Release_Margin_Right', 0xfe2a); - map.set('ISO_Release_Both_Margins', 0xfe2b); - map.set('ISO_Fast_Cursor_Left', 0xfe2c); - map.set('ISO_Fast_Cursor_Right', 0xfe2d); - map.set('ISO_Fast_Cursor_Up', 0xfe2e); - map.set('ISO_Fast_Cursor_Down', 0xfe2f); - map.set('ISO_Continuous_Underline', 0xfe30); - map.set('ISO_Discontinuous_Underline', 0xfe31); - map.set('ISO_Emphasize', 0xfe32); - map.set('ISO_Center_Object', 0xfe33); - map.set('ISO_Enter', 0xfe34); - map.set('dead_grave', 0xfe50); - map.set('dead_acute', 0xfe51); - map.set('dead_circumflex', 0xfe52); - map.set('dead_tilde', 0xfe53); - map.set('dead_perispomeni', 0xfe53); - map.set('dead_macron', 0xfe54); - map.set('dead_breve', 0xfe55); - map.set('dead_abovedot', 0xfe56); - map.set('dead_diaeresis', 0xfe57); - map.set('dead_abovering', 0xfe58); - map.set('dead_doubleacute', 0xfe59); - map.set('dead_caron', 0xfe5a); - map.set('dead_cedilla', 0xfe5b); - map.set('dead_ogonek', 0xfe5c); - map.set('dead_iota', 0xfe5d); - map.set('dead_voiced_sound', 0xfe5e); - map.set('dead_semivoiced_sound', 0xfe5f); - map.set('dead_belowdot', 0xfe60); - map.set('dead_hook', 0xfe61); - map.set('dead_horn', 0xfe62); - map.set('dead_stroke', 0xfe63); - map.set('dead_abovecomma', 0xfe64); - map.set('dead_psili', 0xfe64); - map.set('dead_abovereversedcomma', 0xfe65); - map.set('dead_dasia', 0xfe65); - map.set('dead_doublegrave', 0xfe66); - map.set('dead_belowring', 0xfe67); - map.set('dead_belowmacron', 0xfe68); - map.set('dead_belowcircumflex', 0xfe69); - map.set('dead_belowtilde', 0xfe6a); - map.set('dead_belowbreve', 0xfe6b); - map.set('dead_belowdiaeresis', 0xfe6c); - map.set('dead_invertedbreve', 0xfe6d); - map.set('dead_belowcomma', 0xfe6e); - map.set('dead_currency', 0xfe6f); - map.set('dead_lowline', 0xfe90); - map.set('dead_aboveverticalline', 0xfe91); - map.set('dead_belowverticalline', 0xfe92); - map.set('dead_longsolidusoverlay', 0xfe93); - map.set('dead_a', 0xfe80); - map.set('dead_A', 0xfe81); - map.set('dead_e', 0xfe82); - map.set('dead_E', 0xfe83); - map.set('dead_i', 0xfe84); - map.set('dead_I', 0xfe85); - map.set('dead_o', 0xfe86); - map.set('dead_O', 0xfe87); - map.set('dead_u', 0xfe88); - map.set('dead_U', 0xfe89); - map.set('dead_small_schwa', 0xfe8a); - map.set('dead_capital_schwa', 0xfe8b); - map.set('dead_greek', 0xfe8c); - map.set('First_Virtual_Screen', 0xfed0); - map.set('Prev_Virtual_Screen', 0xfed1); - map.set('Next_Virtual_Screen', 0xfed2); - map.set('Last_Virtual_Screen', 0xfed4); - map.set('Terminate_Server', 0xfed5); - map.set('AccessX_Enable', 0xfe70); - map.set('AccessX_Feedback_Enable', 0xfe71); - map.set('RepeatKeys_Enable', 0xfe72); - map.set('SlowKeys_Enable', 0xfe73); - map.set('BounceKeys_Enable', 0xfe74); - map.set('StickyKeys_Enable', 0xfe75); - map.set('MouseKeys_Enable', 0xfe76); - map.set('MouseKeys_Accel_Enable', 0xfe77); - map.set('Overlay1_Enable', 0xfe78); - map.set('Overlay2_Enable', 0xfe79); - map.set('AudibleBell_Enable', 0xfe7a); - map.set('Pointer_Left', 0xfee0); - map.set('Pointer_Right', 0xfee1); - map.set('Pointer_Up', 0xfee2); - map.set('Pointer_Down', 0xfee3); - map.set('Pointer_UpLeft', 0xfee4); - map.set('Pointer_UpRight', 0xfee5); - map.set('Pointer_DownLeft', 0xfee6); - map.set('Pointer_DownRight', 0xfee7); - map.set('Pointer_Button_Dflt', 0xfee8); - map.set('Pointer_Button1', 0xfee9); - map.set('Pointer_Button2', 0xfeea); - map.set('Pointer_Button3', 0xfeeb); - map.set('Pointer_Button4', 0xfeec); - map.set('Pointer_Button5', 0xfeed); - map.set('Pointer_DblClick_Dflt', 0xfeee); - map.set('Pointer_DblClick1', 0xfeef); - map.set('Pointer_DblClick2', 0xfef0); - map.set('Pointer_DblClick3', 0xfef1); - map.set('Pointer_DblClick4', 0xfef2); - map.set('Pointer_DblClick5', 0xfef3); - map.set('Pointer_Drag_Dflt', 0xfef4); - map.set('Pointer_Drag1', 0xfef5); - map.set('Pointer_Drag2', 0xfef6); - map.set('Pointer_Drag3', 0xfef7); - map.set('Pointer_Drag4', 0xfef8); - map.set('Pointer_Drag5', 0xfefd); - map.set('Pointer_EnableKeys', 0xfef9); - map.set('Pointer_Accelerate', 0xfefa); - map.set('Pointer_DfltBtnNext', 0xfefb); - map.set('Pointer_DfltBtnPrev', 0xfefc); - map.set('ch', 0xfea0); - map.set('Ch', 0xfea1); - map.set('CH', 0xfea2); - map.set('c_h', 0xfea3); - map.set('C_h', 0xfea4); - map.set('C_H', 0xfea5); - map.set('3270_Duplicate', 0xfd01); - map.set('3270_FieldMark', 0xfd02); - map.set('3270_Right2', 0xfd03); - map.set('3270_Left2', 0xfd04); - map.set('3270_BackTab', 0xfd05); - map.set('3270_EraseEOF', 0xfd06); - map.set('3270_EraseInput', 0xfd07); - map.set('3270_Reset', 0xfd08); - map.set('3270_Quit', 0xfd09); - map.set('3270_PA1', 0xfd0a); - map.set('3270_PA2', 0xfd0b); - map.set('3270_PA3', 0xfd0c); - map.set('3270_Test', 0xfd0d); - map.set('3270_Attn', 0xfd0e); - map.set('3270_CursorBlink', 0xfd0f); - map.set('3270_AltCursor', 0xfd10); - map.set('3270_KeyClick', 0xfd11); - map.set('3270_Jump', 0xfd12); - map.set('3270_Ident', 0xfd13); - map.set('3270_Rule', 0xfd14); - map.set('3270_Copy', 0xfd15); - map.set('3270_Play', 0xfd16); - map.set('3270_Setup', 0xfd17); - map.set('3270_Record', 0xfd18); - map.set('3270_ChangeScreen', 0xfd19); - map.set('3270_DeleteWord', 0xfd1a); - map.set('3270_ExSelect', 0xfd1b); - map.set('3270_CursorSelect', 0xfd1c); - map.set('3270_PrintScreen', 0xfd1d); - map.set('3270_Enter', 0xfd1e); - map.set('space', 0x020); - map.set('exclam', 0x021); - map.set('quotedbl', 0x022); - map.set('numbersign', 0x023); - map.set('dollar', 0x024); - map.set('percent', 0x025); - map.set('ampersand', 0x026); - map.set('apostrophe', 0x027); - map.set('quoteright', 0x027); - map.set('parenleft', 0x028); - map.set('parenright', 0x029); - map.set('asterisk', 0x02a); - map.set('plus', 0x02b); - map.set('comma', 0x02c); - map.set('minus', 0x02d); - map.set('period', 0x02e); - map.set('slash', 0x02f); - map.set('0', 0x030); - map.set('1', 0x031); - map.set('2', 0x032); - map.set('3', 0x033); - map.set('4', 0x034); - map.set('5', 0x035); - map.set('6', 0x036); - map.set('7', 0x037); - map.set('8', 0x038); - map.set('9', 0x039); - map.set('colon', 0x03a); - map.set('semicolon', 0x03b); - map.set('less', 0x03c); - map.set('equal', 0x03d); - map.set('greater', 0x03e); - map.set('question', 0x03f); - map.set('at', 0x040); - map.set('A', 0x041); - map.set('B', 0x042); - map.set('C', 0x043); - map.set('D', 0x044); - map.set('E', 0x045); - map.set('F', 0x046); - map.set('G', 0x047); - map.set('H', 0x048); - map.set('I', 0x049); - map.set('J', 0x04a); - map.set('K', 0x04b); - map.set('L', 0x04c); - map.set('M', 0x04d); - map.set('N', 0x04e); - map.set('O', 0x04f); - map.set('P', 0x050); - map.set('Q', 0x051); - map.set('R', 0x052); - map.set('S', 0x053); - map.set('T', 0x054); - map.set('U', 0x055); - map.set('V', 0x056); - map.set('W', 0x057); - map.set('X', 0x058); - map.set('Y', 0x059); - map.set('Z', 0x05a); - map.set('bracketleft', 0x05b); - map.set('backslash', 0x05c); - map.set('bracketright', 0x05d); - map.set('asciicircum', 0x05e); - map.set('underscore', 0x05f); - map.set('grave', 0x060); - map.set('quoteleft', 0x060); - map.set('a', 0x061); - map.set('b', 0x062); - map.set('c', 0x063); - map.set('d', 0x064); - map.set('e', 0x065); - map.set('f', 0x066); - map.set('g', 0x067); - map.set('h', 0x068); - map.set('i', 0x069); - map.set('j', 0x06a); - map.set('k', 0x06b); - map.set('l', 0x06c); - map.set('m', 0x06d); - map.set('n', 0x06e); - map.set('o', 0x06f); - map.set('p', 0x070); - map.set('q', 0x071); - map.set('r', 0x072); - map.set('s', 0x073); - map.set('t', 0x074); - map.set('u', 0x075); - map.set('v', 0x076); - map.set('w', 0x077); - map.set('x', 0x078); - map.set('y', 0x079); - map.set('z', 0x07a); - map.set('braceleft', 0x07b); - map.set('bar', 0x07c); - map.set('braceright', 0x07d); - map.set('asciitilde', 0x07e); - map.set('nobreakspace', 0x0a0); - map.set('exclamdown', 0x0a1); - map.set('cent', 0x0a2); - map.set('sterling', 0x0a3); - map.set('currency', 0x0a4); - map.set('yen', 0x0a5); - map.set('brokenbar', 0x0a6); - map.set('section', 0x0a7); - map.set('diaeresis', 0x0a8); - map.set('copyright', 0x0a9); - map.set('ordfeminine', 0x0aa); - map.set('guillemotleft', 0x0ab); - map.set('notsign', 0x0ac); - map.set('hyphen', 0x0ad); - map.set('registered', 0x0ae); - map.set('macron', 0x0af); - map.set('degree', 0x0b0); - map.set('plusminus', 0x0b1); - map.set('twosuperior', 0x0b2); - map.set('threesuperior', 0x0b3); - map.set('acute', 0x0b4); - map.set('mu', 0x0b5); - map.set('paragraph', 0x0b6); - map.set('periodcentered', 0x0b7); - map.set('cedilla', 0x0b8); - map.set('onesuperior', 0x0b9); - map.set('masculine', 0x0ba); - map.set('guillemotright', 0x0bb); - map.set('onequarter', 0x0bc); - map.set('onehalf', 0x0bd); - map.set('threequarters', 0x0be); - map.set('questiondown', 0x0bf); - map.set('Agrave', 0x0c0); - map.set('Aacute', 0x0c1); - map.set('Acircumflex', 0x0c2); - map.set('Atilde', 0x0c3); - map.set('Adiaeresis', 0x0c4); - map.set('Aring', 0x0c5); - map.set('AE', 0x0c6); - map.set('Ccedilla', 0x0c7); - map.set('Egrave', 0x0c8); - map.set('Eacute', 0x0c9); - map.set('Ecircumflex', 0x0ca); - map.set('Ediaeresis', 0x0cb); - map.set('Igrave', 0x0cc); - map.set('Iacute', 0x0cd); - map.set('Icircumflex', 0x0ce); - map.set('Idiaeresis', 0x0cf); - map.set('ETH', 0x0d0); - map.set('Eth', 0x0d0); - map.set('Ntilde', 0x0d1); - map.set('Ograve', 0x0d2); - map.set('Oacute', 0x0d3); - map.set('Ocircumflex', 0x0d4); - map.set('Otilde', 0x0d5); - map.set('Odiaeresis', 0x0d6); - map.set('multiply', 0x0d7); - map.set('Oslash', 0x0d8); - map.set('Ooblique', 0x0d8); - map.set('Ugrave', 0x0d9); - map.set('Uacute', 0x0da); - map.set('Ucircumflex', 0x0db); - map.set('Udiaeresis', 0x0dc); - map.set('Yacute', 0x0dd); - map.set('THORN', 0x0de); - map.set('Thorn', 0x0de); - map.set('ssharp', 0x0df); - map.set('agrave', 0x0e0); - map.set('aacute', 0x0e1); - map.set('acircumflex', 0x0e2); - map.set('atilde', 0x0e3); - map.set('adiaeresis', 0x0e4); - map.set('aring', 0x0e5); - map.set('ae', 0x0e6); - map.set('ccedilla', 0x0e7); - map.set('egrave', 0x0e8); - map.set('eacute', 0x0e9); - map.set('ecircumflex', 0x0ea); - map.set('ediaeresis', 0x0eb); - map.set('igrave', 0x0ec); - map.set('iacute', 0x0ed); - map.set('icircumflex', 0x0ee); - map.set('idiaeresis', 0x0ef); - map.set('eth', 0x0f0); - map.set('ntilde', 0x0f1); - map.set('ograve', 0x0f2); - map.set('oacute', 0x0f3); - map.set('ocircumflex', 0x0f4); - map.set('otilde', 0x0f5); - map.set('odiaeresis', 0x0f6); - map.set('division', 0x0f7); - map.set('oslash', 0x0f8); - map.set('ooblique', 0x0f8); - map.set('ugrave', 0x0f9); - map.set('uacute', 0x0fa); - map.set('ucircumflex', 0x0fb); - map.set('udiaeresis', 0x0fc); - map.set('yacute', 0x0fd); - map.set('thorn', 0x0fe); - map.set('ydiaeresis', 0x0ff); - map.set('Aogonek', 0x1a1); - map.set('breve', 0x1a2); - map.set('Lstroke', 0x1a3); - map.set('Lcaron', 0x1a5); - map.set('Sacute', 0x1a6); - map.set('Scaron', 0x1a9); - map.set('Scedilla', 0x1aa); - map.set('Tcaron', 0x1ab); - map.set('Zacute', 0x1ac); - map.set('Zcaron', 0x1ae); - map.set('Zabovedot', 0x1af); - map.set('aogonek', 0x1b1); - map.set('ogonek', 0x1b2); - map.set('lstroke', 0x1b3); - map.set('lcaron', 0x1b5); - map.set('sacute', 0x1b6); - map.set('caron', 0x1b7); - map.set('scaron', 0x1b9); - map.set('scedilla', 0x1ba); - map.set('tcaron', 0x1bb); - map.set('zacute', 0x1bc); - map.set('doubleacute', 0x1bd); - map.set('zcaron', 0x1be); - map.set('zabovedot', 0x1bf); - map.set('Racute', 0x1c0); - map.set('Abreve', 0x1c3); - map.set('Lacute', 0x1c5); - map.set('Cacute', 0x1c6); - map.set('Ccaron', 0x1c8); - map.set('Eogonek', 0x1ca); - map.set('Ecaron', 0x1cc); - map.set('Dcaron', 0x1cf); - map.set('Dstroke', 0x1d0); - map.set('Nacute', 0x1d1); - map.set('Ncaron', 0x1d2); - map.set('Odoubleacute', 0x1d5); - map.set('Rcaron', 0x1d8); - map.set('Uring', 0x1d9); - map.set('Udoubleacute', 0x1db); - map.set('Tcedilla', 0x1de); - map.set('racute', 0x1e0); - map.set('abreve', 0x1e3); - map.set('lacute', 0x1e5); - map.set('cacute', 0x1e6); - map.set('ccaron', 0x1e8); - map.set('eogonek', 0x1ea); - map.set('ecaron', 0x1ec); - map.set('dcaron', 0x1ef); - map.set('dstroke', 0x1f0); - map.set('nacute', 0x1f1); - map.set('ncaron', 0x1f2); - map.set('odoubleacute', 0x1f5); - map.set('rcaron', 0x1f8); - map.set('uring', 0x1f9); - map.set('udoubleacute', 0x1fb); - map.set('tcedilla', 0x1fe); - map.set('abovedot', 0x1ff); - map.set('Hstroke', 0x2a1); - map.set('Hcircumflex', 0x2a6); - map.set('Iabovedot', 0x2a9); - map.set('Gbreve', 0x2ab); - map.set('Jcircumflex', 0x2ac); - map.set('hstroke', 0x2b1); - map.set('hcircumflex', 0x2b6); - map.set('idotless', 0x2b9); - map.set('gbreve', 0x2bb); - map.set('jcircumflex', 0x2bc); - map.set('Cabovedot', 0x2c5); - map.set('Ccircumflex', 0x2c6); - map.set('Gabovedot', 0x2d5); - map.set('Gcircumflex', 0x2d8); - map.set('Ubreve', 0x2dd); - map.set('Scircumflex', 0x2de); - map.set('cabovedot', 0x2e5); - map.set('ccircumflex', 0x2e6); - map.set('gabovedot', 0x2f5); - map.set('gcircumflex', 0x2f8); - map.set('ubreve', 0x2fd); - map.set('scircumflex', 0x2fe); - map.set('kra', 0x3a2); - map.set('kappa', 0x3a2); - map.set('Rcedilla', 0x3a3); - map.set('Itilde', 0x3a5); - map.set('Lcedilla', 0x3a6); - map.set('Emacron', 0x3aa); - map.set('Gcedilla', 0x3ab); - map.set('Tslash', 0x3ac); - map.set('rcedilla', 0x3b3); - map.set('itilde', 0x3b5); - map.set('lcedilla', 0x3b6); - map.set('emacron', 0x3ba); - map.set('gcedilla', 0x3bb); - map.set('tslash', 0x3bc); - map.set('ENG', 0x3bd); - map.set('eng', 0x3bf); - map.set('Amacron', 0x3c0); - map.set('Iogonek', 0x3c7); - map.set('Eabovedot', 0x3cc); - map.set('Imacron', 0x3cf); - map.set('Ncedilla', 0x3d1); - map.set('Omacron', 0x3d2); - map.set('Kcedilla', 0x3d3); - map.set('Uogonek', 0x3d9); - map.set('Utilde', 0x3dd); - map.set('Umacron', 0x3de); - map.set('amacron', 0x3e0); - map.set('iogonek', 0x3e7); - map.set('eabovedot', 0x3ec); - map.set('imacron', 0x3ef); - map.set('ncedilla', 0x3f1); - map.set('omacron', 0x3f2); - map.set('kcedilla', 0x3f3); - map.set('uogonek', 0x3f9); - map.set('utilde', 0x3fd); - map.set('umacron', 0x3fe); - map.set('Wcircumflex', 0x1000174); - map.set('wcircumflex', 0x1000175); - map.set('Ycircumflex', 0x1000176); - map.set('ycircumflex', 0x1000177); - map.set('Babovedot', 0x1001e02); - map.set('babovedot', 0x1001e03); - map.set('Dabovedot', 0x1001e0a); - map.set('dabovedot', 0x1001e0b); - map.set('Fabovedot', 0x1001e1e); - map.set('fabovedot', 0x1001e1f); - map.set('Mabovedot', 0x1001e40); - map.set('mabovedot', 0x1001e41); - map.set('Pabovedot', 0x1001e56); - map.set('pabovedot', 0x1001e57); - map.set('Sabovedot', 0x1001e60); - map.set('sabovedot', 0x1001e61); - map.set('Tabovedot', 0x1001e6a); - map.set('tabovedot', 0x1001e6b); - map.set('Wgrave', 0x1001e80); - map.set('wgrave', 0x1001e81); - map.set('Wacute', 0x1001e82); - map.set('wacute', 0x1001e83); - map.set('Wdiaeresis', 0x1001e84); - map.set('wdiaeresis', 0x1001e85); - map.set('Ygrave', 0x1001ef2); - map.set('ygrave', 0x1001ef3); - map.set('OE', 0x13bc); - map.set('oe', 0x13bd); - map.set('Ydiaeresis', 0x13be); - map.set('overline', 0x47e); - map.set('kana_fullstop', 0x4a1); - map.set('kana_openingbracket', 0x4a2); - map.set('kana_closingbracket', 0x4a3); - map.set('kana_comma', 0x4a4); - map.set('kana_conjunctive', 0x4a5); - map.set('kana_middledot', 0x4a5); - map.set('kana_WO', 0x4a6); - map.set('kana_a', 0x4a7); - map.set('kana_i', 0x4a8); - map.set('kana_u', 0x4a9); - map.set('kana_e', 0x4aa); - map.set('kana_o', 0x4ab); - map.set('kana_ya', 0x4ac); - map.set('kana_yu', 0x4ad); - map.set('kana_yo', 0x4ae); - map.set('kana_tsu', 0x4af); - map.set('kana_tu', 0x4af); - map.set('prolongedsound', 0x4b0); - map.set('kana_A', 0x4b1); - map.set('kana_I', 0x4b2); - map.set('kana_U', 0x4b3); - map.set('kana_E', 0x4b4); - map.set('kana_O', 0x4b5); - map.set('kana_KA', 0x4b6); - map.set('kana_KI', 0x4b7); - map.set('kana_KU', 0x4b8); - map.set('kana_KE', 0x4b9); - map.set('kana_KO', 0x4ba); - map.set('kana_SA', 0x4bb); - map.set('kana_SHI', 0x4bc); - map.set('kana_SU', 0x4bd); - map.set('kana_SE', 0x4be); - map.set('kana_SO', 0x4bf); - map.set('kana_TA', 0x4c0); - map.set('kana_CHI', 0x4c1); - map.set('kana_TI', 0x4c1); - map.set('kana_TSU', 0x4c2); - map.set('kana_TU', 0x4c2); - map.set('kana_TE', 0x4c3); - map.set('kana_TO', 0x4c4); - map.set('kana_NA', 0x4c5); - map.set('kana_NI', 0x4c6); - map.set('kana_NU', 0x4c7); - map.set('kana_NE', 0x4c8); - map.set('kana_NO', 0x4c9); - map.set('kana_HA', 0x4ca); - map.set('kana_HI', 0x4cb); - map.set('kana_FU', 0x4cc); - map.set('kana_HU', 0x4cc); - map.set('kana_HE', 0x4cd); - map.set('kana_HO', 0x4ce); - map.set('kana_MA', 0x4cf); - map.set('kana_MI', 0x4d0); - map.set('kana_MU', 0x4d1); - map.set('kana_ME', 0x4d2); - map.set('kana_MO', 0x4d3); - map.set('kana_YA', 0x4d4); - map.set('kana_YU', 0x4d5); - map.set('kana_YO', 0x4d6); - map.set('kana_RA', 0x4d7); - map.set('kana_RI', 0x4d8); - map.set('kana_RU', 0x4d9); - map.set('kana_RE', 0x4da); - map.set('kana_RO', 0x4db); - map.set('kana_WA', 0x4dc); - map.set('kana_N', 0x4dd); - map.set('voicedsound', 0x4de); - map.set('semivoicedsound', 0x4df); - map.set('kana_switch', 0xff7e); - map.set('Farsi_0', 0x10006f0); - map.set('Farsi_1', 0x10006f1); - map.set('Farsi_2', 0x10006f2); - map.set('Farsi_3', 0x10006f3); - map.set('Farsi_4', 0x10006f4); - map.set('Farsi_5', 0x10006f5); - map.set('Farsi_6', 0x10006f6); - map.set('Farsi_7', 0x10006f7); - map.set('Farsi_8', 0x10006f8); - map.set('Farsi_9', 0x10006f9); - map.set('Arabic_percent', 0x100066a); - map.set('Arabic_superscript_alef', 0x1000670); - map.set('Arabic_tteh', 0x1000679); - map.set('Arabic_peh', 0x100067e); - map.set('Arabic_tcheh', 0x1000686); - map.set('Arabic_ddal', 0x1000688); - map.set('Arabic_rreh', 0x1000691); - map.set('Arabic_comma', 0x5ac); - map.set('Arabic_fullstop', 0x10006d4); - map.set('Arabic_0', 0x1000660); - map.set('Arabic_1', 0x1000661); - map.set('Arabic_2', 0x1000662); - map.set('Arabic_3', 0x1000663); - map.set('Arabic_4', 0x1000664); - map.set('Arabic_5', 0x1000665); - map.set('Arabic_6', 0x1000666); - map.set('Arabic_7', 0x1000667); - map.set('Arabic_8', 0x1000668); - map.set('Arabic_9', 0x1000669); - map.set('Arabic_semicolon', 0x5bb); - map.set('Arabic_question_mark', 0x5bf); - map.set('Arabic_hamza', 0x5c1); - map.set('Arabic_maddaonalef', 0x5c2); - map.set('Arabic_hamzaonalef', 0x5c3); - map.set('Arabic_hamzaonwaw', 0x5c4); - map.set('Arabic_hamzaunderalef', 0x5c5); - map.set('Arabic_hamzaonyeh', 0x5c6); - map.set('Arabic_alef', 0x5c7); - map.set('Arabic_beh', 0x5c8); - map.set('Arabic_tehmarbuta', 0x5c9); - map.set('Arabic_teh', 0x5ca); - map.set('Arabic_theh', 0x5cb); - map.set('Arabic_jeem', 0x5cc); - map.set('Arabic_hah', 0x5cd); - map.set('Arabic_khah', 0x5ce); - map.set('Arabic_dal', 0x5cf); - map.set('Arabic_thal', 0x5d0); - map.set('Arabic_ra', 0x5d1); - map.set('Arabic_zain', 0x5d2); - map.set('Arabic_seen', 0x5d3); - map.set('Arabic_sheen', 0x5d4); - map.set('Arabic_sad', 0x5d5); - map.set('Arabic_dad', 0x5d6); - map.set('Arabic_tah', 0x5d7); - map.set('Arabic_zah', 0x5d8); - map.set('Arabic_ain', 0x5d9); - map.set('Arabic_ghain', 0x5da); - map.set('Arabic_tatweel', 0x5e0); - map.set('Arabic_feh', 0x5e1); - map.set('Arabic_qaf', 0x5e2); - map.set('Arabic_kaf', 0x5e3); - map.set('Arabic_lam', 0x5e4); - map.set('Arabic_meem', 0x5e5); - map.set('Arabic_noon', 0x5e6); - map.set('Arabic_ha', 0x5e7); - map.set('Arabic_heh', 0x5e7); - map.set('Arabic_waw', 0x5e8); - map.set('Arabic_alefmaksura', 0x5e9); - map.set('Arabic_yeh', 0x5ea); - map.set('Arabic_fathatan', 0x5eb); - map.set('Arabic_dammatan', 0x5ec); - map.set('Arabic_kasratan', 0x5ed); - map.set('Arabic_fatha', 0x5ee); - map.set('Arabic_damma', 0x5ef); - map.set('Arabic_kasra', 0x5f0); - map.set('Arabic_shadda', 0x5f1); - map.set('Arabic_sukun', 0x5f2); - map.set('Arabic_madda_above', 0x1000653); - map.set('Arabic_hamza_above', 0x1000654); - map.set('Arabic_hamza_below', 0x1000655); - map.set('Arabic_jeh', 0x1000698); - map.set('Arabic_veh', 0x10006a4); - map.set('Arabic_keheh', 0x10006a9); - map.set('Arabic_gaf', 0x10006af); - map.set('Arabic_noon_ghunna', 0x10006ba); - map.set('Arabic_heh_doachashmee', 0x10006be); - map.set('Farsi_yeh', 0x10006cc); - map.set('Arabic_farsi_yeh', 0x10006cc); - map.set('Arabic_yeh_baree', 0x10006d2); - map.set('Arabic_heh_goal', 0x10006c1); - map.set('Arabic_switch', 0xff7e); - map.set('Cyrillic_GHE_bar', 0x1000492); - map.set('Cyrillic_ghe_bar', 0x1000493); - map.set('Cyrillic_ZHE_descender', 0x1000496); - map.set('Cyrillic_zhe_descender', 0x1000497); - map.set('Cyrillic_KA_descender', 0x100049a); - map.set('Cyrillic_ka_descender', 0x100049b); - map.set('Cyrillic_KA_vertstroke', 0x100049c); - map.set('Cyrillic_ka_vertstroke', 0x100049d); - map.set('Cyrillic_EN_descender', 0x10004a2); - map.set('Cyrillic_en_descender', 0x10004a3); - map.set('Cyrillic_U_straight', 0x10004ae); - map.set('Cyrillic_u_straight', 0x10004af); - map.set('Cyrillic_U_straight_bar', 0x10004b0); - map.set('Cyrillic_u_straight_bar', 0x10004b1); - map.set('Cyrillic_HA_descender', 0x10004b2); - map.set('Cyrillic_ha_descender', 0x10004b3); - map.set('Cyrillic_CHE_descender', 0x10004b6); - map.set('Cyrillic_che_descender', 0x10004b7); - map.set('Cyrillic_CHE_vertstroke', 0x10004b8); - map.set('Cyrillic_che_vertstroke', 0x10004b9); - map.set('Cyrillic_SHHA', 0x10004ba); - map.set('Cyrillic_shha', 0x10004bb); - map.set('Cyrillic_SCHWA', 0x10004d8); - map.set('Cyrillic_schwa', 0x10004d9); - map.set('Cyrillic_I_macron', 0x10004e2); - map.set('Cyrillic_i_macron', 0x10004e3); - map.set('Cyrillic_O_bar', 0x10004e8); - map.set('Cyrillic_o_bar', 0x10004e9); - map.set('Cyrillic_U_macron', 0x10004ee); - map.set('Cyrillic_u_macron', 0x10004ef); - map.set('Serbian_dje', 0x6a1); - map.set('Macedonia_gje', 0x6a2); - map.set('Cyrillic_io', 0x6a3); - map.set('Ukrainian_ie', 0x6a4); - map.set('Ukranian_je', 0x6a4); - map.set('Macedonia_dse', 0x6a5); - map.set('Ukrainian_i', 0x6a6); - map.set('Ukranian_i', 0x6a6); - map.set('Ukrainian_yi', 0x6a7); - map.set('Ukranian_yi', 0x6a7); - map.set('Cyrillic_je', 0x6a8); - map.set('Serbian_je', 0x6a8); - map.set('Cyrillic_lje', 0x6a9); - map.set('Serbian_lje', 0x6a9); - map.set('Cyrillic_nje', 0x6aa); - map.set('Serbian_nje', 0x6aa); - map.set('Serbian_tshe', 0x6ab); - map.set('Macedonia_kje', 0x6ac); - map.set('Ukrainian_ghe_with_upturn', 0x6ad); - map.set('Byelorussian_shortu', 0x6ae); - map.set('Cyrillic_dzhe', 0x6af); - map.set('Serbian_dze', 0x6af); - map.set('numerosign', 0x6b0); - map.set('Serbian_DJE', 0x6b1); - map.set('Macedonia_GJE', 0x6b2); - map.set('Cyrillic_IO', 0x6b3); - map.set('Ukrainian_IE', 0x6b4); - map.set('Ukranian_JE', 0x6b4); - map.set('Macedonia_DSE', 0x6b5); - map.set('Ukrainian_I', 0x6b6); - map.set('Ukranian_I', 0x6b6); - map.set('Ukrainian_YI', 0x6b7); - map.set('Ukranian_YI', 0x6b7); - map.set('Cyrillic_JE', 0x6b8); - map.set('Serbian_JE', 0x6b8); - map.set('Cyrillic_LJE', 0x6b9); - map.set('Serbian_LJE', 0x6b9); - map.set('Cyrillic_NJE', 0x6ba); - map.set('Serbian_NJE', 0x6ba); - map.set('Serbian_TSHE', 0x6bb); - map.set('Macedonia_KJE', 0x6bc); - map.set('Ukrainian_GHE_WITH_UPTURN', 0x6bd); - map.set('Byelorussian_SHORTU', 0x6be); - map.set('Cyrillic_DZHE', 0x6bf); - map.set('Serbian_DZE', 0x6bf); - map.set('Cyrillic_yu', 0x6c0); - map.set('Cyrillic_a', 0x6c1); - map.set('Cyrillic_be', 0x6c2); - map.set('Cyrillic_tse', 0x6c3); - map.set('Cyrillic_de', 0x6c4); - map.set('Cyrillic_ie', 0x6c5); - map.set('Cyrillic_ef', 0x6c6); - map.set('Cyrillic_ghe', 0x6c7); - map.set('Cyrillic_ha', 0x6c8); - map.set('Cyrillic_i', 0x6c9); - map.set('Cyrillic_shorti', 0x6ca); - map.set('Cyrillic_ka', 0x6cb); - map.set('Cyrillic_el', 0x6cc); - map.set('Cyrillic_em', 0x6cd); - map.set('Cyrillic_en', 0x6ce); - map.set('Cyrillic_o', 0x6cf); - map.set('Cyrillic_pe', 0x6d0); - map.set('Cyrillic_ya', 0x6d1); - map.set('Cyrillic_er', 0x6d2); - map.set('Cyrillic_es', 0x6d3); - map.set('Cyrillic_te', 0x6d4); - map.set('Cyrillic_u', 0x6d5); - map.set('Cyrillic_zhe', 0x6d6); - map.set('Cyrillic_ve', 0x6d7); - map.set('Cyrillic_softsign', 0x6d8); - map.set('Cyrillic_yeru', 0x6d9); - map.set('Cyrillic_ze', 0x6da); - map.set('Cyrillic_sha', 0x6db); - map.set('Cyrillic_e', 0x6dc); - map.set('Cyrillic_shcha', 0x6dd); - map.set('Cyrillic_che', 0x6de); - map.set('Cyrillic_hardsign', 0x6df); - map.set('Cyrillic_YU', 0x6e0); - map.set('Cyrillic_A', 0x6e1); - map.set('Cyrillic_BE', 0x6e2); - map.set('Cyrillic_TSE', 0x6e3); - map.set('Cyrillic_DE', 0x6e4); - map.set('Cyrillic_IE', 0x6e5); - map.set('Cyrillic_EF', 0x6e6); - map.set('Cyrillic_GHE', 0x6e7); - map.set('Cyrillic_HA', 0x6e8); - map.set('Cyrillic_I', 0x6e9); - map.set('Cyrillic_SHORTI', 0x6ea); - map.set('Cyrillic_KA', 0x6eb); - map.set('Cyrillic_EL', 0x6ec); - map.set('Cyrillic_EM', 0x6ed); - map.set('Cyrillic_EN', 0x6ee); - map.set('Cyrillic_O', 0x6ef); - map.set('Cyrillic_PE', 0x6f0); - map.set('Cyrillic_YA', 0x6f1); - map.set('Cyrillic_ER', 0x6f2); - map.set('Cyrillic_ES', 0x6f3); - map.set('Cyrillic_TE', 0x6f4); - map.set('Cyrillic_U', 0x6f5); - map.set('Cyrillic_ZHE', 0x6f6); - map.set('Cyrillic_VE', 0x6f7); - map.set('Cyrillic_SOFTSIGN', 0x6f8); - map.set('Cyrillic_YERU', 0x6f9); - map.set('Cyrillic_ZE', 0x6fa); - map.set('Cyrillic_SHA', 0x6fb); - map.set('Cyrillic_E', 0x6fc); - map.set('Cyrillic_SHCHA', 0x6fd); - map.set('Cyrillic_CHE', 0x6fe); - map.set('Cyrillic_HARDSIGN', 0x6ff); - map.set('Greek_ALPHAaccent', 0x7a1); - map.set('Greek_EPSILONaccent', 0x7a2); - map.set('Greek_ETAaccent', 0x7a3); - map.set('Greek_IOTAaccent', 0x7a4); - map.set('Greek_IOTAdieresis', 0x7a5); - map.set('Greek_IOTAdiaeresis', 0x7a5); - map.set('Greek_OMICRONaccent', 0x7a7); - map.set('Greek_UPSILONaccent', 0x7a8); - map.set('Greek_UPSILONdieresis', 0x7a9); - map.set('Greek_OMEGAaccent', 0x7ab); - map.set('Greek_accentdieresis', 0x7ae); - map.set('Greek_horizbar', 0x7af); - map.set('Greek_alphaaccent', 0x7b1); - map.set('Greek_epsilonaccent', 0x7b2); - map.set('Greek_etaaccent', 0x7b3); - map.set('Greek_iotaaccent', 0x7b4); - map.set('Greek_iotadieresis', 0x7b5); - map.set('Greek_iotaaccentdieresis', 0x7b6); - map.set('Greek_omicronaccent', 0x7b7); - map.set('Greek_upsilonaccent', 0x7b8); - map.set('Greek_upsilondieresis', 0x7b9); - map.set('Greek_upsilonaccentdieresis', 0x7ba); - map.set('Greek_omegaaccent', 0x7bb); - map.set('Greek_ALPHA', 0x7c1); - map.set('Greek_BETA', 0x7c2); - map.set('Greek_GAMMA', 0x7c3); - map.set('Greek_DELTA', 0x7c4); - map.set('Greek_EPSILON', 0x7c5); - map.set('Greek_ZETA', 0x7c6); - map.set('Greek_ETA', 0x7c7); - map.set('Greek_THETA', 0x7c8); - map.set('Greek_IOTA', 0x7c9); - map.set('Greek_KAPPA', 0x7ca); - map.set('Greek_LAMDA', 0x7cb); - map.set('Greek_LAMBDA', 0x7cb); - map.set('Greek_MU', 0x7cc); - map.set('Greek_NU', 0x7cd); - map.set('Greek_XI', 0x7ce); - map.set('Greek_OMICRON', 0x7cf); - map.set('Greek_PI', 0x7d0); - map.set('Greek_RHO', 0x7d1); - map.set('Greek_SIGMA', 0x7d2); - map.set('Greek_TAU', 0x7d4); - map.set('Greek_UPSILON', 0x7d5); - map.set('Greek_PHI', 0x7d6); - map.set('Greek_CHI', 0x7d7); - map.set('Greek_PSI', 0x7d8); - map.set('Greek_OMEGA', 0x7d9); - map.set('Greek_alpha', 0x7e1); - map.set('Greek_beta', 0x7e2); - map.set('Greek_gamma', 0x7e3); - map.set('Greek_delta', 0x7e4); - map.set('Greek_epsilon', 0x7e5); - map.set('Greek_zeta', 0x7e6); - map.set('Greek_eta', 0x7e7); - map.set('Greek_theta', 0x7e8); - map.set('Greek_iota', 0x7e9); - map.set('Greek_kappa', 0x7ea); - map.set('Greek_lamda', 0x7eb); - map.set('Greek_lambda', 0x7eb); - map.set('Greek_mu', 0x7ec); - map.set('Greek_nu', 0x7ed); - map.set('Greek_xi', 0x7ee); - map.set('Greek_omicron', 0x7ef); - map.set('Greek_pi', 0x7f0); - map.set('Greek_rho', 0x7f1); - map.set('Greek_sigma', 0x7f2); - map.set('Greek_finalsmallsigma', 0x7f3); - map.set('Greek_tau', 0x7f4); - map.set('Greek_upsilon', 0x7f5); - map.set('Greek_phi', 0x7f6); - map.set('Greek_chi', 0x7f7); - map.set('Greek_psi', 0x7f8); - map.set('Greek_omega', 0x7f9); - map.set('Greek_switch', 0xff7e); - map.set('leftradical', 0x8a1); - map.set('topleftradical', 0x8a2); - map.set('horizconnector', 0x8a3); - map.set('topintegral', 0x8a4); - map.set('botintegral', 0x8a5); - map.set('vertconnector', 0x8a6); - map.set('topleftsqbracket', 0x8a7); - map.set('botleftsqbracket', 0x8a8); - map.set('toprightsqbracket', 0x8a9); - map.set('botrightsqbracket', 0x8aa); - map.set('topleftparens', 0x8ab); - map.set('botleftparens', 0x8ac); - map.set('toprightparens', 0x8ad); - map.set('botrightparens', 0x8ae); - map.set('leftmiddlecurlybrace', 0x8af); - map.set('rightmiddlecurlybrace', 0x8b0); - map.set('topleftsummation', 0x8b1); - map.set('botleftsummation', 0x8b2); - map.set('topvertsummationconnector', 0x8b3); - map.set('botvertsummationconnector', 0x8b4); - map.set('toprightsummation', 0x8b5); - map.set('botrightsummation', 0x8b6); - map.set('rightmiddlesummation', 0x8b7); - map.set('lessthanequal', 0x8bc); - map.set('notequal', 0x8bd); - map.set('greaterthanequal', 0x8be); - map.set('integral', 0x8bf); - map.set('therefore', 0x8c0); - map.set('variation', 0x8c1); - map.set('infinity', 0x8c2); - map.set('nabla', 0x8c5); - map.set('approximate', 0x8c8); - map.set('similarequal', 0x8c9); - map.set('ifonlyif', 0x8cd); - map.set('implies', 0x8ce); - map.set('identical', 0x8cf); - map.set('radical', 0x8d6); - map.set('includedin', 0x8da); - map.set('includes', 0x8db); - map.set('intersection', 0x8dc); - map.set('union', 0x8dd); - map.set('logicaland', 0x8de); - map.set('logicalor', 0x8df); - map.set('partialderivative', 0x8ef); - map.set('function', 0x8f6); - map.set('leftarrow', 0x8fb); - map.set('uparrow', 0x8fc); - map.set('rightarrow', 0x8fd); - map.set('downarrow', 0x8fe); - map.set('blank', 0x9df); - map.set('soliddiamond', 0x9e0); - map.set('checkerboard', 0x9e1); - map.set('ht', 0x9e2); - map.set('ff', 0x9e3); - map.set('cr', 0x9e4); - map.set('lf', 0x9e5); - map.set('nl', 0x9e8); - map.set('vt', 0x9e9); - map.set('lowrightcorner', 0x9ea); - map.set('uprightcorner', 0x9eb); - map.set('upleftcorner', 0x9ec); - map.set('lowleftcorner', 0x9ed); - map.set('crossinglines', 0x9ee); - map.set('horizlinescan1', 0x9ef); - map.set('horizlinescan3', 0x9f0); - map.set('horizlinescan5', 0x9f1); - map.set('horizlinescan7', 0x9f2); - map.set('horizlinescan9', 0x9f3); - map.set('leftt', 0x9f4); - map.set('rightt', 0x9f5); - map.set('bott', 0x9f6); - map.set('topt', 0x9f7); - map.set('vertbar', 0x9f8); - map.set('emspace', 0xaa1); - map.set('enspace', 0xaa2); - map.set('em3space', 0xaa3); - map.set('em4space', 0xaa4); - map.set('digitspace', 0xaa5); - map.set('punctspace', 0xaa6); - map.set('thinspace', 0xaa7); - map.set('hairspace', 0xaa8); - map.set('emdash', 0xaa9); - map.set('endash', 0xaaa); - map.set('signifblank', 0xaac); - map.set('ellipsis', 0xaae); - map.set('doubbaselinedot', 0xaaf); - map.set('onethird', 0xab0); - map.set('twothirds', 0xab1); - map.set('onefifth', 0xab2); - map.set('twofifths', 0xab3); - map.set('threefifths', 0xab4); - map.set('fourfifths', 0xab5); - map.set('onesixth', 0xab6); - map.set('fivesixths', 0xab7); - map.set('careof', 0xab8); - map.set('figdash', 0xabb); - map.set('leftanglebracket', 0xabc); - map.set('decimalpoint', 0xabd); - map.set('rightanglebracket', 0xabe); - map.set('marker', 0xabf); - map.set('oneeighth', 0xac3); - map.set('threeeighths', 0xac4); - map.set('fiveeighths', 0xac5); - map.set('seveneighths', 0xac6); - map.set('trademark', 0xac9); - map.set('signaturemark', 0xaca); - map.set('trademarkincircle', 0xacb); - map.set('leftopentriangle', 0xacc); - map.set('rightopentriangle', 0xacd); - map.set('emopencircle', 0xace); - map.set('emopenrectangle', 0xacf); - map.set('leftsinglequotemark', 0xad0); - map.set('rightsinglequotemark', 0xad1); - map.set('leftdoublequotemark', 0xad2); - map.set('rightdoublequotemark', 0xad3); - map.set('prescription', 0xad4); - map.set('permille', 0xad5); - map.set('minutes', 0xad6); - map.set('seconds', 0xad7); - map.set('latincross', 0xad9); - map.set('hexagram', 0xada); - map.set('filledrectbullet', 0xadb); - map.set('filledlefttribullet', 0xadc); - map.set('filledrighttribullet', 0xadd); - map.set('emfilledcircle', 0xade); - map.set('emfilledrect', 0xadf); - map.set('enopencircbullet', 0xae0); - map.set('enopensquarebullet', 0xae1); - map.set('openrectbullet', 0xae2); - map.set('opentribulletup', 0xae3); - map.set('opentribulletdown', 0xae4); - map.set('openstar', 0xae5); - map.set('enfilledcircbullet', 0xae6); - map.set('enfilledsqbullet', 0xae7); - map.set('filledtribulletup', 0xae8); - map.set('filledtribulletdown', 0xae9); - map.set('leftpointer', 0xaea); - map.set('rightpointer', 0xaeb); - map.set('club', 0xaec); - map.set('diamond', 0xaed); - map.set('heart', 0xaee); - map.set('maltesecross', 0xaf0); - map.set('dagger', 0xaf1); - map.set('doubledagger', 0xaf2); - map.set('checkmark', 0xaf3); - map.set('ballotcross', 0xaf4); - map.set('musicalsharp', 0xaf5); - map.set('musicalflat', 0xaf6); - map.set('malesymbol', 0xaf7); - map.set('femalesymbol', 0xaf8); - map.set('telephone', 0xaf9); - map.set('telephonerecorder', 0xafa); - map.set('phonographcopyright', 0xafb); - map.set('caret', 0xafc); - map.set('singlelowquotemark', 0xafd); - map.set('doublelowquotemark', 0xafe); - map.set('cursor', 0xaff); - map.set('leftcaret', 0xba3); - map.set('rightcaret', 0xba6); - map.set('downcaret', 0xba8); - map.set('upcaret', 0xba9); - map.set('overbar', 0xbc0); - map.set('downtack', 0xbc2); - map.set('upshoe', 0xbc3); - map.set('downstile', 0xbc4); - map.set('underbar', 0xbc6); - map.set('jot', 0xbca); - map.set('quad', 0xbcc); - map.set('uptack', 0xbce); - map.set('circle', 0xbcf); - map.set('upstile', 0xbd3); - map.set('downshoe', 0xbd6); - map.set('rightshoe', 0xbd8); - map.set('leftshoe', 0xbda); - map.set('lefttack', 0xbdc); - map.set('righttack', 0xbfc); - map.set('hebrew_doublelowline', 0xcdf); - map.set('hebrew_aleph', 0xce0); - map.set('hebrew_bet', 0xce1); - map.set('hebrew_beth', 0xce1); - map.set('hebrew_gimel', 0xce2); - map.set('hebrew_gimmel', 0xce2); - map.set('hebrew_dalet', 0xce3); - map.set('hebrew_daleth', 0xce3); - map.set('hebrew_he', 0xce4); - map.set('hebrew_waw', 0xce5); - map.set('hebrew_zain', 0xce6); - map.set('hebrew_zayin', 0xce6); - map.set('hebrew_chet', 0xce7); - map.set('hebrew_het', 0xce7); - map.set('hebrew_tet', 0xce8); - map.set('hebrew_teth', 0xce8); - map.set('hebrew_yod', 0xce9); - map.set('hebrew_finalkaph', 0xcea); - map.set('hebrew_kaph', 0xceb); - map.set('hebrew_lamed', 0xcec); - map.set('hebrew_finalmem', 0xced); - map.set('hebrew_mem', 0xcee); - map.set('hebrew_finalnun', 0xcef); - map.set('hebrew_nun', 0xcf0); - map.set('hebrew_samech', 0xcf1); - map.set('hebrew_samekh', 0xcf1); - map.set('hebrew_ayin', 0xcf2); - map.set('hebrew_finalpe', 0xcf3); - map.set('hebrew_pe', 0xcf4); - map.set('hebrew_finalzade', 0xcf5); - map.set('hebrew_finalzadi', 0xcf5); - map.set('hebrew_zade', 0xcf6); - map.set('hebrew_zadi', 0xcf6); - map.set('hebrew_qoph', 0xcf7); - map.set('hebrew_kuf', 0xcf7); - map.set('hebrew_resh', 0xcf8); - map.set('hebrew_shin', 0xcf9); - map.set('hebrew_taw', 0xcfa); - map.set('hebrew_taf', 0xcfa); - map.set('Hebrew_switch', 0xff7e); - map.set('Thai_kokai', 0xda1); - map.set('Thai_khokhai', 0xda2); - map.set('Thai_khokhuat', 0xda3); - map.set('Thai_khokhwai', 0xda4); - map.set('Thai_khokhon', 0xda5); - map.set('Thai_khorakhang', 0xda6); - map.set('Thai_ngongu', 0xda7); - map.set('Thai_chochan', 0xda8); - map.set('Thai_choching', 0xda9); - map.set('Thai_chochang', 0xdaa); - map.set('Thai_soso', 0xdab); - map.set('Thai_chochoe', 0xdac); - map.set('Thai_yoying', 0xdad); - map.set('Thai_dochada', 0xdae); - map.set('Thai_topatak', 0xdaf); - map.set('Thai_thothan', 0xdb0); - map.set('Thai_thonangmontho', 0xdb1); - map.set('Thai_thophuthao', 0xdb2); - map.set('Thai_nonen', 0xdb3); - map.set('Thai_dodek', 0xdb4); - map.set('Thai_totao', 0xdb5); - map.set('Thai_thothung', 0xdb6); - map.set('Thai_thothahan', 0xdb7); - map.set('Thai_thothong', 0xdb8); - map.set('Thai_nonu', 0xdb9); - map.set('Thai_bobaimai', 0xdba); - map.set('Thai_popla', 0xdbb); - map.set('Thai_phophung', 0xdbc); - map.set('Thai_fofa', 0xdbd); - map.set('Thai_phophan', 0xdbe); - map.set('Thai_fofan', 0xdbf); - map.set('Thai_phosamphao', 0xdc0); - map.set('Thai_moma', 0xdc1); - map.set('Thai_yoyak', 0xdc2); - map.set('Thai_rorua', 0xdc3); - map.set('Thai_ru', 0xdc4); - map.set('Thai_loling', 0xdc5); - map.set('Thai_lu', 0xdc6); - map.set('Thai_wowaen', 0xdc7); - map.set('Thai_sosala', 0xdc8); - map.set('Thai_sorusi', 0xdc9); - map.set('Thai_sosua', 0xdca); - map.set('Thai_hohip', 0xdcb); - map.set('Thai_lochula', 0xdcc); - map.set('Thai_oang', 0xdcd); - map.set('Thai_honokhuk', 0xdce); - map.set('Thai_paiyannoi', 0xdcf); - map.set('Thai_saraa', 0xdd0); - map.set('Thai_maihanakat', 0xdd1); - map.set('Thai_saraaa', 0xdd2); - map.set('Thai_saraam', 0xdd3); - map.set('Thai_sarai', 0xdd4); - map.set('Thai_saraii', 0xdd5); - map.set('Thai_saraue', 0xdd6); - map.set('Thai_sarauee', 0xdd7); - map.set('Thai_sarau', 0xdd8); - map.set('Thai_sarauu', 0xdd9); - map.set('Thai_phinthu', 0xdda); - map.set('Thai_maihanakat_maitho', 0xdde); - map.set('Thai_baht', 0xddf); - map.set('Thai_sarae', 0xde0); - map.set('Thai_saraae', 0xde1); - map.set('Thai_sarao', 0xde2); - map.set('Thai_saraaimaimuan', 0xde3); - map.set('Thai_saraaimaimalai', 0xde4); - map.set('Thai_lakkhangyao', 0xde5); - map.set('Thai_maiyamok', 0xde6); - map.set('Thai_maitaikhu', 0xde7); - map.set('Thai_maiek', 0xde8); - map.set('Thai_maitho', 0xde9); - map.set('Thai_maitri', 0xdea); - map.set('Thai_maichattawa', 0xdeb); - map.set('Thai_thanthakhat', 0xdec); - map.set('Thai_nikhahit', 0xded); - map.set('Thai_leksun', 0xdf0); - map.set('Thai_leknung', 0xdf1); - map.set('Thai_leksong', 0xdf2); - map.set('Thai_leksam', 0xdf3); - map.set('Thai_leksi', 0xdf4); - map.set('Thai_lekha', 0xdf5); - map.set('Thai_lekhok', 0xdf6); - map.set('Thai_lekchet', 0xdf7); - map.set('Thai_lekpaet', 0xdf8); - map.set('Thai_lekkao', 0xdf9); - map.set('Hangul', 0xff31); - map.set('Hangul_Start', 0xff32); - map.set('Hangul_End', 0xff33); - map.set('Hangul_Hanja', 0xff34); - map.set('Hangul_Jamo', 0xff35); - map.set('Hangul_Romaja', 0xff36); - map.set('Hangul_Codeinput', 0xff37); - map.set('Hangul_Jeonja', 0xff38); - map.set('Hangul_Banja', 0xff39); - map.set('Hangul_PreHanja', 0xff3a); - map.set('Hangul_PostHanja', 0xff3b); - map.set('Hangul_SingleCandidate', 0xff3c); - map.set('Hangul_MultipleCandidate', 0xff3d); - map.set('Hangul_PreviousCandidate', 0xff3e); - map.set('Hangul_Special', 0xff3f); - map.set('Hangul_switch', 0xff7e); - map.set('Hangul_Kiyeog', 0xea1); - map.set('Hangul_SsangKiyeog', 0xea2); - map.set('Hangul_KiyeogSios', 0xea3); - map.set('Hangul_Nieun', 0xea4); - map.set('Hangul_NieunJieuj', 0xea5); - map.set('Hangul_NieunHieuh', 0xea6); - map.set('Hangul_Dikeud', 0xea7); - map.set('Hangul_SsangDikeud', 0xea8); - map.set('Hangul_Rieul', 0xea9); - map.set('Hangul_RieulKiyeog', 0xeaa); - map.set('Hangul_RieulMieum', 0xeab); - map.set('Hangul_RieulPieub', 0xeac); - map.set('Hangul_RieulSios', 0xead); - map.set('Hangul_RieulTieut', 0xeae); - map.set('Hangul_RieulPhieuf', 0xeaf); - map.set('Hangul_RieulHieuh', 0xeb0); - map.set('Hangul_Mieum', 0xeb1); - map.set('Hangul_Pieub', 0xeb2); - map.set('Hangul_SsangPieub', 0xeb3); - map.set('Hangul_PieubSios', 0xeb4); - map.set('Hangul_Sios', 0xeb5); - map.set('Hangul_SsangSios', 0xeb6); - map.set('Hangul_Ieung', 0xeb7); - map.set('Hangul_Jieuj', 0xeb8); - map.set('Hangul_SsangJieuj', 0xeb9); - map.set('Hangul_Cieuc', 0xeba); - map.set('Hangul_Khieuq', 0xebb); - map.set('Hangul_Tieut', 0xebc); - map.set('Hangul_Phieuf', 0xebd); - map.set('Hangul_Hieuh', 0xebe); - map.set('Hangul_A', 0xebf); - map.set('Hangul_AE', 0xec0); - map.set('Hangul_YA', 0xec1); - map.set('Hangul_YAE', 0xec2); - map.set('Hangul_EO', 0xec3); - map.set('Hangul_E', 0xec4); - map.set('Hangul_YEO', 0xec5); - map.set('Hangul_YE', 0xec6); - map.set('Hangul_O', 0xec7); - map.set('Hangul_WA', 0xec8); - map.set('Hangul_WAE', 0xec9); - map.set('Hangul_OE', 0xeca); - map.set('Hangul_YO', 0xecb); - map.set('Hangul_U', 0xecc); - map.set('Hangul_WEO', 0xecd); - map.set('Hangul_WE', 0xece); - map.set('Hangul_WI', 0xecf); - map.set('Hangul_YU', 0xed0); - map.set('Hangul_EU', 0xed1); - map.set('Hangul_YI', 0xed2); - map.set('Hangul_I', 0xed3); - map.set('Hangul_J_Kiyeog', 0xed4); - map.set('Hangul_J_SsangKiyeog', 0xed5); - map.set('Hangul_J_KiyeogSios', 0xed6); - map.set('Hangul_J_Nieun', 0xed7); - map.set('Hangul_J_NieunJieuj', 0xed8); - map.set('Hangul_J_NieunHieuh', 0xed9); - map.set('Hangul_J_Dikeud', 0xeda); - map.set('Hangul_J_Rieul', 0xedb); - map.set('Hangul_J_RieulKiyeog', 0xedc); - map.set('Hangul_J_RieulMieum', 0xedd); - map.set('Hangul_J_RieulPieub', 0xede); - map.set('Hangul_J_RieulSios', 0xedf); - map.set('Hangul_J_RieulTieut', 0xee0); - map.set('Hangul_J_RieulPhieuf', 0xee1); - map.set('Hangul_J_RieulHieuh', 0xee2); - map.set('Hangul_J_Mieum', 0xee3); - map.set('Hangul_J_Pieub', 0xee4); - map.set('Hangul_J_PieubSios', 0xee5); - map.set('Hangul_J_Sios', 0xee6); - map.set('Hangul_J_SsangSios', 0xee7); - map.set('Hangul_J_Ieung', 0xee8); - map.set('Hangul_J_Jieuj', 0xee9); - map.set('Hangul_J_Cieuc', 0xeea); - map.set('Hangul_J_Khieuq', 0xeeb); - map.set('Hangul_J_Tieut', 0xeec); - map.set('Hangul_J_Phieuf', 0xeed); - map.set('Hangul_J_Hieuh', 0xeee); - map.set('Hangul_RieulYeorinHieuh', 0xeef); - map.set('Hangul_SunkyeongeumMieum', 0xef0); - map.set('Hangul_SunkyeongeumPieub', 0xef1); - map.set('Hangul_PanSios', 0xef2); - map.set('Hangul_KkogjiDalrinIeung', 0xef3); - map.set('Hangul_SunkyeongeumPhieuf', 0xef4); - map.set('Hangul_YeorinHieuh', 0xef5); - map.set('Hangul_AraeA', 0xef6); - map.set('Hangul_AraeAE', 0xef7); - map.set('Hangul_J_PanSios', 0xef8); - map.set('Hangul_J_KkogjiDalrinIeung', 0xef9); - map.set('Hangul_J_YeorinHieuh', 0xefa); - map.set('Korean_Won', 0xeff); - map.set('Armenian_ligature_ew', 0x1000587); - map.set('Armenian_full_stop', 0x1000589); - map.set('Armenian_verjaket', 0x1000589); - map.set('Armenian_separation_mark', 0x100055d); - map.set('Armenian_but', 0x100055d); - map.set('Armenian_hyphen', 0x100058a); - map.set('Armenian_yentamna', 0x100058a); - map.set('Armenian_exclam', 0x100055c); - map.set('Armenian_amanak', 0x100055c); - map.set('Armenian_accent', 0x100055b); - map.set('Armenian_shesht', 0x100055b); - map.set('Armenian_question', 0x100055e); - map.set('Armenian_paruyk', 0x100055e); - map.set('Armenian_AYB', 0x1000531); - map.set('Armenian_ayb', 0x1000561); - map.set('Armenian_BEN', 0x1000532); - map.set('Armenian_ben', 0x1000562); - map.set('Armenian_GIM', 0x1000533); - map.set('Armenian_gim', 0x1000563); - map.set('Armenian_DA', 0x1000534); - map.set('Armenian_da', 0x1000564); - map.set('Armenian_YECH', 0x1000535); - map.set('Armenian_yech', 0x1000565); - map.set('Armenian_ZA', 0x1000536); - map.set('Armenian_za', 0x1000566); - map.set('Armenian_E', 0x1000537); - map.set('Armenian_e', 0x1000567); - map.set('Armenian_AT', 0x1000538); - map.set('Armenian_at', 0x1000568); - map.set('Armenian_TO', 0x1000539); - map.set('Armenian_to', 0x1000569); - map.set('Armenian_ZHE', 0x100053a); - map.set('Armenian_zhe', 0x100056a); - map.set('Armenian_INI', 0x100053b); - map.set('Armenian_ini', 0x100056b); - map.set('Armenian_LYUN', 0x100053c); - map.set('Armenian_lyun', 0x100056c); - map.set('Armenian_KHE', 0x100053d); - map.set('Armenian_khe', 0x100056d); - map.set('Armenian_TSA', 0x100053e); - map.set('Armenian_tsa', 0x100056e); - map.set('Armenian_KEN', 0x100053f); - map.set('Armenian_ken', 0x100056f); - map.set('Armenian_HO', 0x1000540); - map.set('Armenian_ho', 0x1000570); - map.set('Armenian_DZA', 0x1000541); - map.set('Armenian_dza', 0x1000571); - map.set('Armenian_GHAT', 0x1000542); - map.set('Armenian_ghat', 0x1000572); - map.set('Armenian_TCHE', 0x1000543); - map.set('Armenian_tche', 0x1000573); - map.set('Armenian_MEN', 0x1000544); - map.set('Armenian_men', 0x1000574); - map.set('Armenian_HI', 0x1000545); - map.set('Armenian_hi', 0x1000575); - map.set('Armenian_NU', 0x1000546); - map.set('Armenian_nu', 0x1000576); - map.set('Armenian_SHA', 0x1000547); - map.set('Armenian_sha', 0x1000577); - map.set('Armenian_VO', 0x1000548); - map.set('Armenian_vo', 0x1000578); - map.set('Armenian_CHA', 0x1000549); - map.set('Armenian_cha', 0x1000579); - map.set('Armenian_PE', 0x100054a); - map.set('Armenian_pe', 0x100057a); - map.set('Armenian_JE', 0x100054b); - map.set('Armenian_je', 0x100057b); - map.set('Armenian_RA', 0x100054c); - map.set('Armenian_ra', 0x100057c); - map.set('Armenian_SE', 0x100054d); - map.set('Armenian_se', 0x100057d); - map.set('Armenian_VEV', 0x100054e); - map.set('Armenian_vev', 0x100057e); - map.set('Armenian_TYUN', 0x100054f); - map.set('Armenian_tyun', 0x100057f); - map.set('Armenian_RE', 0x1000550); - map.set('Armenian_re', 0x1000580); - map.set('Armenian_TSO', 0x1000551); - map.set('Armenian_tso', 0x1000581); - map.set('Armenian_VYUN', 0x1000552); - map.set('Armenian_vyun', 0x1000582); - map.set('Armenian_PYUR', 0x1000553); - map.set('Armenian_pyur', 0x1000583); - map.set('Armenian_KE', 0x1000554); - map.set('Armenian_ke', 0x1000584); - map.set('Armenian_O', 0x1000555); - map.set('Armenian_o', 0x1000585); - map.set('Armenian_FE', 0x1000556); - map.set('Armenian_fe', 0x1000586); - map.set('Armenian_apostrophe', 0x100055a); - map.set('Georgian_an', 0x10010d0); - map.set('Georgian_ban', 0x10010d1); - map.set('Georgian_gan', 0x10010d2); - map.set('Georgian_don', 0x10010d3); - map.set('Georgian_en', 0x10010d4); - map.set('Georgian_vin', 0x10010d5); - map.set('Georgian_zen', 0x10010d6); - map.set('Georgian_tan', 0x10010d7); - map.set('Georgian_in', 0x10010d8); - map.set('Georgian_kan', 0x10010d9); - map.set('Georgian_las', 0x10010da); - map.set('Georgian_man', 0x10010db); - map.set('Georgian_nar', 0x10010dc); - map.set('Georgian_on', 0x10010dd); - map.set('Georgian_par', 0x10010de); - map.set('Georgian_zhar', 0x10010df); - map.set('Georgian_rae', 0x10010e0); - map.set('Georgian_san', 0x10010e1); - map.set('Georgian_tar', 0x10010e2); - map.set('Georgian_un', 0x10010e3); - map.set('Georgian_phar', 0x10010e4); - map.set('Georgian_khar', 0x10010e5); - map.set('Georgian_ghan', 0x10010e6); - map.set('Georgian_qar', 0x10010e7); - map.set('Georgian_shin', 0x10010e8); - map.set('Georgian_chin', 0x10010e9); - map.set('Georgian_can', 0x10010ea); - map.set('Georgian_jil', 0x10010eb); - map.set('Georgian_cil', 0x10010ec); - map.set('Georgian_char', 0x10010ed); - map.set('Georgian_xan', 0x10010ee); - map.set('Georgian_jhan', 0x10010ef); - map.set('Georgian_hae', 0x10010f0); - map.set('Georgian_he', 0x10010f1); - map.set('Georgian_hie', 0x10010f2); - map.set('Georgian_we', 0x10010f3); - map.set('Georgian_har', 0x10010f4); - map.set('Georgian_hoe', 0x10010f5); - map.set('Georgian_fi', 0x10010f6); - map.set('Xabovedot', 0x1001e8a); - map.set('Ibreve', 0x100012c); - map.set('Zstroke', 0x10001b5); - map.set('Gcaron', 0x10001e6); - map.set('Ocaron', 0x10001d1); - map.set('Obarred', 0x100019f); - map.set('xabovedot', 0x1001e8b); - map.set('ibreve', 0x100012d); - map.set('zstroke', 0x10001b6); - map.set('gcaron', 0x10001e7); - map.set('ocaron', 0x10001d2); - map.set('obarred', 0x1000275); - map.set('SCHWA', 0x100018f); - map.set('schwa', 0x1000259); - map.set('EZH', 0x10001b7); - map.set('ezh', 0x1000292); - map.set('Lbelowdot', 0x1001e36); - map.set('lbelowdot', 0x1001e37); - map.set('Abelowdot', 0x1001ea0); - map.set('abelowdot', 0x1001ea1); - map.set('Ahook', 0x1001ea2); - map.set('ahook', 0x1001ea3); - map.set('Acircumflexacute', 0x1001ea4); - map.set('acircumflexacute', 0x1001ea5); - map.set('Acircumflexgrave', 0x1001ea6); - map.set('acircumflexgrave', 0x1001ea7); - map.set('Acircumflexhook', 0x1001ea8); - map.set('acircumflexhook', 0x1001ea9); - map.set('Acircumflextilde', 0x1001eaa); - map.set('acircumflextilde', 0x1001eab); - map.set('Acircumflexbelowdot', 0x1001eac); - map.set('acircumflexbelowdot', 0x1001ead); - map.set('Abreveacute', 0x1001eae); - map.set('abreveacute', 0x1001eaf); - map.set('Abrevegrave', 0x1001eb0); - map.set('abrevegrave', 0x1001eb1); - map.set('Abrevehook', 0x1001eb2); - map.set('abrevehook', 0x1001eb3); - map.set('Abrevetilde', 0x1001eb4); - map.set('abrevetilde', 0x1001eb5); - map.set('Abrevebelowdot', 0x1001eb6); - map.set('abrevebelowdot', 0x1001eb7); - map.set('Ebelowdot', 0x1001eb8); - map.set('ebelowdot', 0x1001eb9); - map.set('Ehook', 0x1001eba); - map.set('ehook', 0x1001ebb); - map.set('Etilde', 0x1001ebc); - map.set('etilde', 0x1001ebd); - map.set('Ecircumflexacute', 0x1001ebe); - map.set('ecircumflexacute', 0x1001ebf); - map.set('Ecircumflexgrave', 0x1001ec0); - map.set('ecircumflexgrave', 0x1001ec1); - map.set('Ecircumflexhook', 0x1001ec2); - map.set('ecircumflexhook', 0x1001ec3); - map.set('Ecircumflextilde', 0x1001ec4); - map.set('ecircumflextilde', 0x1001ec5); - map.set('Ecircumflexbelowdot', 0x1001ec6); - map.set('ecircumflexbelowdot', 0x1001ec7); - map.set('Ihook', 0x1001ec8); - map.set('ihook', 0x1001ec9); - map.set('Ibelowdot', 0x1001eca); - map.set('ibelowdot', 0x1001ecb); - map.set('Obelowdot', 0x1001ecc); - map.set('obelowdot', 0x1001ecd); - map.set('Ohook', 0x1001ece); - map.set('ohook', 0x1001ecf); - map.set('Ocircumflexacute', 0x1001ed0); - map.set('ocircumflexacute', 0x1001ed1); - map.set('Ocircumflexgrave', 0x1001ed2); - map.set('ocircumflexgrave', 0x1001ed3); - map.set('Ocircumflexhook', 0x1001ed4); - map.set('ocircumflexhook', 0x1001ed5); - map.set('Ocircumflextilde', 0x1001ed6); - map.set('ocircumflextilde', 0x1001ed7); - map.set('Ocircumflexbelowdot', 0x1001ed8); - map.set('ocircumflexbelowdot', 0x1001ed9); - map.set('Ohornacute', 0x1001eda); - map.set('ohornacute', 0x1001edb); - map.set('Ohorngrave', 0x1001edc); - map.set('ohorngrave', 0x1001edd); - map.set('Ohornhook', 0x1001ede); - map.set('ohornhook', 0x1001edf); - map.set('Ohorntilde', 0x1001ee0); - map.set('ohorntilde', 0x1001ee1); - map.set('Ohornbelowdot', 0x1001ee2); - map.set('ohornbelowdot', 0x1001ee3); - map.set('Ubelowdot', 0x1001ee4); - map.set('ubelowdot', 0x1001ee5); - map.set('Uhook', 0x1001ee6); - map.set('uhook', 0x1001ee7); - map.set('Uhornacute', 0x1001ee8); - map.set('uhornacute', 0x1001ee9); - map.set('Uhorngrave', 0x1001eea); - map.set('uhorngrave', 0x1001eeb); - map.set('Uhornhook', 0x1001eec); - map.set('uhornhook', 0x1001eed); - map.set('Uhorntilde', 0x1001eee); - map.set('uhorntilde', 0x1001eef); - map.set('Uhornbelowdot', 0x1001ef0); - map.set('uhornbelowdot', 0x1001ef1); - map.set('Ybelowdot', 0x1001ef4); - map.set('ybelowdot', 0x1001ef5); - map.set('Yhook', 0x1001ef6); - map.set('yhook', 0x1001ef7); - map.set('Ytilde', 0x1001ef8); - map.set('ytilde', 0x1001ef9); - map.set('Ohorn', 0x10001a0); - map.set('ohorn', 0x10001a1); - map.set('Uhorn', 0x10001af); - map.set('uhorn', 0x10001b0); - map.set('EcuSign', 0x10020a0); - map.set('ColonSign', 0x10020a1); - map.set('CruzeiroSign', 0x10020a2); - map.set('FFrancSign', 0x10020a3); - map.set('LiraSign', 0x10020a4); - map.set('MillSign', 0x10020a5); - map.set('NairaSign', 0x10020a6); - map.set('PesetaSign', 0x10020a7); - map.set('RupeeSign', 0x10020a8); - map.set('WonSign', 0x10020a9); - map.set('NewSheqelSign', 0x10020aa); - map.set('DongSign', 0x10020ab); - map.set('EuroSign', 0x20ac); - map.set('zerosuperior', 0x1002070); - map.set('foursuperior', 0x1002074); - map.set('fivesuperior', 0x1002075); - map.set('sixsuperior', 0x1002076); - map.set('sevensuperior', 0x1002077); - map.set('eightsuperior', 0x1002078); - map.set('ninesuperior', 0x1002079); - map.set('zerosubscript', 0x1002080); - map.set('onesubscript', 0x1002081); - map.set('twosubscript', 0x1002082); - map.set('threesubscript', 0x1002083); - map.set('foursubscript', 0x1002084); - map.set('fivesubscript', 0x1002085); - map.set('sixsubscript', 0x1002086); - map.set('sevensubscript', 0x1002087); - map.set('eightsubscript', 0x1002088); - map.set('ninesubscript', 0x1002089); - map.set('partdifferential', 0x1002202); - map.set('emptyset', 0x1002205); - map.set('elementof', 0x1002208); - map.set('notelementof', 0x1002209); - map.set('containsas', 0x100220b); - map.set('squareroot', 0x100221a); - map.set('cuberoot', 0x100221b); - map.set('fourthroot', 0x100221c); - map.set('dintegral', 0x100222c); - map.set('tintegral', 0x100222d); - map.set('because', 0x1002235); - map.set('approxeq', 0x1002248); - map.set('notapproxeq', 0x1002247); - map.set('notidentical', 0x1002262); - map.set('stricteq', 0x1002263); - map.set('braille_dot_1', 0xfff1); - map.set('braille_dot_2', 0xfff2); - map.set('braille_dot_3', 0xfff3); - map.set('braille_dot_4', 0xfff4); - map.set('braille_dot_5', 0xfff5); - map.set('braille_dot_6', 0xfff6); - map.set('braille_dot_7', 0xfff7); - map.set('braille_dot_8', 0xfff8); - map.set('braille_dot_9', 0xfff9); - map.set('braille_dot_10', 0xfffa); - map.set('braille_blank', 0x1002800); - map.set('braille_dots_1', 0x1002801); - map.set('braille_dots_2', 0x1002802); - map.set('braille_dots_12', 0x1002803); - map.set('braille_dots_3', 0x1002804); - map.set('braille_dots_13', 0x1002805); - map.set('braille_dots_23', 0x1002806); - map.set('braille_dots_123', 0x1002807); - map.set('braille_dots_4', 0x1002808); - map.set('braille_dots_14', 0x1002809); - map.set('braille_dots_24', 0x100280a); - map.set('braille_dots_124', 0x100280b); - map.set('braille_dots_34', 0x100280c); - map.set('braille_dots_134', 0x100280d); - map.set('braille_dots_234', 0x100280e); - map.set('braille_dots_1234', 0x100280f); - map.set('braille_dots_5', 0x1002810); - map.set('braille_dots_15', 0x1002811); - map.set('braille_dots_25', 0x1002812); - map.set('braille_dots_125', 0x1002813); - map.set('braille_dots_35', 0x1002814); - map.set('braille_dots_135', 0x1002815); - map.set('braille_dots_235', 0x1002816); - map.set('braille_dots_1235', 0x1002817); - map.set('braille_dots_45', 0x1002818); - map.set('braille_dots_145', 0x1002819); - map.set('braille_dots_245', 0x100281a); - map.set('braille_dots_1245', 0x100281b); - map.set('braille_dots_345', 0x100281c); - map.set('braille_dots_1345', 0x100281d); - map.set('braille_dots_2345', 0x100281e); - map.set('braille_dots_12345', 0x100281f); - map.set('braille_dots_6', 0x1002820); - map.set('braille_dots_16', 0x1002821); - map.set('braille_dots_26', 0x1002822); - map.set('braille_dots_126', 0x1002823); - map.set('braille_dots_36', 0x1002824); - map.set('braille_dots_136', 0x1002825); - map.set('braille_dots_236', 0x1002826); - map.set('braille_dots_1236', 0x1002827); - map.set('braille_dots_46', 0x1002828); - map.set('braille_dots_146', 0x1002829); - map.set('braille_dots_246', 0x100282a); - map.set('braille_dots_1246', 0x100282b); - map.set('braille_dots_346', 0x100282c); - map.set('braille_dots_1346', 0x100282d); - map.set('braille_dots_2346', 0x100282e); - map.set('braille_dots_12346', 0x100282f); - map.set('braille_dots_56', 0x1002830); - map.set('braille_dots_156', 0x1002831); - map.set('braille_dots_256', 0x1002832); - map.set('braille_dots_1256', 0x1002833); - map.set('braille_dots_356', 0x1002834); - map.set('braille_dots_1356', 0x1002835); - map.set('braille_dots_2356', 0x1002836); - map.set('braille_dots_12356', 0x1002837); - map.set('braille_dots_456', 0x1002838); - map.set('braille_dots_1456', 0x1002839); - map.set('braille_dots_2456', 0x100283a); - map.set('braille_dots_12456', 0x100283b); - map.set('braille_dots_3456', 0x100283c); - map.set('braille_dots_13456', 0x100283d); - map.set('braille_dots_23456', 0x100283e); - map.set('braille_dots_123456', 0x100283f); - map.set('braille_dots_7', 0x1002840); - map.set('braille_dots_17', 0x1002841); - map.set('braille_dots_27', 0x1002842); - map.set('braille_dots_127', 0x1002843); - map.set('braille_dots_37', 0x1002844); - map.set('braille_dots_137', 0x1002845); - map.set('braille_dots_237', 0x1002846); - map.set('braille_dots_1237', 0x1002847); - map.set('braille_dots_47', 0x1002848); - map.set('braille_dots_147', 0x1002849); - map.set('braille_dots_247', 0x100284a); - map.set('braille_dots_1247', 0x100284b); - map.set('braille_dots_347', 0x100284c); - map.set('braille_dots_1347', 0x100284d); - map.set('braille_dots_2347', 0x100284e); - map.set('braille_dots_12347', 0x100284f); - map.set('braille_dots_57', 0x1002850); - map.set('braille_dots_157', 0x1002851); - map.set('braille_dots_257', 0x1002852); - map.set('braille_dots_1257', 0x1002853); - map.set('braille_dots_357', 0x1002854); - map.set('braille_dots_1357', 0x1002855); - map.set('braille_dots_2357', 0x1002856); - map.set('braille_dots_12357', 0x1002857); - map.set('braille_dots_457', 0x1002858); - map.set('braille_dots_1457', 0x1002859); - map.set('braille_dots_2457', 0x100285a); - map.set('braille_dots_12457', 0x100285b); - map.set('braille_dots_3457', 0x100285c); - map.set('braille_dots_13457', 0x100285d); - map.set('braille_dots_23457', 0x100285e); - map.set('braille_dots_123457', 0x100285f); - map.set('braille_dots_67', 0x1002860); - map.set('braille_dots_167', 0x1002861); - map.set('braille_dots_267', 0x1002862); - map.set('braille_dots_1267', 0x1002863); - map.set('braille_dots_367', 0x1002864); - map.set('braille_dots_1367', 0x1002865); - map.set('braille_dots_2367', 0x1002866); - map.set('braille_dots_12367', 0x1002867); - map.set('braille_dots_467', 0x1002868); - map.set('braille_dots_1467', 0x1002869); - map.set('braille_dots_2467', 0x100286a); - map.set('braille_dots_12467', 0x100286b); - map.set('braille_dots_3467', 0x100286c); - map.set('braille_dots_13467', 0x100286d); - map.set('braille_dots_23467', 0x100286e); - map.set('braille_dots_123467', 0x100286f); - map.set('braille_dots_567', 0x1002870); - map.set('braille_dots_1567', 0x1002871); - map.set('braille_dots_2567', 0x1002872); - map.set('braille_dots_12567', 0x1002873); - map.set('braille_dots_3567', 0x1002874); - map.set('braille_dots_13567', 0x1002875); - map.set('braille_dots_23567', 0x1002876); - map.set('braille_dots_123567', 0x1002877); - map.set('braille_dots_4567', 0x1002878); - map.set('braille_dots_14567', 0x1002879); - map.set('braille_dots_24567', 0x100287a); - map.set('braille_dots_124567', 0x100287b); - map.set('braille_dots_34567', 0x100287c); - map.set('braille_dots_134567', 0x100287d); - map.set('braille_dots_234567', 0x100287e); - map.set('braille_dots_1234567', 0x100287f); - map.set('braille_dots_8', 0x1002880); - map.set('braille_dots_18', 0x1002881); - map.set('braille_dots_28', 0x1002882); - map.set('braille_dots_128', 0x1002883); - map.set('braille_dots_38', 0x1002884); - map.set('braille_dots_138', 0x1002885); - map.set('braille_dots_238', 0x1002886); - map.set('braille_dots_1238', 0x1002887); - map.set('braille_dots_48', 0x1002888); - map.set('braille_dots_148', 0x1002889); - map.set('braille_dots_248', 0x100288a); - map.set('braille_dots_1248', 0x100288b); - map.set('braille_dots_348', 0x100288c); - map.set('braille_dots_1348', 0x100288d); - map.set('braille_dots_2348', 0x100288e); - map.set('braille_dots_12348', 0x100288f); - map.set('braille_dots_58', 0x1002890); - map.set('braille_dots_158', 0x1002891); - map.set('braille_dots_258', 0x1002892); - map.set('braille_dots_1258', 0x1002893); - map.set('braille_dots_358', 0x1002894); - map.set('braille_dots_1358', 0x1002895); - map.set('braille_dots_2358', 0x1002896); - map.set('braille_dots_12358', 0x1002897); - map.set('braille_dots_458', 0x1002898); - map.set('braille_dots_1458', 0x1002899); - map.set('braille_dots_2458', 0x100289a); - map.set('braille_dots_12458', 0x100289b); - map.set('braille_dots_3458', 0x100289c); - map.set('braille_dots_13458', 0x100289d); - map.set('braille_dots_23458', 0x100289e); - map.set('braille_dots_123458', 0x100289f); - map.set('braille_dots_68', 0x10028a0); - map.set('braille_dots_168', 0x10028a1); - map.set('braille_dots_268', 0x10028a2); - map.set('braille_dots_1268', 0x10028a3); - map.set('braille_dots_368', 0x10028a4); - map.set('braille_dots_1368', 0x10028a5); - map.set('braille_dots_2368', 0x10028a6); - map.set('braille_dots_12368', 0x10028a7); - map.set('braille_dots_468', 0x10028a8); - map.set('braille_dots_1468', 0x10028a9); - map.set('braille_dots_2468', 0x10028aa); - map.set('braille_dots_12468', 0x10028ab); - map.set('braille_dots_3468', 0x10028ac); - map.set('braille_dots_13468', 0x10028ad); - map.set('braille_dots_23468', 0x10028ae); - map.set('braille_dots_123468', 0x10028af); - map.set('braille_dots_568', 0x10028b0); - map.set('braille_dots_1568', 0x10028b1); - map.set('braille_dots_2568', 0x10028b2); - map.set('braille_dots_12568', 0x10028b3); - map.set('braille_dots_3568', 0x10028b4); - map.set('braille_dots_13568', 0x10028b5); - map.set('braille_dots_23568', 0x10028b6); - map.set('braille_dots_123568', 0x10028b7); - map.set('braille_dots_4568', 0x10028b8); - map.set('braille_dots_14568', 0x10028b9); - map.set('braille_dots_24568', 0x10028ba); - map.set('braille_dots_124568', 0x10028bb); - map.set('braille_dots_34568', 0x10028bc); - map.set('braille_dots_134568', 0x10028bd); - map.set('braille_dots_234568', 0x10028be); - map.set('braille_dots_1234568', 0x10028bf); - map.set('braille_dots_78', 0x10028c0); - map.set('braille_dots_178', 0x10028c1); - map.set('braille_dots_278', 0x10028c2); - map.set('braille_dots_1278', 0x10028c3); - map.set('braille_dots_378', 0x10028c4); - map.set('braille_dots_1378', 0x10028c5); - map.set('braille_dots_2378', 0x10028c6); - map.set('braille_dots_12378', 0x10028c7); - map.set('braille_dots_478', 0x10028c8); - map.set('braille_dots_1478', 0x10028c9); - map.set('braille_dots_2478', 0x10028ca); - map.set('braille_dots_12478', 0x10028cb); - map.set('braille_dots_3478', 0x10028cc); - map.set('braille_dots_13478', 0x10028cd); - map.set('braille_dots_23478', 0x10028ce); - map.set('braille_dots_123478', 0x10028cf); - map.set('braille_dots_578', 0x10028d0); - map.set('braille_dots_1578', 0x10028d1); - map.set('braille_dots_2578', 0x10028d2); - map.set('braille_dots_12578', 0x10028d3); - map.set('braille_dots_3578', 0x10028d4); - map.set('braille_dots_13578', 0x10028d5); - map.set('braille_dots_23578', 0x10028d6); - map.set('braille_dots_123578', 0x10028d7); - map.set('braille_dots_4578', 0x10028d8); - map.set('braille_dots_14578', 0x10028d9); - map.set('braille_dots_24578', 0x10028da); - map.set('braille_dots_124578', 0x10028db); - map.set('braille_dots_34578', 0x10028dc); - map.set('braille_dots_134578', 0x10028dd); - map.set('braille_dots_234578', 0x10028de); - map.set('braille_dots_1234578', 0x10028df); - map.set('braille_dots_678', 0x10028e0); - map.set('braille_dots_1678', 0x10028e1); - map.set('braille_dots_2678', 0x10028e2); - map.set('braille_dots_12678', 0x10028e3); - map.set('braille_dots_3678', 0x10028e4); - map.set('braille_dots_13678', 0x10028e5); - map.set('braille_dots_23678', 0x10028e6); - map.set('braille_dots_123678', 0x10028e7); - map.set('braille_dots_4678', 0x10028e8); - map.set('braille_dots_14678', 0x10028e9); - map.set('braille_dots_24678', 0x10028ea); - map.set('braille_dots_124678', 0x10028eb); - map.set('braille_dots_34678', 0x10028ec); - map.set('braille_dots_134678', 0x10028ed); - map.set('braille_dots_234678', 0x10028ee); - map.set('braille_dots_1234678', 0x10028ef); - map.set('braille_dots_5678', 0x10028f0); - map.set('braille_dots_15678', 0x10028f1); - map.set('braille_dots_25678', 0x10028f2); - map.set('braille_dots_125678', 0x10028f3); - map.set('braille_dots_35678', 0x10028f4); - map.set('braille_dots_135678', 0x10028f5); - map.set('braille_dots_235678', 0x10028f6); - map.set('braille_dots_1235678', 0x10028f7); - map.set('braille_dots_45678', 0x10028f8); - map.set('braille_dots_145678', 0x10028f9); - map.set('braille_dots_245678', 0x10028fa); - map.set('braille_dots_1245678', 0x10028fb); - map.set('braille_dots_345678', 0x10028fc); - map.set('braille_dots_1345678', 0x10028fd); - map.set('braille_dots_2345678', 0x10028fe); - map.set('braille_dots_12345678', 0x10028ff); - map.set('Sinh_ng', 0x1000d82); - map.set('Sinh_h2', 0x1000d83); - map.set('Sinh_a', 0x1000d85); - map.set('Sinh_aa', 0x1000d86); - map.set('Sinh_ae', 0x1000d87); - map.set('Sinh_aee', 0x1000d88); - map.set('Sinh_i', 0x1000d89); - map.set('Sinh_ii', 0x1000d8a); - map.set('Sinh_u', 0x1000d8b); - map.set('Sinh_uu', 0x1000d8c); - map.set('Sinh_ri', 0x1000d8d); - map.set('Sinh_rii', 0x1000d8e); - map.set('Sinh_lu', 0x1000d8f); - map.set('Sinh_luu', 0x1000d90); - map.set('Sinh_e', 0x1000d91); - map.set('Sinh_ee', 0x1000d92); - map.set('Sinh_ai', 0x1000d93); - map.set('Sinh_o', 0x1000d94); - map.set('Sinh_oo', 0x1000d95); - map.set('Sinh_au', 0x1000d96); - map.set('Sinh_ka', 0x1000d9a); - map.set('Sinh_kha', 0x1000d9b); - map.set('Sinh_ga', 0x1000d9c); - map.set('Sinh_gha', 0x1000d9d); - map.set('Sinh_ng2', 0x1000d9e); - map.set('Sinh_nga', 0x1000d9f); - map.set('Sinh_ca', 0x1000da0); - map.set('Sinh_cha', 0x1000da1); - map.set('Sinh_ja', 0x1000da2); - map.set('Sinh_jha', 0x1000da3); - map.set('Sinh_nya', 0x1000da4); - map.set('Sinh_jnya', 0x1000da5); - map.set('Sinh_nja', 0x1000da6); - map.set('Sinh_tta', 0x1000da7); - map.set('Sinh_ttha', 0x1000da8); - map.set('Sinh_dda', 0x1000da9); - map.set('Sinh_ddha', 0x1000daa); - map.set('Sinh_nna', 0x1000dab); - map.set('Sinh_ndda', 0x1000dac); - map.set('Sinh_tha', 0x1000dad); - map.set('Sinh_thha', 0x1000dae); - map.set('Sinh_dha', 0x1000daf); - map.set('Sinh_dhha', 0x1000db0); - map.set('Sinh_na', 0x1000db1); - map.set('Sinh_ndha', 0x1000db3); - map.set('Sinh_pa', 0x1000db4); - map.set('Sinh_pha', 0x1000db5); - map.set('Sinh_ba', 0x1000db6); - map.set('Sinh_bha', 0x1000db7); - map.set('Sinh_ma', 0x1000db8); - map.set('Sinh_mba', 0x1000db9); - map.set('Sinh_ya', 0x1000dba); - map.set('Sinh_ra', 0x1000dbb); - map.set('Sinh_la', 0x1000dbd); - map.set('Sinh_va', 0x1000dc0); - map.set('Sinh_sha', 0x1000dc1); - map.set('Sinh_ssha', 0x1000dc2); - map.set('Sinh_sa', 0x1000dc3); - map.set('Sinh_ha', 0x1000dc4); - map.set('Sinh_lla', 0x1000dc5); - map.set('Sinh_fa', 0x1000dc6); - map.set('Sinh_al', 0x1000dca); - map.set('Sinh_aa2', 0x1000dcf); - map.set('Sinh_ae2', 0x1000dd0); - map.set('Sinh_aee2', 0x1000dd1); - map.set('Sinh_i2', 0x1000dd2); - map.set('Sinh_ii2', 0x1000dd3); - map.set('Sinh_u2', 0x1000dd4); - map.set('Sinh_uu2', 0x1000dd6); - map.set('Sinh_ru2', 0x1000dd8); - map.set('Sinh_e2', 0x1000dd9); - map.set('Sinh_ee2', 0x1000dda); - map.set('Sinh_ai2', 0x1000ddb); - map.set('Sinh_o2', 0x1000ddc); - map.set('Sinh_oo2', 0x1000ddd); - map.set('Sinh_au2', 0x1000dde); - map.set('Sinh_lu2', 0x1000ddf); - map.set('Sinh_ruu2', 0x1000df2); - map.set('Sinh_luu2', 0x1000df3); - map.set('Sinh_kunddaliya', 0x1000df4); - map.set('ModeLock', 0x1008ff01); - map.set('MonBrightnessUp', 0x1008ff02); - map.set('MonBrightnessDown', 0x1008ff03); - map.set('KbdLightOnOff', 0x1008ff04); - map.set('KbdBrightnessUp', 0x1008ff05); - map.set('KbdBrightnessDown', 0x1008ff06); - map.set('Standby', 0x1008ff10); - map.set('AudioLowerVolume', 0x1008ff11); - map.set('AudioMute', 0x1008ff12); - map.set('AudioRaiseVolume', 0x1008ff13); - map.set('AudioPlay', 0x1008ff14); - map.set('AudioStop', 0x1008ff15); - map.set('AudioPrev', 0x1008ff16); - map.set('AudioNext', 0x1008ff17); - map.set('HomePage', 0x1008ff18); - map.set('Mail', 0x1008ff19); - map.set('Start', 0x1008ff1a); - map.set('Search', 0x1008ff1b); - map.set('AudioRecord', 0x1008ff1c); - map.set('Calculator', 0x1008ff1d); - map.set('Memo', 0x1008ff1e); - map.set('ToDoList', 0x1008ff1f); - map.set('Calendar', 0x1008ff20); - map.set('PowerDown', 0x1008ff21); - map.set('ContrastAdjust', 0x1008ff22); - map.set('RockerUp', 0x1008ff23); - map.set('RockerDown', 0x1008ff24); - map.set('RockerEnter', 0x1008ff25); - map.set('Back', 0x1008ff26); - map.set('Forward', 0x1008ff27); - map.set('Stop', 0x1008ff28); - map.set('Refresh', 0x1008ff29); - map.set('PowerOff', 0x1008ff2a); - map.set('WakeUp', 0x1008ff2b); - map.set('Eject', 0x1008ff2c); - map.set('ScreenSaver', 0x1008ff2d); - map.set('WWW', 0x1008ff2e); - map.set('Sleep', 0x1008ff2f); - map.set('Favorites', 0x1008ff30); - map.set('AudioPause', 0x1008ff31); - map.set('AudioMedia', 0x1008ff32); - map.set('MyComputer', 0x1008ff33); - map.set('VendorHome', 0x1008ff34); - map.set('LightBulb', 0x1008ff35); - map.set('Shop', 0x1008ff36); - map.set('History', 0x1008ff37); - map.set('OpenURL', 0x1008ff38); - map.set('AddFavorite', 0x1008ff39); - map.set('HotLinks', 0x1008ff3a); - map.set('BrightnessAdjust', 0x1008ff3b); - map.set('Finance', 0x1008ff3c); - map.set('Community', 0x1008ff3d); - map.set('AudioRewind', 0x1008ff3e); - map.set('BackForward', 0x1008ff3f); - map.set('Launch0', 0x1008ff40); - map.set('Launch1', 0x1008ff41); - map.set('Launch2', 0x1008ff42); - map.set('Launch3', 0x1008ff43); - map.set('Launch4', 0x1008ff44); - map.set('Launch5', 0x1008ff45); - map.set('Launch6', 0x1008ff46); - map.set('Launch7', 0x1008ff47); - map.set('Launch8', 0x1008ff48); - map.set('Launch9', 0x1008ff49); - map.set('LaunchA', 0x1008ff4a); - map.set('LaunchB', 0x1008ff4b); - map.set('LaunchC', 0x1008ff4c); - map.set('LaunchD', 0x1008ff4d); - map.set('LaunchE', 0x1008ff4e); - map.set('LaunchF', 0x1008ff4f); - map.set('ApplicationLeft', 0x1008ff50); - map.set('ApplicationRight', 0x1008ff51); - map.set('Book', 0x1008ff52); - map.set('CD', 0x1008ff53); - map.set('WindowClear', 0x1008ff55); - map.set('Close', 0x1008ff56); - map.set('Copy', 0x1008ff57); - map.set('Cut', 0x1008ff58); - map.set('Display', 0x1008ff59); - map.set('DOS', 0x1008ff5a); - map.set('Documents', 0x1008ff5b); - map.set('Excel', 0x1008ff5c); - map.set('Explorer', 0x1008ff5d); - map.set('Game', 0x1008ff5e); - map.set('Go', 0x1008ff5f); - map.set('iTouch', 0x1008ff60); - map.set('LogOff', 0x1008ff61); - map.set('Market', 0x1008ff62); - map.set('Meeting', 0x1008ff63); - map.set('MenuKB', 0x1008ff65); - map.set('MenuPB', 0x1008ff66); - map.set('MySites', 0x1008ff67); - map.set('New', 0x1008ff68); - map.set('News', 0x1008ff69); - map.set('OfficeHome', 0x1008ff6a); - map.set('Open', 0x1008ff6b); - map.set('Option', 0x1008ff6c); - map.set('Paste', 0x1008ff6d); - map.set('Phone', 0x1008ff6e); - map.set('Reply', 0x1008ff72); - map.set('Reload', 0x1008ff73); - map.set('RotateWindows', 0x1008ff74); - map.set('RotationPB', 0x1008ff75); - map.set('RotationKB', 0x1008ff76); - map.set('Save', 0x1008ff77); - map.set('ScrollUp', 0x1008ff78); - map.set('ScrollDown', 0x1008ff79); - map.set('ScrollClick', 0x1008ff7a); - map.set('Send', 0x1008ff7b); - map.set('Spell', 0x1008ff7c); - map.set('SplitScreen', 0x1008ff7d); - map.set('Support', 0x1008ff7e); - map.set('TaskPane', 0x1008ff7f); - map.set('Terminal', 0x1008ff80); - map.set('Tools', 0x1008ff81); - map.set('Travel', 0x1008ff82); - map.set('UserPB', 0x1008ff84); - map.set('User1KB', 0x1008ff85); - map.set('User2KB', 0x1008ff86); - map.set('Video', 0x1008ff87); - map.set('WheelButton', 0x1008ff88); - map.set('Word', 0x1008ff89); - map.set('Xfer', 0x1008ff8a); - map.set('ZoomIn', 0x1008ff8b); - map.set('ZoomOut', 0x1008ff8c); - map.set('Away', 0x1008ff8d); - map.set('Messenger', 0x1008ff8e); - map.set('WebCam', 0x1008ff8f); - map.set('MailForward', 0x1008ff90); - map.set('Pictures', 0x1008ff91); - map.set('Music', 0x1008ff92); - map.set('Battery', 0x1008ff93); - map.set('Bluetooth', 0x1008ff94); - map.set('WLAN', 0x1008ff95); - map.set('UWB', 0x1008ff96); - map.set('AudioForward', 0x1008ff97); - map.set('AudioRepeat', 0x1008ff98); - map.set('AudioRandomPlay', 0x1008ff99); - map.set('Subtitle', 0x1008ff9a); - map.set('AudioCycleTrack', 0x1008ff9b); - map.set('CycleAngle', 0x1008ff9c); - map.set('FrameBack', 0x1008ff9d); - map.set('FrameForward', 0x1008ff9e); - map.set('Time', 0x1008ff9f); - map.set('SelectButton', 0x1008ffa0); - map.set('View', 0x1008ffa1); - map.set('TopMenu', 0x1008ffa2); - map.set('Red', 0x1008ffa3); - map.set('Green', 0x1008ffa4); - map.set('Yellow', 0x1008ffa5); - map.set('Blue', 0x1008ffa6); - map.set('Suspend', 0x1008ffa7); - map.set('Hibernate', 0x1008ffa8); - map.set('TouchpadToggle', 0x1008ffa9); - map.set('TouchpadOn', 0x1008ffb0); - map.set('TouchpadOff', 0x1008ffb1); - map.set('AudioMicMute', 0x1008ffb2); - map.set('Keyboard', 0x1008ffb3); - map.set('WWAN', 0x1008ffb4); - map.set('RFKill', 0x1008ffb5); - map.set('AudioPreset', 0x1008ffb6); - map.set('Switch_VT_1', 0x1008fe01); - map.set('Switch_VT_2', 0x1008fe02); - map.set('Switch_VT_3', 0x1008fe03); - map.set('Switch_VT_4', 0x1008fe04); - map.set('Switch_VT_5', 0x1008fe05); - map.set('Switch_VT_6', 0x1008fe06); - map.set('Switch_VT_7', 0x1008fe07); - map.set('Switch_VT_8', 0x1008fe08); - map.set('Switch_VT_9', 0x1008fe09); - map.set('Switch_VT_10', 0x1008fe0a); - map.set('Switch_VT_11', 0x1008fe0b); - map.set('Switch_VT_12', 0x1008fe0c); - map.set('Ungrab', 0x1008fe20); - map.set('ClearGrab', 0x1008fe21); - map.set('Next_VMode', 0x1008fe22); - map.set('Prev_VMode', 0x1008fe23); - map.set('LogWindowTree', 0x1008fe24); - map.set('LogGrabInfo', 0x1008fe25); - keycodeMap = map; + return result; + } + + /** + * Replicates Gdk full keyset. + * https://gitlab.gnome.org/GNOME/gtk/-/blob/4.13.0/gdk/gdkkeysyms.h?ref_type=tags + */ + _initKeycodeMap(force = false) { + if (!force && this.keycodeMap) { + return; + } + const map = new Map(); + map.set('VoidSymbol', 0xffffff); + map.set('BackSpace', 0xff08); + map.set('Tab', 0xff09); + map.set('Linefeed', 0xff0a); + map.set('Clear', 0xff0b); + map.set('Return', 0xff0d); + map.set('Pause', 0xff13); + map.set('Scroll_Lock', 0xff14); + map.set('Sys_Req', 0xff15); + map.set('Escape', 0xff1b); + map.set('Delete', 0xffff); + map.set('Multi_key', 0xff20); + map.set('Codeinput', 0xff37); + map.set('SingleCandidate', 0xff3c); + map.set('MultipleCandidate', 0xff3d); + map.set('PreviousCandidate', 0xff3e); + map.set('Kanji', 0xff21); + map.set('Muhenkan', 0xff22); + map.set('Henkan_Mode', 0xff23); + map.set('Henkan', 0xff23); + map.set('Romaji', 0xff24); + map.set('Hiragana', 0xff25); + map.set('Katakana', 0xff26); + map.set('Hiragana_Katakana', 0xff27); + map.set('Zenkaku', 0xff28); + map.set('Hankaku', 0xff29); + map.set('Zenkaku_Hankaku', 0xff2a); + map.set('Touroku', 0xff2b); + map.set('Massyo', 0xff2c); + map.set('Kana_Lock', 0xff2d); + map.set('Kana_Shift', 0xff2e); + map.set('Eisu_Shift', 0xff2f); + map.set('Eisu_toggle', 0xff30); + map.set('Kanji_Bangou', 0xff37); + map.set('Zen_Koho', 0xff3d); + map.set('Mae_Koho', 0xff3e); + map.set('Home', 0xff50); + map.set('Left', 0xff51); + map.set('Up', 0xff52); + map.set('Right', 0xff53); + map.set('Down', 0xff54); + map.set('Prior', 0xff55); + map.set('Page_Up', 0xff55); + map.set('Next', 0xff56); + map.set('Page_Down', 0xff56); + map.set('End', 0xff57); + map.set('Begin', 0xff58); + map.set('Select', 0xff60); + map.set('Print', 0xff61); + map.set('Execute', 0xff62); + map.set('Insert', 0xff63); + map.set('Undo', 0xff65); + map.set('Redo', 0xff66); + map.set('Menu', 0xff67); + map.set('Find', 0xff68); + map.set('Cancel', 0xff69); + map.set('Help', 0xff6a); + map.set('Break', 0xff6b); + map.set('Mode_switch', 0xff7e); + map.set('script_switch', 0xff7e); + map.set('Num_Lock', 0xff7f); + map.set('KP_Space', 0xff80); + map.set('KP_Tab', 0xff89); + map.set('KP_Enter', 0xff8d); + map.set('KP_F1', 0xff91); + map.set('KP_F2', 0xff92); + map.set('KP_F3', 0xff93); + map.set('KP_F4', 0xff94); + map.set('KP_Home', 0xff95); + map.set('KP_Left', 0xff96); + map.set('KP_Up', 0xff97); + map.set('KP_Right', 0xff98); + map.set('KP_Down', 0xff99); + map.set('KP_Prior', 0xff9a); + map.set('KP_Page_Up', 0xff9a); + map.set('KP_Next', 0xff9b); + map.set('KP_Page_Down', 0xff9b); + map.set('KP_End', 0xff9c); + map.set('KP_Begin', 0xff9d); + map.set('KP_Insert', 0xff9e); + map.set('KP_Delete', 0xff9f); + map.set('KP_Equal', 0xffbd); + map.set('KP_Multiply', 0xffaa); + map.set('KP_Add', 0xffab); + map.set('KP_Separator', 0xffac); + map.set('KP_Subtract', 0xffad); + map.set('KP_Decimal', 0xffae); + map.set('KP_Divide', 0xffaf); + map.set('KP_0', 0xffb0); + map.set('KP_1', 0xffb1); + map.set('KP_2', 0xffb2); + map.set('KP_3', 0xffb3); + map.set('KP_4', 0xffb4); + map.set('KP_5', 0xffb5); + map.set('KP_6', 0xffb6); + map.set('KP_7', 0xffb7); + map.set('KP_8', 0xffb8); + map.set('KP_9', 0xffb9); + map.set('F1', 0xffbe); + map.set('F2', 0xffbf); + map.set('F3', 0xffc0); + map.set('F4', 0xffc1); + map.set('F5', 0xffc2); + map.set('F6', 0xffc3); + map.set('F7', 0xffc4); + map.set('F8', 0xffc5); + map.set('F9', 0xffc6); + map.set('F10', 0xffc7); + map.set('F11', 0xffc8); + map.set('L1', 0xffc8); + map.set('F12', 0xffc9); + map.set('L2', 0xffc9); + map.set('F13', 0xffca); + map.set('L3', 0xffca); + map.set('F14', 0xffcb); + map.set('L4', 0xffcb); + map.set('F15', 0xffcc); + map.set('L5', 0xffcc); + map.set('F16', 0xffcd); + map.set('L6', 0xffcd); + map.set('F17', 0xffce); + map.set('L7', 0xffce); + map.set('F18', 0xffcf); + map.set('L8', 0xffcf); + map.set('F19', 0xffd0); + map.set('L9', 0xffd0); + map.set('F20', 0xffd1); + map.set('L10', 0xffd1); + map.set('F21', 0xffd2); + map.set('R1', 0xffd2); + map.set('F22', 0xffd3); + map.set('R2', 0xffd3); + map.set('F23', 0xffd4); + map.set('R3', 0xffd4); + map.set('F24', 0xffd5); + map.set('R4', 0xffd5); + map.set('F25', 0xffd6); + map.set('R5', 0xffd6); + map.set('F26', 0xffd7); + map.set('R6', 0xffd7); + map.set('F27', 0xffd8); + map.set('R7', 0xffd8); + map.set('F28', 0xffd9); + map.set('R8', 0xffd9); + map.set('F29', 0xffda); + map.set('R9', 0xffda); + map.set('F30', 0xffdb); + map.set('R10', 0xffdb); + map.set('F31', 0xffdc); + map.set('R11', 0xffdc); + map.set('F32', 0xffdd); + map.set('R12', 0xffdd); + map.set('F33', 0xffde); + map.set('R13', 0xffde); + map.set('F34', 0xffdf); + map.set('R14', 0xffdf); + map.set('F35', 0xffe0); + map.set('R15', 0xffe0); + map.set('Shift_L', 0xffe1); + map.set('Shift_R', 0xffe2); + map.set('Control_L', 0xffe3); + map.set('Control_R', 0xffe4); + map.set('Caps_Lock', 0xffe5); + map.set('Shift_Lock', 0xffe6); + map.set('Meta_L', 0xffe7); + map.set('Meta_R', 0xffe8); + map.set('Alt_L', 0xffe9); + map.set('Alt_R', 0xffea); + map.set('Super_L', 0xffeb); + map.set('Super_R', 0xffec); + map.set('Hyper_L', 0xffed); + map.set('Hyper_R', 0xffee); + map.set('ISO_Lock', 0xfe01); + map.set('ISO_Level2_Latch', 0xfe02); + map.set('ISO_Level3_Shift', 0xfe03); + map.set('ISO_Level3_Latch', 0xfe04); + map.set('ISO_Level3_Lock', 0xfe05); + map.set('ISO_Level5_Shift', 0xfe11); + map.set('ISO_Level5_Latch', 0xfe12); + map.set('ISO_Level5_Lock', 0xfe13); + map.set('ISO_Group_Shift', 0xff7e); + map.set('ISO_Group_Latch', 0xfe06); + map.set('ISO_Group_Lock', 0xfe07); + map.set('ISO_Next_Group', 0xfe08); + map.set('ISO_Next_Group_Lock', 0xfe09); + map.set('ISO_Prev_Group', 0xfe0a); + map.set('ISO_Prev_Group_Lock', 0xfe0b); + map.set('ISO_First_Group', 0xfe0c); + map.set('ISO_First_Group_Lock', 0xfe0d); + map.set('ISO_Last_Group', 0xfe0e); + map.set('ISO_Last_Group_Lock', 0xfe0f); + map.set('ISO_Left_Tab', 0xfe20); + map.set('ISO_Move_Line_Up', 0xfe21); + map.set('ISO_Move_Line_Down', 0xfe22); + map.set('ISO_Partial_Line_Up', 0xfe23); + map.set('ISO_Partial_Line_Down', 0xfe24); + map.set('ISO_Partial_Space_Left', 0xfe25); + map.set('ISO_Partial_Space_Right', 0xfe26); + map.set('ISO_Set_Margin_Left', 0xfe27); + map.set('ISO_Set_Margin_Right', 0xfe28); + map.set('ISO_Release_Margin_Left', 0xfe29); + map.set('ISO_Release_Margin_Right', 0xfe2a); + map.set('ISO_Release_Both_Margins', 0xfe2b); + map.set('ISO_Fast_Cursor_Left', 0xfe2c); + map.set('ISO_Fast_Cursor_Right', 0xfe2d); + map.set('ISO_Fast_Cursor_Up', 0xfe2e); + map.set('ISO_Fast_Cursor_Down', 0xfe2f); + map.set('ISO_Continuous_Underline', 0xfe30); + map.set('ISO_Discontinuous_Underline', 0xfe31); + map.set('ISO_Emphasize', 0xfe32); + map.set('ISO_Center_Object', 0xfe33); + map.set('ISO_Enter', 0xfe34); + map.set('dead_grave', 0xfe50); + map.set('dead_acute', 0xfe51); + map.set('dead_circumflex', 0xfe52); + map.set('dead_tilde', 0xfe53); + map.set('dead_perispomeni', 0xfe53); + map.set('dead_macron', 0xfe54); + map.set('dead_breve', 0xfe55); + map.set('dead_abovedot', 0xfe56); + map.set('dead_diaeresis', 0xfe57); + map.set('dead_abovering', 0xfe58); + map.set('dead_doubleacute', 0xfe59); + map.set('dead_caron', 0xfe5a); + map.set('dead_cedilla', 0xfe5b); + map.set('dead_ogonek', 0xfe5c); + map.set('dead_iota', 0xfe5d); + map.set('dead_voiced_sound', 0xfe5e); + map.set('dead_semivoiced_sound', 0xfe5f); + map.set('dead_belowdot', 0xfe60); + map.set('dead_hook', 0xfe61); + map.set('dead_horn', 0xfe62); + map.set('dead_stroke', 0xfe63); + map.set('dead_abovecomma', 0xfe64); + map.set('dead_psili', 0xfe64); + map.set('dead_abovereversedcomma', 0xfe65); + map.set('dead_dasia', 0xfe65); + map.set('dead_doublegrave', 0xfe66); + map.set('dead_belowring', 0xfe67); + map.set('dead_belowmacron', 0xfe68); + map.set('dead_belowcircumflex', 0xfe69); + map.set('dead_belowtilde', 0xfe6a); + map.set('dead_belowbreve', 0xfe6b); + map.set('dead_belowdiaeresis', 0xfe6c); + map.set('dead_invertedbreve', 0xfe6d); + map.set('dead_belowcomma', 0xfe6e); + map.set('dead_currency', 0xfe6f); + map.set('dead_lowline', 0xfe90); + map.set('dead_aboveverticalline', 0xfe91); + map.set('dead_belowverticalline', 0xfe92); + map.set('dead_longsolidusoverlay', 0xfe93); + map.set('dead_a', 0xfe80); + map.set('dead_A', 0xfe81); + map.set('dead_e', 0xfe82); + map.set('dead_E', 0xfe83); + map.set('dead_i', 0xfe84); + map.set('dead_I', 0xfe85); + map.set('dead_o', 0xfe86); + map.set('dead_O', 0xfe87); + map.set('dead_u', 0xfe88); + map.set('dead_U', 0xfe89); + map.set('dead_small_schwa', 0xfe8a); + map.set('dead_capital_schwa', 0xfe8b); + map.set('dead_greek', 0xfe8c); + map.set('First_Virtual_Screen', 0xfed0); + map.set('Prev_Virtual_Screen', 0xfed1); + map.set('Next_Virtual_Screen', 0xfed2); + map.set('Last_Virtual_Screen', 0xfed4); + map.set('Terminate_Server', 0xfed5); + map.set('AccessX_Enable', 0xfe70); + map.set('AccessX_Feedback_Enable', 0xfe71); + map.set('RepeatKeys_Enable', 0xfe72); + map.set('SlowKeys_Enable', 0xfe73); + map.set('BounceKeys_Enable', 0xfe74); + map.set('StickyKeys_Enable', 0xfe75); + map.set('MouseKeys_Enable', 0xfe76); + map.set('MouseKeys_Accel_Enable', 0xfe77); + map.set('Overlay1_Enable', 0xfe78); + map.set('Overlay2_Enable', 0xfe79); + map.set('AudibleBell_Enable', 0xfe7a); + map.set('Pointer_Left', 0xfee0); + map.set('Pointer_Right', 0xfee1); + map.set('Pointer_Up', 0xfee2); + map.set('Pointer_Down', 0xfee3); + map.set('Pointer_UpLeft', 0xfee4); + map.set('Pointer_UpRight', 0xfee5); + map.set('Pointer_DownLeft', 0xfee6); + map.set('Pointer_DownRight', 0xfee7); + map.set('Pointer_Button_Dflt', 0xfee8); + map.set('Pointer_Button1', 0xfee9); + map.set('Pointer_Button2', 0xfeea); + map.set('Pointer_Button3', 0xfeeb); + map.set('Pointer_Button4', 0xfeec); + map.set('Pointer_Button5', 0xfeed); + map.set('Pointer_DblClick_Dflt', 0xfeee); + map.set('Pointer_DblClick1', 0xfeef); + map.set('Pointer_DblClick2', 0xfef0); + map.set('Pointer_DblClick3', 0xfef1); + map.set('Pointer_DblClick4', 0xfef2); + map.set('Pointer_DblClick5', 0xfef3); + map.set('Pointer_Drag_Dflt', 0xfef4); + map.set('Pointer_Drag1', 0xfef5); + map.set('Pointer_Drag2', 0xfef6); + map.set('Pointer_Drag3', 0xfef7); + map.set('Pointer_Drag4', 0xfef8); + map.set('Pointer_Drag5', 0xfefd); + map.set('Pointer_EnableKeys', 0xfef9); + map.set('Pointer_Accelerate', 0xfefa); + map.set('Pointer_DfltBtnNext', 0xfefb); + map.set('Pointer_DfltBtnPrev', 0xfefc); + map.set('ch', 0xfea0); + map.set('Ch', 0xfea1); + map.set('CH', 0xfea2); + map.set('c_h', 0xfea3); + map.set('C_h', 0xfea4); + map.set('C_H', 0xfea5); + map.set('3270_Duplicate', 0xfd01); + map.set('3270_FieldMark', 0xfd02); + map.set('3270_Right2', 0xfd03); + map.set('3270_Left2', 0xfd04); + map.set('3270_BackTab', 0xfd05); + map.set('3270_EraseEOF', 0xfd06); + map.set('3270_EraseInput', 0xfd07); + map.set('3270_Reset', 0xfd08); + map.set('3270_Quit', 0xfd09); + map.set('3270_PA1', 0xfd0a); + map.set('3270_PA2', 0xfd0b); + map.set('3270_PA3', 0xfd0c); + map.set('3270_Test', 0xfd0d); + map.set('3270_Attn', 0xfd0e); + map.set('3270_CursorBlink', 0xfd0f); + map.set('3270_AltCursor', 0xfd10); + map.set('3270_KeyClick', 0xfd11); + map.set('3270_Jump', 0xfd12); + map.set('3270_Ident', 0xfd13); + map.set('3270_Rule', 0xfd14); + map.set('3270_Copy', 0xfd15); + map.set('3270_Play', 0xfd16); + map.set('3270_Setup', 0xfd17); + map.set('3270_Record', 0xfd18); + map.set('3270_ChangeScreen', 0xfd19); + map.set('3270_DeleteWord', 0xfd1a); + map.set('3270_ExSelect', 0xfd1b); + map.set('3270_CursorSelect', 0xfd1c); + map.set('3270_PrintScreen', 0xfd1d); + map.set('3270_Enter', 0xfd1e); + map.set('space', 0x020); + map.set('exclam', 0x021); + map.set('quotedbl', 0x022); + map.set('numbersign', 0x023); + map.set('dollar', 0x024); + map.set('percent', 0x025); + map.set('ampersand', 0x026); + map.set('apostrophe', 0x027); + map.set('quoteright', 0x027); + map.set('parenleft', 0x028); + map.set('parenright', 0x029); + map.set('asterisk', 0x02a); + map.set('plus', 0x02b); + map.set('comma', 0x02c); + map.set('minus', 0x02d); + map.set('period', 0x02e); + map.set('slash', 0x02f); + map.set('0', 0x030); + map.set('1', 0x031); + map.set('2', 0x032); + map.set('3', 0x033); + map.set('4', 0x034); + map.set('5', 0x035); + map.set('6', 0x036); + map.set('7', 0x037); + map.set('8', 0x038); + map.set('9', 0x039); + map.set('colon', 0x03a); + map.set('semicolon', 0x03b); + map.set('less', 0x03c); + map.set('equal', 0x03d); + map.set('greater', 0x03e); + map.set('question', 0x03f); + map.set('at', 0x040); + map.set('A', 0x041); + map.set('B', 0x042); + map.set('C', 0x043); + map.set('D', 0x044); + map.set('E', 0x045); + map.set('F', 0x046); + map.set('G', 0x047); + map.set('H', 0x048); + map.set('I', 0x049); + map.set('J', 0x04a); + map.set('K', 0x04b); + map.set('L', 0x04c); + map.set('M', 0x04d); + map.set('N', 0x04e); + map.set('O', 0x04f); + map.set('P', 0x050); + map.set('Q', 0x051); + map.set('R', 0x052); + map.set('S', 0x053); + map.set('T', 0x054); + map.set('U', 0x055); + map.set('V', 0x056); + map.set('W', 0x057); + map.set('X', 0x058); + map.set('Y', 0x059); + map.set('Z', 0x05a); + map.set('bracketleft', 0x05b); + map.set('backslash', 0x05c); + map.set('bracketright', 0x05d); + map.set('asciicircum', 0x05e); + map.set('underscore', 0x05f); + map.set('grave', 0x060); + map.set('quoteleft', 0x060); + map.set('a', 0x061); + map.set('b', 0x062); + map.set('c', 0x063); + map.set('d', 0x064); + map.set('e', 0x065); + map.set('f', 0x066); + map.set('g', 0x067); + map.set('h', 0x068); + map.set('i', 0x069); + map.set('j', 0x06a); + map.set('k', 0x06b); + map.set('l', 0x06c); + map.set('m', 0x06d); + map.set('n', 0x06e); + map.set('o', 0x06f); + map.set('p', 0x070); + map.set('q', 0x071); + map.set('r', 0x072); + map.set('s', 0x073); + map.set('t', 0x074); + map.set('u', 0x075); + map.set('v', 0x076); + map.set('w', 0x077); + map.set('x', 0x078); + map.set('y', 0x079); + map.set('z', 0x07a); + map.set('braceleft', 0x07b); + map.set('bar', 0x07c); + map.set('braceright', 0x07d); + map.set('asciitilde', 0x07e); + map.set('nobreakspace', 0x0a0); + map.set('exclamdown', 0x0a1); + map.set('cent', 0x0a2); + map.set('sterling', 0x0a3); + map.set('currency', 0x0a4); + map.set('yen', 0x0a5); + map.set('brokenbar', 0x0a6); + map.set('section', 0x0a7); + map.set('diaeresis', 0x0a8); + map.set('copyright', 0x0a9); + map.set('ordfeminine', 0x0aa); + map.set('guillemotleft', 0x0ab); + map.set('notsign', 0x0ac); + map.set('hyphen', 0x0ad); + map.set('registered', 0x0ae); + map.set('macron', 0x0af); + map.set('degree', 0x0b0); + map.set('plusminus', 0x0b1); + map.set('twosuperior', 0x0b2); + map.set('threesuperior', 0x0b3); + map.set('acute', 0x0b4); + map.set('mu', 0x0b5); + map.set('paragraph', 0x0b6); + map.set('periodcentered', 0x0b7); + map.set('cedilla', 0x0b8); + map.set('onesuperior', 0x0b9); + map.set('masculine', 0x0ba); + map.set('guillemotright', 0x0bb); + map.set('onequarter', 0x0bc); + map.set('onehalf', 0x0bd); + map.set('threequarters', 0x0be); + map.set('questiondown', 0x0bf); + map.set('Agrave', 0x0c0); + map.set('Aacute', 0x0c1); + map.set('Acircumflex', 0x0c2); + map.set('Atilde', 0x0c3); + map.set('Adiaeresis', 0x0c4); + map.set('Aring', 0x0c5); + map.set('AE', 0x0c6); + map.set('Ccedilla', 0x0c7); + map.set('Egrave', 0x0c8); + map.set('Eacute', 0x0c9); + map.set('Ecircumflex', 0x0ca); + map.set('Ediaeresis', 0x0cb); + map.set('Igrave', 0x0cc); + map.set('Iacute', 0x0cd); + map.set('Icircumflex', 0x0ce); + map.set('Idiaeresis', 0x0cf); + map.set('ETH', 0x0d0); + map.set('Eth', 0x0d0); + map.set('Ntilde', 0x0d1); + map.set('Ograve', 0x0d2); + map.set('Oacute', 0x0d3); + map.set('Ocircumflex', 0x0d4); + map.set('Otilde', 0x0d5); + map.set('Odiaeresis', 0x0d6); + map.set('multiply', 0x0d7); + map.set('Oslash', 0x0d8); + map.set('Ooblique', 0x0d8); + map.set('Ugrave', 0x0d9); + map.set('Uacute', 0x0da); + map.set('Ucircumflex', 0x0db); + map.set('Udiaeresis', 0x0dc); + map.set('Yacute', 0x0dd); + map.set('THORN', 0x0de); + map.set('Thorn', 0x0de); + map.set('ssharp', 0x0df); + map.set('agrave', 0x0e0); + map.set('aacute', 0x0e1); + map.set('acircumflex', 0x0e2); + map.set('atilde', 0x0e3); + map.set('adiaeresis', 0x0e4); + map.set('aring', 0x0e5); + map.set('ae', 0x0e6); + map.set('ccedilla', 0x0e7); + map.set('egrave', 0x0e8); + map.set('eacute', 0x0e9); + map.set('ecircumflex', 0x0ea); + map.set('ediaeresis', 0x0eb); + map.set('igrave', 0x0ec); + map.set('iacute', 0x0ed); + map.set('icircumflex', 0x0ee); + map.set('idiaeresis', 0x0ef); + map.set('eth', 0x0f0); + map.set('ntilde', 0x0f1); + map.set('ograve', 0x0f2); + map.set('oacute', 0x0f3); + map.set('ocircumflex', 0x0f4); + map.set('otilde', 0x0f5); + map.set('odiaeresis', 0x0f6); + map.set('division', 0x0f7); + map.set('oslash', 0x0f8); + map.set('ooblique', 0x0f8); + map.set('ugrave', 0x0f9); + map.set('uacute', 0x0fa); + map.set('ucircumflex', 0x0fb); + map.set('udiaeresis', 0x0fc); + map.set('yacute', 0x0fd); + map.set('thorn', 0x0fe); + map.set('ydiaeresis', 0x0ff); + map.set('Aogonek', 0x1a1); + map.set('breve', 0x1a2); + map.set('Lstroke', 0x1a3); + map.set('Lcaron', 0x1a5); + map.set('Sacute', 0x1a6); + map.set('Scaron', 0x1a9); + map.set('Scedilla', 0x1aa); + map.set('Tcaron', 0x1ab); + map.set('Zacute', 0x1ac); + map.set('Zcaron', 0x1ae); + map.set('Zabovedot', 0x1af); + map.set('aogonek', 0x1b1); + map.set('ogonek', 0x1b2); + map.set('lstroke', 0x1b3); + map.set('lcaron', 0x1b5); + map.set('sacute', 0x1b6); + map.set('caron', 0x1b7); + map.set('scaron', 0x1b9); + map.set('scedilla', 0x1ba); + map.set('tcaron', 0x1bb); + map.set('zacute', 0x1bc); + map.set('doubleacute', 0x1bd); + map.set('zcaron', 0x1be); + map.set('zabovedot', 0x1bf); + map.set('Racute', 0x1c0); + map.set('Abreve', 0x1c3); + map.set('Lacute', 0x1c5); + map.set('Cacute', 0x1c6); + map.set('Ccaron', 0x1c8); + map.set('Eogonek', 0x1ca); + map.set('Ecaron', 0x1cc); + map.set('Dcaron', 0x1cf); + map.set('Dstroke', 0x1d0); + map.set('Nacute', 0x1d1); + map.set('Ncaron', 0x1d2); + map.set('Odoubleacute', 0x1d5); + map.set('Rcaron', 0x1d8); + map.set('Uring', 0x1d9); + map.set('Udoubleacute', 0x1db); + map.set('Tcedilla', 0x1de); + map.set('racute', 0x1e0); + map.set('abreve', 0x1e3); + map.set('lacute', 0x1e5); + map.set('cacute', 0x1e6); + map.set('ccaron', 0x1e8); + map.set('eogonek', 0x1ea); + map.set('ecaron', 0x1ec); + map.set('dcaron', 0x1ef); + map.set('dstroke', 0x1f0); + map.set('nacute', 0x1f1); + map.set('ncaron', 0x1f2); + map.set('odoubleacute', 0x1f5); + map.set('rcaron', 0x1f8); + map.set('uring', 0x1f9); + map.set('udoubleacute', 0x1fb); + map.set('tcedilla', 0x1fe); + map.set('abovedot', 0x1ff); + map.set('Hstroke', 0x2a1); + map.set('Hcircumflex', 0x2a6); + map.set('Iabovedot', 0x2a9); + map.set('Gbreve', 0x2ab); + map.set('Jcircumflex', 0x2ac); + map.set('hstroke', 0x2b1); + map.set('hcircumflex', 0x2b6); + map.set('idotless', 0x2b9); + map.set('gbreve', 0x2bb); + map.set('jcircumflex', 0x2bc); + map.set('Cabovedot', 0x2c5); + map.set('Ccircumflex', 0x2c6); + map.set('Gabovedot', 0x2d5); + map.set('Gcircumflex', 0x2d8); + map.set('Ubreve', 0x2dd); + map.set('Scircumflex', 0x2de); + map.set('cabovedot', 0x2e5); + map.set('ccircumflex', 0x2e6); + map.set('gabovedot', 0x2f5); + map.set('gcircumflex', 0x2f8); + map.set('ubreve', 0x2fd); + map.set('scircumflex', 0x2fe); + map.set('kra', 0x3a2); + map.set('kappa', 0x3a2); + map.set('Rcedilla', 0x3a3); + map.set('Itilde', 0x3a5); + map.set('Lcedilla', 0x3a6); + map.set('Emacron', 0x3aa); + map.set('Gcedilla', 0x3ab); + map.set('Tslash', 0x3ac); + map.set('rcedilla', 0x3b3); + map.set('itilde', 0x3b5); + map.set('lcedilla', 0x3b6); + map.set('emacron', 0x3ba); + map.set('gcedilla', 0x3bb); + map.set('tslash', 0x3bc); + map.set('ENG', 0x3bd); + map.set('eng', 0x3bf); + map.set('Amacron', 0x3c0); + map.set('Iogonek', 0x3c7); + map.set('Eabovedot', 0x3cc); + map.set('Imacron', 0x3cf); + map.set('Ncedilla', 0x3d1); + map.set('Omacron', 0x3d2); + map.set('Kcedilla', 0x3d3); + map.set('Uogonek', 0x3d9); + map.set('Utilde', 0x3dd); + map.set('Umacron', 0x3de); + map.set('amacron', 0x3e0); + map.set('iogonek', 0x3e7); + map.set('eabovedot', 0x3ec); + map.set('imacron', 0x3ef); + map.set('ncedilla', 0x3f1); + map.set('omacron', 0x3f2); + map.set('kcedilla', 0x3f3); + map.set('uogonek', 0x3f9); + map.set('utilde', 0x3fd); + map.set('umacron', 0x3fe); + map.set('Wcircumflex', 0x1000174); + map.set('wcircumflex', 0x1000175); + map.set('Ycircumflex', 0x1000176); + map.set('ycircumflex', 0x1000177); + map.set('Babovedot', 0x1001e02); + map.set('babovedot', 0x1001e03); + map.set('Dabovedot', 0x1001e0a); + map.set('dabovedot', 0x1001e0b); + map.set('Fabovedot', 0x1001e1e); + map.set('fabovedot', 0x1001e1f); + map.set('Mabovedot', 0x1001e40); + map.set('mabovedot', 0x1001e41); + map.set('Pabovedot', 0x1001e56); + map.set('pabovedot', 0x1001e57); + map.set('Sabovedot', 0x1001e60); + map.set('sabovedot', 0x1001e61); + map.set('Tabovedot', 0x1001e6a); + map.set('tabovedot', 0x1001e6b); + map.set('Wgrave', 0x1001e80); + map.set('wgrave', 0x1001e81); + map.set('Wacute', 0x1001e82); + map.set('wacute', 0x1001e83); + map.set('Wdiaeresis', 0x1001e84); + map.set('wdiaeresis', 0x1001e85); + map.set('Ygrave', 0x1001ef2); + map.set('ygrave', 0x1001ef3); + map.set('OE', 0x13bc); + map.set('oe', 0x13bd); + map.set('Ydiaeresis', 0x13be); + map.set('overline', 0x47e); + map.set('kana_fullstop', 0x4a1); + map.set('kana_openingbracket', 0x4a2); + map.set('kana_closingbracket', 0x4a3); + map.set('kana_comma', 0x4a4); + map.set('kana_conjunctive', 0x4a5); + map.set('kana_middledot', 0x4a5); + map.set('kana_WO', 0x4a6); + map.set('kana_a', 0x4a7); + map.set('kana_i', 0x4a8); + map.set('kana_u', 0x4a9); + map.set('kana_e', 0x4aa); + map.set('kana_o', 0x4ab); + map.set('kana_ya', 0x4ac); + map.set('kana_yu', 0x4ad); + map.set('kana_yo', 0x4ae); + map.set('kana_tsu', 0x4af); + map.set('kana_tu', 0x4af); + map.set('prolongedsound', 0x4b0); + map.set('kana_A', 0x4b1); + map.set('kana_I', 0x4b2); + map.set('kana_U', 0x4b3); + map.set('kana_E', 0x4b4); + map.set('kana_O', 0x4b5); + map.set('kana_KA', 0x4b6); + map.set('kana_KI', 0x4b7); + map.set('kana_KU', 0x4b8); + map.set('kana_KE', 0x4b9); + map.set('kana_KO', 0x4ba); + map.set('kana_SA', 0x4bb); + map.set('kana_SHI', 0x4bc); + map.set('kana_SU', 0x4bd); + map.set('kana_SE', 0x4be); + map.set('kana_SO', 0x4bf); + map.set('kana_TA', 0x4c0); + map.set('kana_CHI', 0x4c1); + map.set('kana_TI', 0x4c1); + map.set('kana_TSU', 0x4c2); + map.set('kana_TU', 0x4c2); + map.set('kana_TE', 0x4c3); + map.set('kana_TO', 0x4c4); + map.set('kana_NA', 0x4c5); + map.set('kana_NI', 0x4c6); + map.set('kana_NU', 0x4c7); + map.set('kana_NE', 0x4c8); + map.set('kana_NO', 0x4c9); + map.set('kana_HA', 0x4ca); + map.set('kana_HI', 0x4cb); + map.set('kana_FU', 0x4cc); + map.set('kana_HU', 0x4cc); + map.set('kana_HE', 0x4cd); + map.set('kana_HO', 0x4ce); + map.set('kana_MA', 0x4cf); + map.set('kana_MI', 0x4d0); + map.set('kana_MU', 0x4d1); + map.set('kana_ME', 0x4d2); + map.set('kana_MO', 0x4d3); + map.set('kana_YA', 0x4d4); + map.set('kana_YU', 0x4d5); + map.set('kana_YO', 0x4d6); + map.set('kana_RA', 0x4d7); + map.set('kana_RI', 0x4d8); + map.set('kana_RU', 0x4d9); + map.set('kana_RE', 0x4da); + map.set('kana_RO', 0x4db); + map.set('kana_WA', 0x4dc); + map.set('kana_N', 0x4dd); + map.set('voicedsound', 0x4de); + map.set('semivoicedsound', 0x4df); + map.set('kana_switch', 0xff7e); + map.set('Farsi_0', 0x10006f0); + map.set('Farsi_1', 0x10006f1); + map.set('Farsi_2', 0x10006f2); + map.set('Farsi_3', 0x10006f3); + map.set('Farsi_4', 0x10006f4); + map.set('Farsi_5', 0x10006f5); + map.set('Farsi_6', 0x10006f6); + map.set('Farsi_7', 0x10006f7); + map.set('Farsi_8', 0x10006f8); + map.set('Farsi_9', 0x10006f9); + map.set('Arabic_percent', 0x100066a); + map.set('Arabic_superscript_alef', 0x1000670); + map.set('Arabic_tteh', 0x1000679); + map.set('Arabic_peh', 0x100067e); + map.set('Arabic_tcheh', 0x1000686); + map.set('Arabic_ddal', 0x1000688); + map.set('Arabic_rreh', 0x1000691); + map.set('Arabic_comma', 0x5ac); + map.set('Arabic_fullstop', 0x10006d4); + map.set('Arabic_0', 0x1000660); + map.set('Arabic_1', 0x1000661); + map.set('Arabic_2', 0x1000662); + map.set('Arabic_3', 0x1000663); + map.set('Arabic_4', 0x1000664); + map.set('Arabic_5', 0x1000665); + map.set('Arabic_6', 0x1000666); + map.set('Arabic_7', 0x1000667); + map.set('Arabic_8', 0x1000668); + map.set('Arabic_9', 0x1000669); + map.set('Arabic_semicolon', 0x5bb); + map.set('Arabic_question_mark', 0x5bf); + map.set('Arabic_hamza', 0x5c1); + map.set('Arabic_maddaonalef', 0x5c2); + map.set('Arabic_hamzaonalef', 0x5c3); + map.set('Arabic_hamzaonwaw', 0x5c4); + map.set('Arabic_hamzaunderalef', 0x5c5); + map.set('Arabic_hamzaonyeh', 0x5c6); + map.set('Arabic_alef', 0x5c7); + map.set('Arabic_beh', 0x5c8); + map.set('Arabic_tehmarbuta', 0x5c9); + map.set('Arabic_teh', 0x5ca); + map.set('Arabic_theh', 0x5cb); + map.set('Arabic_jeem', 0x5cc); + map.set('Arabic_hah', 0x5cd); + map.set('Arabic_khah', 0x5ce); + map.set('Arabic_dal', 0x5cf); + map.set('Arabic_thal', 0x5d0); + map.set('Arabic_ra', 0x5d1); + map.set('Arabic_zain', 0x5d2); + map.set('Arabic_seen', 0x5d3); + map.set('Arabic_sheen', 0x5d4); + map.set('Arabic_sad', 0x5d5); + map.set('Arabic_dad', 0x5d6); + map.set('Arabic_tah', 0x5d7); + map.set('Arabic_zah', 0x5d8); + map.set('Arabic_ain', 0x5d9); + map.set('Arabic_ghain', 0x5da); + map.set('Arabic_tatweel', 0x5e0); + map.set('Arabic_feh', 0x5e1); + map.set('Arabic_qaf', 0x5e2); + map.set('Arabic_kaf', 0x5e3); + map.set('Arabic_lam', 0x5e4); + map.set('Arabic_meem', 0x5e5); + map.set('Arabic_noon', 0x5e6); + map.set('Arabic_ha', 0x5e7); + map.set('Arabic_heh', 0x5e7); + map.set('Arabic_waw', 0x5e8); + map.set('Arabic_alefmaksura', 0x5e9); + map.set('Arabic_yeh', 0x5ea); + map.set('Arabic_fathatan', 0x5eb); + map.set('Arabic_dammatan', 0x5ec); + map.set('Arabic_kasratan', 0x5ed); + map.set('Arabic_fatha', 0x5ee); + map.set('Arabic_damma', 0x5ef); + map.set('Arabic_kasra', 0x5f0); + map.set('Arabic_shadda', 0x5f1); + map.set('Arabic_sukun', 0x5f2); + map.set('Arabic_madda_above', 0x1000653); + map.set('Arabic_hamza_above', 0x1000654); + map.set('Arabic_hamza_below', 0x1000655); + map.set('Arabic_jeh', 0x1000698); + map.set('Arabic_veh', 0x10006a4); + map.set('Arabic_keheh', 0x10006a9); + map.set('Arabic_gaf', 0x10006af); + map.set('Arabic_noon_ghunna', 0x10006ba); + map.set('Arabic_heh_doachashmee', 0x10006be); + map.set('Farsi_yeh', 0x10006cc); + map.set('Arabic_farsi_yeh', 0x10006cc); + map.set('Arabic_yeh_baree', 0x10006d2); + map.set('Arabic_heh_goal', 0x10006c1); + map.set('Arabic_switch', 0xff7e); + map.set('Cyrillic_GHE_bar', 0x1000492); + map.set('Cyrillic_ghe_bar', 0x1000493); + map.set('Cyrillic_ZHE_descender', 0x1000496); + map.set('Cyrillic_zhe_descender', 0x1000497); + map.set('Cyrillic_KA_descender', 0x100049a); + map.set('Cyrillic_ka_descender', 0x100049b); + map.set('Cyrillic_KA_vertstroke', 0x100049c); + map.set('Cyrillic_ka_vertstroke', 0x100049d); + map.set('Cyrillic_EN_descender', 0x10004a2); + map.set('Cyrillic_en_descender', 0x10004a3); + map.set('Cyrillic_U_straight', 0x10004ae); + map.set('Cyrillic_u_straight', 0x10004af); + map.set('Cyrillic_U_straight_bar', 0x10004b0); + map.set('Cyrillic_u_straight_bar', 0x10004b1); + map.set('Cyrillic_HA_descender', 0x10004b2); + map.set('Cyrillic_ha_descender', 0x10004b3); + map.set('Cyrillic_CHE_descender', 0x10004b6); + map.set('Cyrillic_che_descender', 0x10004b7); + map.set('Cyrillic_CHE_vertstroke', 0x10004b8); + map.set('Cyrillic_che_vertstroke', 0x10004b9); + map.set('Cyrillic_SHHA', 0x10004ba); + map.set('Cyrillic_shha', 0x10004bb); + map.set('Cyrillic_SCHWA', 0x10004d8); + map.set('Cyrillic_schwa', 0x10004d9); + map.set('Cyrillic_I_macron', 0x10004e2); + map.set('Cyrillic_i_macron', 0x10004e3); + map.set('Cyrillic_O_bar', 0x10004e8); + map.set('Cyrillic_o_bar', 0x10004e9); + map.set('Cyrillic_U_macron', 0x10004ee); + map.set('Cyrillic_u_macron', 0x10004ef); + map.set('Serbian_dje', 0x6a1); + map.set('Macedonia_gje', 0x6a2); + map.set('Cyrillic_io', 0x6a3); + map.set('Ukrainian_ie', 0x6a4); + map.set('Ukranian_je', 0x6a4); + map.set('Macedonia_dse', 0x6a5); + map.set('Ukrainian_i', 0x6a6); + map.set('Ukranian_i', 0x6a6); + map.set('Ukrainian_yi', 0x6a7); + map.set('Ukranian_yi', 0x6a7); + map.set('Cyrillic_je', 0x6a8); + map.set('Serbian_je', 0x6a8); + map.set('Cyrillic_lje', 0x6a9); + map.set('Serbian_lje', 0x6a9); + map.set('Cyrillic_nje', 0x6aa); + map.set('Serbian_nje', 0x6aa); + map.set('Serbian_tshe', 0x6ab); + map.set('Macedonia_kje', 0x6ac); + map.set('Ukrainian_ghe_with_upturn', 0x6ad); + map.set('Byelorussian_shortu', 0x6ae); + map.set('Cyrillic_dzhe', 0x6af); + map.set('Serbian_dze', 0x6af); + map.set('numerosign', 0x6b0); + map.set('Serbian_DJE', 0x6b1); + map.set('Macedonia_GJE', 0x6b2); + map.set('Cyrillic_IO', 0x6b3); + map.set('Ukrainian_IE', 0x6b4); + map.set('Ukranian_JE', 0x6b4); + map.set('Macedonia_DSE', 0x6b5); + map.set('Ukrainian_I', 0x6b6); + map.set('Ukranian_I', 0x6b6); + map.set('Ukrainian_YI', 0x6b7); + map.set('Ukranian_YI', 0x6b7); + map.set('Cyrillic_JE', 0x6b8); + map.set('Serbian_JE', 0x6b8); + map.set('Cyrillic_LJE', 0x6b9); + map.set('Serbian_LJE', 0x6b9); + map.set('Cyrillic_NJE', 0x6ba); + map.set('Serbian_NJE', 0x6ba); + map.set('Serbian_TSHE', 0x6bb); + map.set('Macedonia_KJE', 0x6bc); + map.set('Ukrainian_GHE_WITH_UPTURN', 0x6bd); + map.set('Byelorussian_SHORTU', 0x6be); + map.set('Cyrillic_DZHE', 0x6bf); + map.set('Serbian_DZE', 0x6bf); + map.set('Cyrillic_yu', 0x6c0); + map.set('Cyrillic_a', 0x6c1); + map.set('Cyrillic_be', 0x6c2); + map.set('Cyrillic_tse', 0x6c3); + map.set('Cyrillic_de', 0x6c4); + map.set('Cyrillic_ie', 0x6c5); + map.set('Cyrillic_ef', 0x6c6); + map.set('Cyrillic_ghe', 0x6c7); + map.set('Cyrillic_ha', 0x6c8); + map.set('Cyrillic_i', 0x6c9); + map.set('Cyrillic_shorti', 0x6ca); + map.set('Cyrillic_ka', 0x6cb); + map.set('Cyrillic_el', 0x6cc); + map.set('Cyrillic_em', 0x6cd); + map.set('Cyrillic_en', 0x6ce); + map.set('Cyrillic_o', 0x6cf); + map.set('Cyrillic_pe', 0x6d0); + map.set('Cyrillic_ya', 0x6d1); + map.set('Cyrillic_er', 0x6d2); + map.set('Cyrillic_es', 0x6d3); + map.set('Cyrillic_te', 0x6d4); + map.set('Cyrillic_u', 0x6d5); + map.set('Cyrillic_zhe', 0x6d6); + map.set('Cyrillic_ve', 0x6d7); + map.set('Cyrillic_softsign', 0x6d8); + map.set('Cyrillic_yeru', 0x6d9); + map.set('Cyrillic_ze', 0x6da); + map.set('Cyrillic_sha', 0x6db); + map.set('Cyrillic_e', 0x6dc); + map.set('Cyrillic_shcha', 0x6dd); + map.set('Cyrillic_che', 0x6de); + map.set('Cyrillic_hardsign', 0x6df); + map.set('Cyrillic_YU', 0x6e0); + map.set('Cyrillic_A', 0x6e1); + map.set('Cyrillic_BE', 0x6e2); + map.set('Cyrillic_TSE', 0x6e3); + map.set('Cyrillic_DE', 0x6e4); + map.set('Cyrillic_IE', 0x6e5); + map.set('Cyrillic_EF', 0x6e6); + map.set('Cyrillic_GHE', 0x6e7); + map.set('Cyrillic_HA', 0x6e8); + map.set('Cyrillic_I', 0x6e9); + map.set('Cyrillic_SHORTI', 0x6ea); + map.set('Cyrillic_KA', 0x6eb); + map.set('Cyrillic_EL', 0x6ec); + map.set('Cyrillic_EM', 0x6ed); + map.set('Cyrillic_EN', 0x6ee); + map.set('Cyrillic_O', 0x6ef); + map.set('Cyrillic_PE', 0x6f0); + map.set('Cyrillic_YA', 0x6f1); + map.set('Cyrillic_ER', 0x6f2); + map.set('Cyrillic_ES', 0x6f3); + map.set('Cyrillic_TE', 0x6f4); + map.set('Cyrillic_U', 0x6f5); + map.set('Cyrillic_ZHE', 0x6f6); + map.set('Cyrillic_VE', 0x6f7); + map.set('Cyrillic_SOFTSIGN', 0x6f8); + map.set('Cyrillic_YERU', 0x6f9); + map.set('Cyrillic_ZE', 0x6fa); + map.set('Cyrillic_SHA', 0x6fb); + map.set('Cyrillic_E', 0x6fc); + map.set('Cyrillic_SHCHA', 0x6fd); + map.set('Cyrillic_CHE', 0x6fe); + map.set('Cyrillic_HARDSIGN', 0x6ff); + map.set('Greek_ALPHAaccent', 0x7a1); + map.set('Greek_EPSILONaccent', 0x7a2); + map.set('Greek_ETAaccent', 0x7a3); + map.set('Greek_IOTAaccent', 0x7a4); + map.set('Greek_IOTAdieresis', 0x7a5); + map.set('Greek_IOTAdiaeresis', 0x7a5); + map.set('Greek_OMICRONaccent', 0x7a7); + map.set('Greek_UPSILONaccent', 0x7a8); + map.set('Greek_UPSILONdieresis', 0x7a9); + map.set('Greek_OMEGAaccent', 0x7ab); + map.set('Greek_accentdieresis', 0x7ae); + map.set('Greek_horizbar', 0x7af); + map.set('Greek_alphaaccent', 0x7b1); + map.set('Greek_epsilonaccent', 0x7b2); + map.set('Greek_etaaccent', 0x7b3); + map.set('Greek_iotaaccent', 0x7b4); + map.set('Greek_iotadieresis', 0x7b5); + map.set('Greek_iotaaccentdieresis', 0x7b6); + map.set('Greek_omicronaccent', 0x7b7); + map.set('Greek_upsilonaccent', 0x7b8); + map.set('Greek_upsilondieresis', 0x7b9); + map.set('Greek_upsilonaccentdieresis', 0x7ba); + map.set('Greek_omegaaccent', 0x7bb); + map.set('Greek_ALPHA', 0x7c1); + map.set('Greek_BETA', 0x7c2); + map.set('Greek_GAMMA', 0x7c3); + map.set('Greek_DELTA', 0x7c4); + map.set('Greek_EPSILON', 0x7c5); + map.set('Greek_ZETA', 0x7c6); + map.set('Greek_ETA', 0x7c7); + map.set('Greek_THETA', 0x7c8); + map.set('Greek_IOTA', 0x7c9); + map.set('Greek_KAPPA', 0x7ca); + map.set('Greek_LAMDA', 0x7cb); + map.set('Greek_LAMBDA', 0x7cb); + map.set('Greek_MU', 0x7cc); + map.set('Greek_NU', 0x7cd); + map.set('Greek_XI', 0x7ce); + map.set('Greek_OMICRON', 0x7cf); + map.set('Greek_PI', 0x7d0); + map.set('Greek_RHO', 0x7d1); + map.set('Greek_SIGMA', 0x7d2); + map.set('Greek_TAU', 0x7d4); + map.set('Greek_UPSILON', 0x7d5); + map.set('Greek_PHI', 0x7d6); + map.set('Greek_CHI', 0x7d7); + map.set('Greek_PSI', 0x7d8); + map.set('Greek_OMEGA', 0x7d9); + map.set('Greek_alpha', 0x7e1); + map.set('Greek_beta', 0x7e2); + map.set('Greek_gamma', 0x7e3); + map.set('Greek_delta', 0x7e4); + map.set('Greek_epsilon', 0x7e5); + map.set('Greek_zeta', 0x7e6); + map.set('Greek_eta', 0x7e7); + map.set('Greek_theta', 0x7e8); + map.set('Greek_iota', 0x7e9); + map.set('Greek_kappa', 0x7ea); + map.set('Greek_lamda', 0x7eb); + map.set('Greek_lambda', 0x7eb); + map.set('Greek_mu', 0x7ec); + map.set('Greek_nu', 0x7ed); + map.set('Greek_xi', 0x7ee); + map.set('Greek_omicron', 0x7ef); + map.set('Greek_pi', 0x7f0); + map.set('Greek_rho', 0x7f1); + map.set('Greek_sigma', 0x7f2); + map.set('Greek_finalsmallsigma', 0x7f3); + map.set('Greek_tau', 0x7f4); + map.set('Greek_upsilon', 0x7f5); + map.set('Greek_phi', 0x7f6); + map.set('Greek_chi', 0x7f7); + map.set('Greek_psi', 0x7f8); + map.set('Greek_omega', 0x7f9); + map.set('Greek_switch', 0xff7e); + map.set('leftradical', 0x8a1); + map.set('topleftradical', 0x8a2); + map.set('horizconnector', 0x8a3); + map.set('topintegral', 0x8a4); + map.set('botintegral', 0x8a5); + map.set('vertconnector', 0x8a6); + map.set('topleftsqbracket', 0x8a7); + map.set('botleftsqbracket', 0x8a8); + map.set('toprightsqbracket', 0x8a9); + map.set('botrightsqbracket', 0x8aa); + map.set('topleftparens', 0x8ab); + map.set('botleftparens', 0x8ac); + map.set('toprightparens', 0x8ad); + map.set('botrightparens', 0x8ae); + map.set('leftmiddlecurlybrace', 0x8af); + map.set('rightmiddlecurlybrace', 0x8b0); + map.set('topleftsummation', 0x8b1); + map.set('botleftsummation', 0x8b2); + map.set('topvertsummationconnector', 0x8b3); + map.set('botvertsummationconnector', 0x8b4); + map.set('toprightsummation', 0x8b5); + map.set('botrightsummation', 0x8b6); + map.set('rightmiddlesummation', 0x8b7); + map.set('lessthanequal', 0x8bc); + map.set('notequal', 0x8bd); + map.set('greaterthanequal', 0x8be); + map.set('integral', 0x8bf); + map.set('therefore', 0x8c0); + map.set('variation', 0x8c1); + map.set('infinity', 0x8c2); + map.set('nabla', 0x8c5); + map.set('approximate', 0x8c8); + map.set('similarequal', 0x8c9); + map.set('ifonlyif', 0x8cd); + map.set('implies', 0x8ce); + map.set('identical', 0x8cf); + map.set('radical', 0x8d6); + map.set('includedin', 0x8da); + map.set('includes', 0x8db); + map.set('intersection', 0x8dc); + map.set('union', 0x8dd); + map.set('logicaland', 0x8de); + map.set('logicalor', 0x8df); + map.set('partialderivative', 0x8ef); + map.set('function', 0x8f6); + map.set('leftarrow', 0x8fb); + map.set('uparrow', 0x8fc); + map.set('rightarrow', 0x8fd); + map.set('downarrow', 0x8fe); + map.set('blank', 0x9df); + map.set('soliddiamond', 0x9e0); + map.set('checkerboard', 0x9e1); + map.set('ht', 0x9e2); + map.set('ff', 0x9e3); + map.set('cr', 0x9e4); + map.set('lf', 0x9e5); + map.set('nl', 0x9e8); + map.set('vt', 0x9e9); + map.set('lowrightcorner', 0x9ea); + map.set('uprightcorner', 0x9eb); + map.set('upleftcorner', 0x9ec); + map.set('lowleftcorner', 0x9ed); + map.set('crossinglines', 0x9ee); + map.set('horizlinescan1', 0x9ef); + map.set('horizlinescan3', 0x9f0); + map.set('horizlinescan5', 0x9f1); + map.set('horizlinescan7', 0x9f2); + map.set('horizlinescan9', 0x9f3); + map.set('leftt', 0x9f4); + map.set('rightt', 0x9f5); + map.set('bott', 0x9f6); + map.set('topt', 0x9f7); + map.set('vertbar', 0x9f8); + map.set('emspace', 0xaa1); + map.set('enspace', 0xaa2); + map.set('em3space', 0xaa3); + map.set('em4space', 0xaa4); + map.set('digitspace', 0xaa5); + map.set('punctspace', 0xaa6); + map.set('thinspace', 0xaa7); + map.set('hairspace', 0xaa8); + map.set('emdash', 0xaa9); + map.set('endash', 0xaaa); + map.set('signifblank', 0xaac); + map.set('ellipsis', 0xaae); + map.set('doubbaselinedot', 0xaaf); + map.set('onethird', 0xab0); + map.set('twothirds', 0xab1); + map.set('onefifth', 0xab2); + map.set('twofifths', 0xab3); + map.set('threefifths', 0xab4); + map.set('fourfifths', 0xab5); + map.set('onesixth', 0xab6); + map.set('fivesixths', 0xab7); + map.set('careof', 0xab8); + map.set('figdash', 0xabb); + map.set('leftanglebracket', 0xabc); + map.set('decimalpoint', 0xabd); + map.set('rightanglebracket', 0xabe); + map.set('marker', 0xabf); + map.set('oneeighth', 0xac3); + map.set('threeeighths', 0xac4); + map.set('fiveeighths', 0xac5); + map.set('seveneighths', 0xac6); + map.set('trademark', 0xac9); + map.set('signaturemark', 0xaca); + map.set('trademarkincircle', 0xacb); + map.set('leftopentriangle', 0xacc); + map.set('rightopentriangle', 0xacd); + map.set('emopencircle', 0xace); + map.set('emopenrectangle', 0xacf); + map.set('leftsinglequotemark', 0xad0); + map.set('rightsinglequotemark', 0xad1); + map.set('leftdoublequotemark', 0xad2); + map.set('rightdoublequotemark', 0xad3); + map.set('prescription', 0xad4); + map.set('permille', 0xad5); + map.set('minutes', 0xad6); + map.set('seconds', 0xad7); + map.set('latincross', 0xad9); + map.set('hexagram', 0xada); + map.set('filledrectbullet', 0xadb); + map.set('filledlefttribullet', 0xadc); + map.set('filledrighttribullet', 0xadd); + map.set('emfilledcircle', 0xade); + map.set('emfilledrect', 0xadf); + map.set('enopencircbullet', 0xae0); + map.set('enopensquarebullet', 0xae1); + map.set('openrectbullet', 0xae2); + map.set('opentribulletup', 0xae3); + map.set('opentribulletdown', 0xae4); + map.set('openstar', 0xae5); + map.set('enfilledcircbullet', 0xae6); + map.set('enfilledsqbullet', 0xae7); + map.set('filledtribulletup', 0xae8); + map.set('filledtribulletdown', 0xae9); + map.set('leftpointer', 0xaea); + map.set('rightpointer', 0xaeb); + map.set('club', 0xaec); + map.set('diamond', 0xaed); + map.set('heart', 0xaee); + map.set('maltesecross', 0xaf0); + map.set('dagger', 0xaf1); + map.set('doubledagger', 0xaf2); + map.set('checkmark', 0xaf3); + map.set('ballotcross', 0xaf4); + map.set('musicalsharp', 0xaf5); + map.set('musicalflat', 0xaf6); + map.set('malesymbol', 0xaf7); + map.set('femalesymbol', 0xaf8); + map.set('telephone', 0xaf9); + map.set('telephonerecorder', 0xafa); + map.set('phonographcopyright', 0xafb); + map.set('caret', 0xafc); + map.set('singlelowquotemark', 0xafd); + map.set('doublelowquotemark', 0xafe); + map.set('cursor', 0xaff); + map.set('leftcaret', 0xba3); + map.set('rightcaret', 0xba6); + map.set('downcaret', 0xba8); + map.set('upcaret', 0xba9); + map.set('overbar', 0xbc0); + map.set('downtack', 0xbc2); + map.set('upshoe', 0xbc3); + map.set('downstile', 0xbc4); + map.set('underbar', 0xbc6); + map.set('jot', 0xbca); + map.set('quad', 0xbcc); + map.set('uptack', 0xbce); + map.set('circle', 0xbcf); + map.set('upstile', 0xbd3); + map.set('downshoe', 0xbd6); + map.set('rightshoe', 0xbd8); + map.set('leftshoe', 0xbda); + map.set('lefttack', 0xbdc); + map.set('righttack', 0xbfc); + map.set('hebrew_doublelowline', 0xcdf); + map.set('hebrew_aleph', 0xce0); + map.set('hebrew_bet', 0xce1); + map.set('hebrew_beth', 0xce1); + map.set('hebrew_gimel', 0xce2); + map.set('hebrew_gimmel', 0xce2); + map.set('hebrew_dalet', 0xce3); + map.set('hebrew_daleth', 0xce3); + map.set('hebrew_he', 0xce4); + map.set('hebrew_waw', 0xce5); + map.set('hebrew_zain', 0xce6); + map.set('hebrew_zayin', 0xce6); + map.set('hebrew_chet', 0xce7); + map.set('hebrew_het', 0xce7); + map.set('hebrew_tet', 0xce8); + map.set('hebrew_teth', 0xce8); + map.set('hebrew_yod', 0xce9); + map.set('hebrew_finalkaph', 0xcea); + map.set('hebrew_kaph', 0xceb); + map.set('hebrew_lamed', 0xcec); + map.set('hebrew_finalmem', 0xced); + map.set('hebrew_mem', 0xcee); + map.set('hebrew_finalnun', 0xcef); + map.set('hebrew_nun', 0xcf0); + map.set('hebrew_samech', 0xcf1); + map.set('hebrew_samekh', 0xcf1); + map.set('hebrew_ayin', 0xcf2); + map.set('hebrew_finalpe', 0xcf3); + map.set('hebrew_pe', 0xcf4); + map.set('hebrew_finalzade', 0xcf5); + map.set('hebrew_finalzadi', 0xcf5); + map.set('hebrew_zade', 0xcf6); + map.set('hebrew_zadi', 0xcf6); + map.set('hebrew_qoph', 0xcf7); + map.set('hebrew_kuf', 0xcf7); + map.set('hebrew_resh', 0xcf8); + map.set('hebrew_shin', 0xcf9); + map.set('hebrew_taw', 0xcfa); + map.set('hebrew_taf', 0xcfa); + map.set('Hebrew_switch', 0xff7e); + map.set('Thai_kokai', 0xda1); + map.set('Thai_khokhai', 0xda2); + map.set('Thai_khokhuat', 0xda3); + map.set('Thai_khokhwai', 0xda4); + map.set('Thai_khokhon', 0xda5); + map.set('Thai_khorakhang', 0xda6); + map.set('Thai_ngongu', 0xda7); + map.set('Thai_chochan', 0xda8); + map.set('Thai_choching', 0xda9); + map.set('Thai_chochang', 0xdaa); + map.set('Thai_soso', 0xdab); + map.set('Thai_chochoe', 0xdac); + map.set('Thai_yoying', 0xdad); + map.set('Thai_dochada', 0xdae); + map.set('Thai_topatak', 0xdaf); + map.set('Thai_thothan', 0xdb0); + map.set('Thai_thonangmontho', 0xdb1); + map.set('Thai_thophuthao', 0xdb2); + map.set('Thai_nonen', 0xdb3); + map.set('Thai_dodek', 0xdb4); + map.set('Thai_totao', 0xdb5); + map.set('Thai_thothung', 0xdb6); + map.set('Thai_thothahan', 0xdb7); + map.set('Thai_thothong', 0xdb8); + map.set('Thai_nonu', 0xdb9); + map.set('Thai_bobaimai', 0xdba); + map.set('Thai_popla', 0xdbb); + map.set('Thai_phophung', 0xdbc); + map.set('Thai_fofa', 0xdbd); + map.set('Thai_phophan', 0xdbe); + map.set('Thai_fofan', 0xdbf); + map.set('Thai_phosamphao', 0xdc0); + map.set('Thai_moma', 0xdc1); + map.set('Thai_yoyak', 0xdc2); + map.set('Thai_rorua', 0xdc3); + map.set('Thai_ru', 0xdc4); + map.set('Thai_loling', 0xdc5); + map.set('Thai_lu', 0xdc6); + map.set('Thai_wowaen', 0xdc7); + map.set('Thai_sosala', 0xdc8); + map.set('Thai_sorusi', 0xdc9); + map.set('Thai_sosua', 0xdca); + map.set('Thai_hohip', 0xdcb); + map.set('Thai_lochula', 0xdcc); + map.set('Thai_oang', 0xdcd); + map.set('Thai_honokhuk', 0xdce); + map.set('Thai_paiyannoi', 0xdcf); + map.set('Thai_saraa', 0xdd0); + map.set('Thai_maihanakat', 0xdd1); + map.set('Thai_saraaa', 0xdd2); + map.set('Thai_saraam', 0xdd3); + map.set('Thai_sarai', 0xdd4); + map.set('Thai_saraii', 0xdd5); + map.set('Thai_saraue', 0xdd6); + map.set('Thai_sarauee', 0xdd7); + map.set('Thai_sarau', 0xdd8); + map.set('Thai_sarauu', 0xdd9); + map.set('Thai_phinthu', 0xdda); + map.set('Thai_maihanakat_maitho', 0xdde); + map.set('Thai_baht', 0xddf); + map.set('Thai_sarae', 0xde0); + map.set('Thai_saraae', 0xde1); + map.set('Thai_sarao', 0xde2); + map.set('Thai_saraaimaimuan', 0xde3); + map.set('Thai_saraaimaimalai', 0xde4); + map.set('Thai_lakkhangyao', 0xde5); + map.set('Thai_maiyamok', 0xde6); + map.set('Thai_maitaikhu', 0xde7); + map.set('Thai_maiek', 0xde8); + map.set('Thai_maitho', 0xde9); + map.set('Thai_maitri', 0xdea); + map.set('Thai_maichattawa', 0xdeb); + map.set('Thai_thanthakhat', 0xdec); + map.set('Thai_nikhahit', 0xded); + map.set('Thai_leksun', 0xdf0); + map.set('Thai_leknung', 0xdf1); + map.set('Thai_leksong', 0xdf2); + map.set('Thai_leksam', 0xdf3); + map.set('Thai_leksi', 0xdf4); + map.set('Thai_lekha', 0xdf5); + map.set('Thai_lekhok', 0xdf6); + map.set('Thai_lekchet', 0xdf7); + map.set('Thai_lekpaet', 0xdf8); + map.set('Thai_lekkao', 0xdf9); + map.set('Hangul', 0xff31); + map.set('Hangul_Start', 0xff32); + map.set('Hangul_End', 0xff33); + map.set('Hangul_Hanja', 0xff34); + map.set('Hangul_Jamo', 0xff35); + map.set('Hangul_Romaja', 0xff36); + map.set('Hangul_Codeinput', 0xff37); + map.set('Hangul_Jeonja', 0xff38); + map.set('Hangul_Banja', 0xff39); + map.set('Hangul_PreHanja', 0xff3a); + map.set('Hangul_PostHanja', 0xff3b); + map.set('Hangul_SingleCandidate', 0xff3c); + map.set('Hangul_MultipleCandidate', 0xff3d); + map.set('Hangul_PreviousCandidate', 0xff3e); + map.set('Hangul_Special', 0xff3f); + map.set('Hangul_switch', 0xff7e); + map.set('Hangul_Kiyeog', 0xea1); + map.set('Hangul_SsangKiyeog', 0xea2); + map.set('Hangul_KiyeogSios', 0xea3); + map.set('Hangul_Nieun', 0xea4); + map.set('Hangul_NieunJieuj', 0xea5); + map.set('Hangul_NieunHieuh', 0xea6); + map.set('Hangul_Dikeud', 0xea7); + map.set('Hangul_SsangDikeud', 0xea8); + map.set('Hangul_Rieul', 0xea9); + map.set('Hangul_RieulKiyeog', 0xeaa); + map.set('Hangul_RieulMieum', 0xeab); + map.set('Hangul_RieulPieub', 0xeac); + map.set('Hangul_RieulSios', 0xead); + map.set('Hangul_RieulTieut', 0xeae); + map.set('Hangul_RieulPhieuf', 0xeaf); + map.set('Hangul_RieulHieuh', 0xeb0); + map.set('Hangul_Mieum', 0xeb1); + map.set('Hangul_Pieub', 0xeb2); + map.set('Hangul_SsangPieub', 0xeb3); + map.set('Hangul_PieubSios', 0xeb4); + map.set('Hangul_Sios', 0xeb5); + map.set('Hangul_SsangSios', 0xeb6); + map.set('Hangul_Ieung', 0xeb7); + map.set('Hangul_Jieuj', 0xeb8); + map.set('Hangul_SsangJieuj', 0xeb9); + map.set('Hangul_Cieuc', 0xeba); + map.set('Hangul_Khieuq', 0xebb); + map.set('Hangul_Tieut', 0xebc); + map.set('Hangul_Phieuf', 0xebd); + map.set('Hangul_Hieuh', 0xebe); + map.set('Hangul_A', 0xebf); + map.set('Hangul_AE', 0xec0); + map.set('Hangul_YA', 0xec1); + map.set('Hangul_YAE', 0xec2); + map.set('Hangul_EO', 0xec3); + map.set('Hangul_E', 0xec4); + map.set('Hangul_YEO', 0xec5); + map.set('Hangul_YE', 0xec6); + map.set('Hangul_O', 0xec7); + map.set('Hangul_WA', 0xec8); + map.set('Hangul_WAE', 0xec9); + map.set('Hangul_OE', 0xeca); + map.set('Hangul_YO', 0xecb); + map.set('Hangul_U', 0xecc); + map.set('Hangul_WEO', 0xecd); + map.set('Hangul_WE', 0xece); + map.set('Hangul_WI', 0xecf); + map.set('Hangul_YU', 0xed0); + map.set('Hangul_EU', 0xed1); + map.set('Hangul_YI', 0xed2); + map.set('Hangul_I', 0xed3); + map.set('Hangul_J_Kiyeog', 0xed4); + map.set('Hangul_J_SsangKiyeog', 0xed5); + map.set('Hangul_J_KiyeogSios', 0xed6); + map.set('Hangul_J_Nieun', 0xed7); + map.set('Hangul_J_NieunJieuj', 0xed8); + map.set('Hangul_J_NieunHieuh', 0xed9); + map.set('Hangul_J_Dikeud', 0xeda); + map.set('Hangul_J_Rieul', 0xedb); + map.set('Hangul_J_RieulKiyeog', 0xedc); + map.set('Hangul_J_RieulMieum', 0xedd); + map.set('Hangul_J_RieulPieub', 0xede); + map.set('Hangul_J_RieulSios', 0xedf); + map.set('Hangul_J_RieulTieut', 0xee0); + map.set('Hangul_J_RieulPhieuf', 0xee1); + map.set('Hangul_J_RieulHieuh', 0xee2); + map.set('Hangul_J_Mieum', 0xee3); + map.set('Hangul_J_Pieub', 0xee4); + map.set('Hangul_J_PieubSios', 0xee5); + map.set('Hangul_J_Sios', 0xee6); + map.set('Hangul_J_SsangSios', 0xee7); + map.set('Hangul_J_Ieung', 0xee8); + map.set('Hangul_J_Jieuj', 0xee9); + map.set('Hangul_J_Cieuc', 0xeea); + map.set('Hangul_J_Khieuq', 0xeeb); + map.set('Hangul_J_Tieut', 0xeec); + map.set('Hangul_J_Phieuf', 0xeed); + map.set('Hangul_J_Hieuh', 0xeee); + map.set('Hangul_RieulYeorinHieuh', 0xeef); + map.set('Hangul_SunkyeongeumMieum', 0xef0); + map.set('Hangul_SunkyeongeumPieub', 0xef1); + map.set('Hangul_PanSios', 0xef2); + map.set('Hangul_KkogjiDalrinIeung', 0xef3); + map.set('Hangul_SunkyeongeumPhieuf', 0xef4); + map.set('Hangul_YeorinHieuh', 0xef5); + map.set('Hangul_AraeA', 0xef6); + map.set('Hangul_AraeAE', 0xef7); + map.set('Hangul_J_PanSios', 0xef8); + map.set('Hangul_J_KkogjiDalrinIeung', 0xef9); + map.set('Hangul_J_YeorinHieuh', 0xefa); + map.set('Korean_Won', 0xeff); + map.set('Armenian_ligature_ew', 0x1000587); + map.set('Armenian_full_stop', 0x1000589); + map.set('Armenian_verjaket', 0x1000589); + map.set('Armenian_separation_mark', 0x100055d); + map.set('Armenian_but', 0x100055d); + map.set('Armenian_hyphen', 0x100058a); + map.set('Armenian_yentamna', 0x100058a); + map.set('Armenian_exclam', 0x100055c); + map.set('Armenian_amanak', 0x100055c); + map.set('Armenian_accent', 0x100055b); + map.set('Armenian_shesht', 0x100055b); + map.set('Armenian_question', 0x100055e); + map.set('Armenian_paruyk', 0x100055e); + map.set('Armenian_AYB', 0x1000531); + map.set('Armenian_ayb', 0x1000561); + map.set('Armenian_BEN', 0x1000532); + map.set('Armenian_ben', 0x1000562); + map.set('Armenian_GIM', 0x1000533); + map.set('Armenian_gim', 0x1000563); + map.set('Armenian_DA', 0x1000534); + map.set('Armenian_da', 0x1000564); + map.set('Armenian_YECH', 0x1000535); + map.set('Armenian_yech', 0x1000565); + map.set('Armenian_ZA', 0x1000536); + map.set('Armenian_za', 0x1000566); + map.set('Armenian_E', 0x1000537); + map.set('Armenian_e', 0x1000567); + map.set('Armenian_AT', 0x1000538); + map.set('Armenian_at', 0x1000568); + map.set('Armenian_TO', 0x1000539); + map.set('Armenian_to', 0x1000569); + map.set('Armenian_ZHE', 0x100053a); + map.set('Armenian_zhe', 0x100056a); + map.set('Armenian_INI', 0x100053b); + map.set('Armenian_ini', 0x100056b); + map.set('Armenian_LYUN', 0x100053c); + map.set('Armenian_lyun', 0x100056c); + map.set('Armenian_KHE', 0x100053d); + map.set('Armenian_khe', 0x100056d); + map.set('Armenian_TSA', 0x100053e); + map.set('Armenian_tsa', 0x100056e); + map.set('Armenian_KEN', 0x100053f); + map.set('Armenian_ken', 0x100056f); + map.set('Armenian_HO', 0x1000540); + map.set('Armenian_ho', 0x1000570); + map.set('Armenian_DZA', 0x1000541); + map.set('Armenian_dza', 0x1000571); + map.set('Armenian_GHAT', 0x1000542); + map.set('Armenian_ghat', 0x1000572); + map.set('Armenian_TCHE', 0x1000543); + map.set('Armenian_tche', 0x1000573); + map.set('Armenian_MEN', 0x1000544); + map.set('Armenian_men', 0x1000574); + map.set('Armenian_HI', 0x1000545); + map.set('Armenian_hi', 0x1000575); + map.set('Armenian_NU', 0x1000546); + map.set('Armenian_nu', 0x1000576); + map.set('Armenian_SHA', 0x1000547); + map.set('Armenian_sha', 0x1000577); + map.set('Armenian_VO', 0x1000548); + map.set('Armenian_vo', 0x1000578); + map.set('Armenian_CHA', 0x1000549); + map.set('Armenian_cha', 0x1000579); + map.set('Armenian_PE', 0x100054a); + map.set('Armenian_pe', 0x100057a); + map.set('Armenian_JE', 0x100054b); + map.set('Armenian_je', 0x100057b); + map.set('Armenian_RA', 0x100054c); + map.set('Armenian_ra', 0x100057c); + map.set('Armenian_SE', 0x100054d); + map.set('Armenian_se', 0x100057d); + map.set('Armenian_VEV', 0x100054e); + map.set('Armenian_vev', 0x100057e); + map.set('Armenian_TYUN', 0x100054f); + map.set('Armenian_tyun', 0x100057f); + map.set('Armenian_RE', 0x1000550); + map.set('Armenian_re', 0x1000580); + map.set('Armenian_TSO', 0x1000551); + map.set('Armenian_tso', 0x1000581); + map.set('Armenian_VYUN', 0x1000552); + map.set('Armenian_vyun', 0x1000582); + map.set('Armenian_PYUR', 0x1000553); + map.set('Armenian_pyur', 0x1000583); + map.set('Armenian_KE', 0x1000554); + map.set('Armenian_ke', 0x1000584); + map.set('Armenian_O', 0x1000555); + map.set('Armenian_o', 0x1000585); + map.set('Armenian_FE', 0x1000556); + map.set('Armenian_fe', 0x1000586); + map.set('Armenian_apostrophe', 0x100055a); + map.set('Georgian_an', 0x10010d0); + map.set('Georgian_ban', 0x10010d1); + map.set('Georgian_gan', 0x10010d2); + map.set('Georgian_don', 0x10010d3); + map.set('Georgian_en', 0x10010d4); + map.set('Georgian_vin', 0x10010d5); + map.set('Georgian_zen', 0x10010d6); + map.set('Georgian_tan', 0x10010d7); + map.set('Georgian_in', 0x10010d8); + map.set('Georgian_kan', 0x10010d9); + map.set('Georgian_las', 0x10010da); + map.set('Georgian_man', 0x10010db); + map.set('Georgian_nar', 0x10010dc); + map.set('Georgian_on', 0x10010dd); + map.set('Georgian_par', 0x10010de); + map.set('Georgian_zhar', 0x10010df); + map.set('Georgian_rae', 0x10010e0); + map.set('Georgian_san', 0x10010e1); + map.set('Georgian_tar', 0x10010e2); + map.set('Georgian_un', 0x10010e3); + map.set('Georgian_phar', 0x10010e4); + map.set('Georgian_khar', 0x10010e5); + map.set('Georgian_ghan', 0x10010e6); + map.set('Georgian_qar', 0x10010e7); + map.set('Georgian_shin', 0x10010e8); + map.set('Georgian_chin', 0x10010e9); + map.set('Georgian_can', 0x10010ea); + map.set('Georgian_jil', 0x10010eb); + map.set('Georgian_cil', 0x10010ec); + map.set('Georgian_char', 0x10010ed); + map.set('Georgian_xan', 0x10010ee); + map.set('Georgian_jhan', 0x10010ef); + map.set('Georgian_hae', 0x10010f0); + map.set('Georgian_he', 0x10010f1); + map.set('Georgian_hie', 0x10010f2); + map.set('Georgian_we', 0x10010f3); + map.set('Georgian_har', 0x10010f4); + map.set('Georgian_hoe', 0x10010f5); + map.set('Georgian_fi', 0x10010f6); + map.set('Xabovedot', 0x1001e8a); + map.set('Ibreve', 0x100012c); + map.set('Zstroke', 0x10001b5); + map.set('Gcaron', 0x10001e6); + map.set('Ocaron', 0x10001d1); + map.set('Obarred', 0x100019f); + map.set('xabovedot', 0x1001e8b); + map.set('ibreve', 0x100012d); + map.set('zstroke', 0x10001b6); + map.set('gcaron', 0x10001e7); + map.set('ocaron', 0x10001d2); + map.set('obarred', 0x1000275); + map.set('SCHWA', 0x100018f); + map.set('schwa', 0x1000259); + map.set('EZH', 0x10001b7); + map.set('ezh', 0x1000292); + map.set('Lbelowdot', 0x1001e36); + map.set('lbelowdot', 0x1001e37); + map.set('Abelowdot', 0x1001ea0); + map.set('abelowdot', 0x1001ea1); + map.set('Ahook', 0x1001ea2); + map.set('ahook', 0x1001ea3); + map.set('Acircumflexacute', 0x1001ea4); + map.set('acircumflexacute', 0x1001ea5); + map.set('Acircumflexgrave', 0x1001ea6); + map.set('acircumflexgrave', 0x1001ea7); + map.set('Acircumflexhook', 0x1001ea8); + map.set('acircumflexhook', 0x1001ea9); + map.set('Acircumflextilde', 0x1001eaa); + map.set('acircumflextilde', 0x1001eab); + map.set('Acircumflexbelowdot', 0x1001eac); + map.set('acircumflexbelowdot', 0x1001ead); + map.set('Abreveacute', 0x1001eae); + map.set('abreveacute', 0x1001eaf); + map.set('Abrevegrave', 0x1001eb0); + map.set('abrevegrave', 0x1001eb1); + map.set('Abrevehook', 0x1001eb2); + map.set('abrevehook', 0x1001eb3); + map.set('Abrevetilde', 0x1001eb4); + map.set('abrevetilde', 0x1001eb5); + map.set('Abrevebelowdot', 0x1001eb6); + map.set('abrevebelowdot', 0x1001eb7); + map.set('Ebelowdot', 0x1001eb8); + map.set('ebelowdot', 0x1001eb9); + map.set('Ehook', 0x1001eba); + map.set('ehook', 0x1001ebb); + map.set('Etilde', 0x1001ebc); + map.set('etilde', 0x1001ebd); + map.set('Ecircumflexacute', 0x1001ebe); + map.set('ecircumflexacute', 0x1001ebf); + map.set('Ecircumflexgrave', 0x1001ec0); + map.set('ecircumflexgrave', 0x1001ec1); + map.set('Ecircumflexhook', 0x1001ec2); + map.set('ecircumflexhook', 0x1001ec3); + map.set('Ecircumflextilde', 0x1001ec4); + map.set('ecircumflextilde', 0x1001ec5); + map.set('Ecircumflexbelowdot', 0x1001ec6); + map.set('ecircumflexbelowdot', 0x1001ec7); + map.set('Ihook', 0x1001ec8); + map.set('ihook', 0x1001ec9); + map.set('Ibelowdot', 0x1001eca); + map.set('ibelowdot', 0x1001ecb); + map.set('Obelowdot', 0x1001ecc); + map.set('obelowdot', 0x1001ecd); + map.set('Ohook', 0x1001ece); + map.set('ohook', 0x1001ecf); + map.set('Ocircumflexacute', 0x1001ed0); + map.set('ocircumflexacute', 0x1001ed1); + map.set('Ocircumflexgrave', 0x1001ed2); + map.set('ocircumflexgrave', 0x1001ed3); + map.set('Ocircumflexhook', 0x1001ed4); + map.set('ocircumflexhook', 0x1001ed5); + map.set('Ocircumflextilde', 0x1001ed6); + map.set('ocircumflextilde', 0x1001ed7); + map.set('Ocircumflexbelowdot', 0x1001ed8); + map.set('ocircumflexbelowdot', 0x1001ed9); + map.set('Ohornacute', 0x1001eda); + map.set('ohornacute', 0x1001edb); + map.set('Ohorngrave', 0x1001edc); + map.set('ohorngrave', 0x1001edd); + map.set('Ohornhook', 0x1001ede); + map.set('ohornhook', 0x1001edf); + map.set('Ohorntilde', 0x1001ee0); + map.set('ohorntilde', 0x1001ee1); + map.set('Ohornbelowdot', 0x1001ee2); + map.set('ohornbelowdot', 0x1001ee3); + map.set('Ubelowdot', 0x1001ee4); + map.set('ubelowdot', 0x1001ee5); + map.set('Uhook', 0x1001ee6); + map.set('uhook', 0x1001ee7); + map.set('Uhornacute', 0x1001ee8); + map.set('uhornacute', 0x1001ee9); + map.set('Uhorngrave', 0x1001eea); + map.set('uhorngrave', 0x1001eeb); + map.set('Uhornhook', 0x1001eec); + map.set('uhornhook', 0x1001eed); + map.set('Uhorntilde', 0x1001eee); + map.set('uhorntilde', 0x1001eef); + map.set('Uhornbelowdot', 0x1001ef0); + map.set('uhornbelowdot', 0x1001ef1); + map.set('Ybelowdot', 0x1001ef4); + map.set('ybelowdot', 0x1001ef5); + map.set('Yhook', 0x1001ef6); + map.set('yhook', 0x1001ef7); + map.set('Ytilde', 0x1001ef8); + map.set('ytilde', 0x1001ef9); + map.set('Ohorn', 0x10001a0); + map.set('ohorn', 0x10001a1); + map.set('Uhorn', 0x10001af); + map.set('uhorn', 0x10001b0); + map.set('EcuSign', 0x10020a0); + map.set('ColonSign', 0x10020a1); + map.set('CruzeiroSign', 0x10020a2); + map.set('FFrancSign', 0x10020a3); + map.set('LiraSign', 0x10020a4); + map.set('MillSign', 0x10020a5); + map.set('NairaSign', 0x10020a6); + map.set('PesetaSign', 0x10020a7); + map.set('RupeeSign', 0x10020a8); + map.set('WonSign', 0x10020a9); + map.set('NewSheqelSign', 0x10020aa); + map.set('DongSign', 0x10020ab); + map.set('EuroSign', 0x20ac); + map.set('zerosuperior', 0x1002070); + map.set('foursuperior', 0x1002074); + map.set('fivesuperior', 0x1002075); + map.set('sixsuperior', 0x1002076); + map.set('sevensuperior', 0x1002077); + map.set('eightsuperior', 0x1002078); + map.set('ninesuperior', 0x1002079); + map.set('zerosubscript', 0x1002080); + map.set('onesubscript', 0x1002081); + map.set('twosubscript', 0x1002082); + map.set('threesubscript', 0x1002083); + map.set('foursubscript', 0x1002084); + map.set('fivesubscript', 0x1002085); + map.set('sixsubscript', 0x1002086); + map.set('sevensubscript', 0x1002087); + map.set('eightsubscript', 0x1002088); + map.set('ninesubscript', 0x1002089); + map.set('partdifferential', 0x1002202); + map.set('emptyset', 0x1002205); + map.set('elementof', 0x1002208); + map.set('notelementof', 0x1002209); + map.set('containsas', 0x100220b); + map.set('squareroot', 0x100221a); + map.set('cuberoot', 0x100221b); + map.set('fourthroot', 0x100221c); + map.set('dintegral', 0x100222c); + map.set('tintegral', 0x100222d); + map.set('because', 0x1002235); + map.set('approxeq', 0x1002248); + map.set('notapproxeq', 0x1002247); + map.set('notidentical', 0x1002262); + map.set('stricteq', 0x1002263); + map.set('braille_dot_1', 0xfff1); + map.set('braille_dot_2', 0xfff2); + map.set('braille_dot_3', 0xfff3); + map.set('braille_dot_4', 0xfff4); + map.set('braille_dot_5', 0xfff5); + map.set('braille_dot_6', 0xfff6); + map.set('braille_dot_7', 0xfff7); + map.set('braille_dot_8', 0xfff8); + map.set('braille_dot_9', 0xfff9); + map.set('braille_dot_10', 0xfffa); + map.set('braille_blank', 0x1002800); + map.set('braille_dots_1', 0x1002801); + map.set('braille_dots_2', 0x1002802); + map.set('braille_dots_12', 0x1002803); + map.set('braille_dots_3', 0x1002804); + map.set('braille_dots_13', 0x1002805); + map.set('braille_dots_23', 0x1002806); + map.set('braille_dots_123', 0x1002807); + map.set('braille_dots_4', 0x1002808); + map.set('braille_dots_14', 0x1002809); + map.set('braille_dots_24', 0x100280a); + map.set('braille_dots_124', 0x100280b); + map.set('braille_dots_34', 0x100280c); + map.set('braille_dots_134', 0x100280d); + map.set('braille_dots_234', 0x100280e); + map.set('braille_dots_1234', 0x100280f); + map.set('braille_dots_5', 0x1002810); + map.set('braille_dots_15', 0x1002811); + map.set('braille_dots_25', 0x1002812); + map.set('braille_dots_125', 0x1002813); + map.set('braille_dots_35', 0x1002814); + map.set('braille_dots_135', 0x1002815); + map.set('braille_dots_235', 0x1002816); + map.set('braille_dots_1235', 0x1002817); + map.set('braille_dots_45', 0x1002818); + map.set('braille_dots_145', 0x1002819); + map.set('braille_dots_245', 0x100281a); + map.set('braille_dots_1245', 0x100281b); + map.set('braille_dots_345', 0x100281c); + map.set('braille_dots_1345', 0x100281d); + map.set('braille_dots_2345', 0x100281e); + map.set('braille_dots_12345', 0x100281f); + map.set('braille_dots_6', 0x1002820); + map.set('braille_dots_16', 0x1002821); + map.set('braille_dots_26', 0x1002822); + map.set('braille_dots_126', 0x1002823); + map.set('braille_dots_36', 0x1002824); + map.set('braille_dots_136', 0x1002825); + map.set('braille_dots_236', 0x1002826); + map.set('braille_dots_1236', 0x1002827); + map.set('braille_dots_46', 0x1002828); + map.set('braille_dots_146', 0x1002829); + map.set('braille_dots_246', 0x100282a); + map.set('braille_dots_1246', 0x100282b); + map.set('braille_dots_346', 0x100282c); + map.set('braille_dots_1346', 0x100282d); + map.set('braille_dots_2346', 0x100282e); + map.set('braille_dots_12346', 0x100282f); + map.set('braille_dots_56', 0x1002830); + map.set('braille_dots_156', 0x1002831); + map.set('braille_dots_256', 0x1002832); + map.set('braille_dots_1256', 0x1002833); + map.set('braille_dots_356', 0x1002834); + map.set('braille_dots_1356', 0x1002835); + map.set('braille_dots_2356', 0x1002836); + map.set('braille_dots_12356', 0x1002837); + map.set('braille_dots_456', 0x1002838); + map.set('braille_dots_1456', 0x1002839); + map.set('braille_dots_2456', 0x100283a); + map.set('braille_dots_12456', 0x100283b); + map.set('braille_dots_3456', 0x100283c); + map.set('braille_dots_13456', 0x100283d); + map.set('braille_dots_23456', 0x100283e); + map.set('braille_dots_123456', 0x100283f); + map.set('braille_dots_7', 0x1002840); + map.set('braille_dots_17', 0x1002841); + map.set('braille_dots_27', 0x1002842); + map.set('braille_dots_127', 0x1002843); + map.set('braille_dots_37', 0x1002844); + map.set('braille_dots_137', 0x1002845); + map.set('braille_dots_237', 0x1002846); + map.set('braille_dots_1237', 0x1002847); + map.set('braille_dots_47', 0x1002848); + map.set('braille_dots_147', 0x1002849); + map.set('braille_dots_247', 0x100284a); + map.set('braille_dots_1247', 0x100284b); + map.set('braille_dots_347', 0x100284c); + map.set('braille_dots_1347', 0x100284d); + map.set('braille_dots_2347', 0x100284e); + map.set('braille_dots_12347', 0x100284f); + map.set('braille_dots_57', 0x1002850); + map.set('braille_dots_157', 0x1002851); + map.set('braille_dots_257', 0x1002852); + map.set('braille_dots_1257', 0x1002853); + map.set('braille_dots_357', 0x1002854); + map.set('braille_dots_1357', 0x1002855); + map.set('braille_dots_2357', 0x1002856); + map.set('braille_dots_12357', 0x1002857); + map.set('braille_dots_457', 0x1002858); + map.set('braille_dots_1457', 0x1002859); + map.set('braille_dots_2457', 0x100285a); + map.set('braille_dots_12457', 0x100285b); + map.set('braille_dots_3457', 0x100285c); + map.set('braille_dots_13457', 0x100285d); + map.set('braille_dots_23457', 0x100285e); + map.set('braille_dots_123457', 0x100285f); + map.set('braille_dots_67', 0x1002860); + map.set('braille_dots_167', 0x1002861); + map.set('braille_dots_267', 0x1002862); + map.set('braille_dots_1267', 0x1002863); + map.set('braille_dots_367', 0x1002864); + map.set('braille_dots_1367', 0x1002865); + map.set('braille_dots_2367', 0x1002866); + map.set('braille_dots_12367', 0x1002867); + map.set('braille_dots_467', 0x1002868); + map.set('braille_dots_1467', 0x1002869); + map.set('braille_dots_2467', 0x100286a); + map.set('braille_dots_12467', 0x100286b); + map.set('braille_dots_3467', 0x100286c); + map.set('braille_dots_13467', 0x100286d); + map.set('braille_dots_23467', 0x100286e); + map.set('braille_dots_123467', 0x100286f); + map.set('braille_dots_567', 0x1002870); + map.set('braille_dots_1567', 0x1002871); + map.set('braille_dots_2567', 0x1002872); + map.set('braille_dots_12567', 0x1002873); + map.set('braille_dots_3567', 0x1002874); + map.set('braille_dots_13567', 0x1002875); + map.set('braille_dots_23567', 0x1002876); + map.set('braille_dots_123567', 0x1002877); + map.set('braille_dots_4567', 0x1002878); + map.set('braille_dots_14567', 0x1002879); + map.set('braille_dots_24567', 0x100287a); + map.set('braille_dots_124567', 0x100287b); + map.set('braille_dots_34567', 0x100287c); + map.set('braille_dots_134567', 0x100287d); + map.set('braille_dots_234567', 0x100287e); + map.set('braille_dots_1234567', 0x100287f); + map.set('braille_dots_8', 0x1002880); + map.set('braille_dots_18', 0x1002881); + map.set('braille_dots_28', 0x1002882); + map.set('braille_dots_128', 0x1002883); + map.set('braille_dots_38', 0x1002884); + map.set('braille_dots_138', 0x1002885); + map.set('braille_dots_238', 0x1002886); + map.set('braille_dots_1238', 0x1002887); + map.set('braille_dots_48', 0x1002888); + map.set('braille_dots_148', 0x1002889); + map.set('braille_dots_248', 0x100288a); + map.set('braille_dots_1248', 0x100288b); + map.set('braille_dots_348', 0x100288c); + map.set('braille_dots_1348', 0x100288d); + map.set('braille_dots_2348', 0x100288e); + map.set('braille_dots_12348', 0x100288f); + map.set('braille_dots_58', 0x1002890); + map.set('braille_dots_158', 0x1002891); + map.set('braille_dots_258', 0x1002892); + map.set('braille_dots_1258', 0x1002893); + map.set('braille_dots_358', 0x1002894); + map.set('braille_dots_1358', 0x1002895); + map.set('braille_dots_2358', 0x1002896); + map.set('braille_dots_12358', 0x1002897); + map.set('braille_dots_458', 0x1002898); + map.set('braille_dots_1458', 0x1002899); + map.set('braille_dots_2458', 0x100289a); + map.set('braille_dots_12458', 0x100289b); + map.set('braille_dots_3458', 0x100289c); + map.set('braille_dots_13458', 0x100289d); + map.set('braille_dots_23458', 0x100289e); + map.set('braille_dots_123458', 0x100289f); + map.set('braille_dots_68', 0x10028a0); + map.set('braille_dots_168', 0x10028a1); + map.set('braille_dots_268', 0x10028a2); + map.set('braille_dots_1268', 0x10028a3); + map.set('braille_dots_368', 0x10028a4); + map.set('braille_dots_1368', 0x10028a5); + map.set('braille_dots_2368', 0x10028a6); + map.set('braille_dots_12368', 0x10028a7); + map.set('braille_dots_468', 0x10028a8); + map.set('braille_dots_1468', 0x10028a9); + map.set('braille_dots_2468', 0x10028aa); + map.set('braille_dots_12468', 0x10028ab); + map.set('braille_dots_3468', 0x10028ac); + map.set('braille_dots_13468', 0x10028ad); + map.set('braille_dots_23468', 0x10028ae); + map.set('braille_dots_123468', 0x10028af); + map.set('braille_dots_568', 0x10028b0); + map.set('braille_dots_1568', 0x10028b1); + map.set('braille_dots_2568', 0x10028b2); + map.set('braille_dots_12568', 0x10028b3); + map.set('braille_dots_3568', 0x10028b4); + map.set('braille_dots_13568', 0x10028b5); + map.set('braille_dots_23568', 0x10028b6); + map.set('braille_dots_123568', 0x10028b7); + map.set('braille_dots_4568', 0x10028b8); + map.set('braille_dots_14568', 0x10028b9); + map.set('braille_dots_24568', 0x10028ba); + map.set('braille_dots_124568', 0x10028bb); + map.set('braille_dots_34568', 0x10028bc); + map.set('braille_dots_134568', 0x10028bd); + map.set('braille_dots_234568', 0x10028be); + map.set('braille_dots_1234568', 0x10028bf); + map.set('braille_dots_78', 0x10028c0); + map.set('braille_dots_178', 0x10028c1); + map.set('braille_dots_278', 0x10028c2); + map.set('braille_dots_1278', 0x10028c3); + map.set('braille_dots_378', 0x10028c4); + map.set('braille_dots_1378', 0x10028c5); + map.set('braille_dots_2378', 0x10028c6); + map.set('braille_dots_12378', 0x10028c7); + map.set('braille_dots_478', 0x10028c8); + map.set('braille_dots_1478', 0x10028c9); + map.set('braille_dots_2478', 0x10028ca); + map.set('braille_dots_12478', 0x10028cb); + map.set('braille_dots_3478', 0x10028cc); + map.set('braille_dots_13478', 0x10028cd); + map.set('braille_dots_23478', 0x10028ce); + map.set('braille_dots_123478', 0x10028cf); + map.set('braille_dots_578', 0x10028d0); + map.set('braille_dots_1578', 0x10028d1); + map.set('braille_dots_2578', 0x10028d2); + map.set('braille_dots_12578', 0x10028d3); + map.set('braille_dots_3578', 0x10028d4); + map.set('braille_dots_13578', 0x10028d5); + map.set('braille_dots_23578', 0x10028d6); + map.set('braille_dots_123578', 0x10028d7); + map.set('braille_dots_4578', 0x10028d8); + map.set('braille_dots_14578', 0x10028d9); + map.set('braille_dots_24578', 0x10028da); + map.set('braille_dots_124578', 0x10028db); + map.set('braille_dots_34578', 0x10028dc); + map.set('braille_dots_134578', 0x10028dd); + map.set('braille_dots_234578', 0x10028de); + map.set('braille_dots_1234578', 0x10028df); + map.set('braille_dots_678', 0x10028e0); + map.set('braille_dots_1678', 0x10028e1); + map.set('braille_dots_2678', 0x10028e2); + map.set('braille_dots_12678', 0x10028e3); + map.set('braille_dots_3678', 0x10028e4); + map.set('braille_dots_13678', 0x10028e5); + map.set('braille_dots_23678', 0x10028e6); + map.set('braille_dots_123678', 0x10028e7); + map.set('braille_dots_4678', 0x10028e8); + map.set('braille_dots_14678', 0x10028e9); + map.set('braille_dots_24678', 0x10028ea); + map.set('braille_dots_124678', 0x10028eb); + map.set('braille_dots_34678', 0x10028ec); + map.set('braille_dots_134678', 0x10028ed); + map.set('braille_dots_234678', 0x10028ee); + map.set('braille_dots_1234678', 0x10028ef); + map.set('braille_dots_5678', 0x10028f0); + map.set('braille_dots_15678', 0x10028f1); + map.set('braille_dots_25678', 0x10028f2); + map.set('braille_dots_125678', 0x10028f3); + map.set('braille_dots_35678', 0x10028f4); + map.set('braille_dots_135678', 0x10028f5); + map.set('braille_dots_235678', 0x10028f6); + map.set('braille_dots_1235678', 0x10028f7); + map.set('braille_dots_45678', 0x10028f8); + map.set('braille_dots_145678', 0x10028f9); + map.set('braille_dots_245678', 0x10028fa); + map.set('braille_dots_1245678', 0x10028fb); + map.set('braille_dots_345678', 0x10028fc); + map.set('braille_dots_1345678', 0x10028fd); + map.set('braille_dots_2345678', 0x10028fe); + map.set('braille_dots_12345678', 0x10028ff); + map.set('Sinh_ng', 0x1000d82); + map.set('Sinh_h2', 0x1000d83); + map.set('Sinh_a', 0x1000d85); + map.set('Sinh_aa', 0x1000d86); + map.set('Sinh_ae', 0x1000d87); + map.set('Sinh_aee', 0x1000d88); + map.set('Sinh_i', 0x1000d89); + map.set('Sinh_ii', 0x1000d8a); + map.set('Sinh_u', 0x1000d8b); + map.set('Sinh_uu', 0x1000d8c); + map.set('Sinh_ri', 0x1000d8d); + map.set('Sinh_rii', 0x1000d8e); + map.set('Sinh_lu', 0x1000d8f); + map.set('Sinh_luu', 0x1000d90); + map.set('Sinh_e', 0x1000d91); + map.set('Sinh_ee', 0x1000d92); + map.set('Sinh_ai', 0x1000d93); + map.set('Sinh_o', 0x1000d94); + map.set('Sinh_oo', 0x1000d95); + map.set('Sinh_au', 0x1000d96); + map.set('Sinh_ka', 0x1000d9a); + map.set('Sinh_kha', 0x1000d9b); + map.set('Sinh_ga', 0x1000d9c); + map.set('Sinh_gha', 0x1000d9d); + map.set('Sinh_ng2', 0x1000d9e); + map.set('Sinh_nga', 0x1000d9f); + map.set('Sinh_ca', 0x1000da0); + map.set('Sinh_cha', 0x1000da1); + map.set('Sinh_ja', 0x1000da2); + map.set('Sinh_jha', 0x1000da3); + map.set('Sinh_nya', 0x1000da4); + map.set('Sinh_jnya', 0x1000da5); + map.set('Sinh_nja', 0x1000da6); + map.set('Sinh_tta', 0x1000da7); + map.set('Sinh_ttha', 0x1000da8); + map.set('Sinh_dda', 0x1000da9); + map.set('Sinh_ddha', 0x1000daa); + map.set('Sinh_nna', 0x1000dab); + map.set('Sinh_ndda', 0x1000dac); + map.set('Sinh_tha', 0x1000dad); + map.set('Sinh_thha', 0x1000dae); + map.set('Sinh_dha', 0x1000daf); + map.set('Sinh_dhha', 0x1000db0); + map.set('Sinh_na', 0x1000db1); + map.set('Sinh_ndha', 0x1000db3); + map.set('Sinh_pa', 0x1000db4); + map.set('Sinh_pha', 0x1000db5); + map.set('Sinh_ba', 0x1000db6); + map.set('Sinh_bha', 0x1000db7); + map.set('Sinh_ma', 0x1000db8); + map.set('Sinh_mba', 0x1000db9); + map.set('Sinh_ya', 0x1000dba); + map.set('Sinh_ra', 0x1000dbb); + map.set('Sinh_la', 0x1000dbd); + map.set('Sinh_va', 0x1000dc0); + map.set('Sinh_sha', 0x1000dc1); + map.set('Sinh_ssha', 0x1000dc2); + map.set('Sinh_sa', 0x1000dc3); + map.set('Sinh_ha', 0x1000dc4); + map.set('Sinh_lla', 0x1000dc5); + map.set('Sinh_fa', 0x1000dc6); + map.set('Sinh_al', 0x1000dca); + map.set('Sinh_aa2', 0x1000dcf); + map.set('Sinh_ae2', 0x1000dd0); + map.set('Sinh_aee2', 0x1000dd1); + map.set('Sinh_i2', 0x1000dd2); + map.set('Sinh_ii2', 0x1000dd3); + map.set('Sinh_u2', 0x1000dd4); + map.set('Sinh_uu2', 0x1000dd6); + map.set('Sinh_ru2', 0x1000dd8); + map.set('Sinh_e2', 0x1000dd9); + map.set('Sinh_ee2', 0x1000dda); + map.set('Sinh_ai2', 0x1000ddb); + map.set('Sinh_o2', 0x1000ddc); + map.set('Sinh_oo2', 0x1000ddd); + map.set('Sinh_au2', 0x1000dde); + map.set('Sinh_lu2', 0x1000ddf); + map.set('Sinh_ruu2', 0x1000df2); + map.set('Sinh_luu2', 0x1000df3); + map.set('Sinh_kunddaliya', 0x1000df4); + map.set('ModeLock', 0x1008ff01); + map.set('MonBrightnessUp', 0x1008ff02); + map.set('MonBrightnessDown', 0x1008ff03); + map.set('KbdLightOnOff', 0x1008ff04); + map.set('KbdBrightnessUp', 0x1008ff05); + map.set('KbdBrightnessDown', 0x1008ff06); + map.set('Standby', 0x1008ff10); + map.set('AudioLowerVolume', 0x1008ff11); + map.set('AudioMute', 0x1008ff12); + map.set('AudioRaiseVolume', 0x1008ff13); + map.set('AudioPlay', 0x1008ff14); + map.set('AudioStop', 0x1008ff15); + map.set('AudioPrev', 0x1008ff16); + map.set('AudioNext', 0x1008ff17); + map.set('HomePage', 0x1008ff18); + map.set('Mail', 0x1008ff19); + map.set('Start', 0x1008ff1a); + map.set('Search', 0x1008ff1b); + map.set('AudioRecord', 0x1008ff1c); + map.set('Calculator', 0x1008ff1d); + map.set('Memo', 0x1008ff1e); + map.set('ToDoList', 0x1008ff1f); + map.set('Calendar', 0x1008ff20); + map.set('PowerDown', 0x1008ff21); + map.set('ContrastAdjust', 0x1008ff22); + map.set('RockerUp', 0x1008ff23); + map.set('RockerDown', 0x1008ff24); + map.set('RockerEnter', 0x1008ff25); + map.set('Back', 0x1008ff26); + map.set('Forward', 0x1008ff27); + map.set('Stop', 0x1008ff28); + map.set('Refresh', 0x1008ff29); + map.set('PowerOff', 0x1008ff2a); + map.set('WakeUp', 0x1008ff2b); + map.set('Eject', 0x1008ff2c); + map.set('ScreenSaver', 0x1008ff2d); + map.set('WWW', 0x1008ff2e); + map.set('Sleep', 0x1008ff2f); + map.set('Favorites', 0x1008ff30); + map.set('AudioPause', 0x1008ff31); + map.set('AudioMedia', 0x1008ff32); + map.set('MyComputer', 0x1008ff33); + map.set('VendorHome', 0x1008ff34); + map.set('LightBulb', 0x1008ff35); + map.set('Shop', 0x1008ff36); + map.set('History', 0x1008ff37); + map.set('OpenURL', 0x1008ff38); + map.set('AddFavorite', 0x1008ff39); + map.set('HotLinks', 0x1008ff3a); + map.set('BrightnessAdjust', 0x1008ff3b); + map.set('Finance', 0x1008ff3c); + map.set('Community', 0x1008ff3d); + map.set('AudioRewind', 0x1008ff3e); + map.set('BackForward', 0x1008ff3f); + map.set('Launch0', 0x1008ff40); + map.set('Launch1', 0x1008ff41); + map.set('Launch2', 0x1008ff42); + map.set('Launch3', 0x1008ff43); + map.set('Launch4', 0x1008ff44); + map.set('Launch5', 0x1008ff45); + map.set('Launch6', 0x1008ff46); + map.set('Launch7', 0x1008ff47); + map.set('Launch8', 0x1008ff48); + map.set('Launch9', 0x1008ff49); + map.set('LaunchA', 0x1008ff4a); + map.set('LaunchB', 0x1008ff4b); + map.set('LaunchC', 0x1008ff4c); + map.set('LaunchD', 0x1008ff4d); + map.set('LaunchE', 0x1008ff4e); + map.set('LaunchF', 0x1008ff4f); + map.set('ApplicationLeft', 0x1008ff50); + map.set('ApplicationRight', 0x1008ff51); + map.set('Book', 0x1008ff52); + map.set('CD', 0x1008ff53); + map.set('WindowClear', 0x1008ff55); + map.set('Close', 0x1008ff56); + map.set('Copy', 0x1008ff57); + map.set('Cut', 0x1008ff58); + map.set('Display', 0x1008ff59); + map.set('DOS', 0x1008ff5a); + map.set('Documents', 0x1008ff5b); + map.set('Excel', 0x1008ff5c); + map.set('Explorer', 0x1008ff5d); + map.set('Game', 0x1008ff5e); + map.set('Go', 0x1008ff5f); + map.set('iTouch', 0x1008ff60); + map.set('LogOff', 0x1008ff61); + map.set('Market', 0x1008ff62); + map.set('Meeting', 0x1008ff63); + map.set('MenuKB', 0x1008ff65); + map.set('MenuPB', 0x1008ff66); + map.set('MySites', 0x1008ff67); + map.set('New', 0x1008ff68); + map.set('News', 0x1008ff69); + map.set('OfficeHome', 0x1008ff6a); + map.set('Open', 0x1008ff6b); + map.set('Option', 0x1008ff6c); + map.set('Paste', 0x1008ff6d); + map.set('Phone', 0x1008ff6e); + map.set('Reply', 0x1008ff72); + map.set('Reload', 0x1008ff73); + map.set('RotateWindows', 0x1008ff74); + map.set('RotationPB', 0x1008ff75); + map.set('RotationKB', 0x1008ff76); + map.set('Save', 0x1008ff77); + map.set('ScrollUp', 0x1008ff78); + map.set('ScrollDown', 0x1008ff79); + map.set('ScrollClick', 0x1008ff7a); + map.set('Send', 0x1008ff7b); + map.set('Spell', 0x1008ff7c); + map.set('SplitScreen', 0x1008ff7d); + map.set('Support', 0x1008ff7e); + map.set('TaskPane', 0x1008ff7f); + map.set('Terminal', 0x1008ff80); + map.set('Tools', 0x1008ff81); + map.set('Travel', 0x1008ff82); + map.set('UserPB', 0x1008ff84); + map.set('User1KB', 0x1008ff85); + map.set('User2KB', 0x1008ff86); + map.set('Video', 0x1008ff87); + map.set('WheelButton', 0x1008ff88); + map.set('Word', 0x1008ff89); + map.set('Xfer', 0x1008ff8a); + map.set('ZoomIn', 0x1008ff8b); + map.set('ZoomOut', 0x1008ff8c); + map.set('Away', 0x1008ff8d); + map.set('Messenger', 0x1008ff8e); + map.set('WebCam', 0x1008ff8f); + map.set('MailForward', 0x1008ff90); + map.set('Pictures', 0x1008ff91); + map.set('Music', 0x1008ff92); + map.set('Battery', 0x1008ff93); + map.set('Bluetooth', 0x1008ff94); + map.set('WLAN', 0x1008ff95); + map.set('UWB', 0x1008ff96); + map.set('AudioForward', 0x1008ff97); + map.set('AudioRepeat', 0x1008ff98); + map.set('AudioRandomPlay', 0x1008ff99); + map.set('Subtitle', 0x1008ff9a); + map.set('AudioCycleTrack', 0x1008ff9b); + map.set('CycleAngle', 0x1008ff9c); + map.set('FrameBack', 0x1008ff9d); + map.set('FrameForward', 0x1008ff9e); + map.set('Time', 0x1008ff9f); + map.set('SelectButton', 0x1008ffa0); + map.set('View', 0x1008ffa1); + map.set('TopMenu', 0x1008ffa2); + map.set('Red', 0x1008ffa3); + map.set('Green', 0x1008ffa4); + map.set('Yellow', 0x1008ffa5); + map.set('Blue', 0x1008ffa6); + map.set('Suspend', 0x1008ffa7); + map.set('Hibernate', 0x1008ffa8); + map.set('TouchpadToggle', 0x1008ffa9); + map.set('TouchpadOn', 0x1008ffb0); + map.set('TouchpadOff', 0x1008ffb1); + map.set('AudioMicMute', 0x1008ffb2); + map.set('Keyboard', 0x1008ffb3); + map.set('WWAN', 0x1008ffb4); + map.set('RFKill', 0x1008ffb5); + map.set('AudioPreset', 0x1008ffb6); + map.set('Switch_VT_1', 0x1008fe01); + map.set('Switch_VT_2', 0x1008fe02); + map.set('Switch_VT_3', 0x1008fe03); + map.set('Switch_VT_4', 0x1008fe04); + map.set('Switch_VT_5', 0x1008fe05); + map.set('Switch_VT_6', 0x1008fe06); + map.set('Switch_VT_7', 0x1008fe07); + map.set('Switch_VT_8', 0x1008fe08); + map.set('Switch_VT_9', 0x1008fe09); + map.set('Switch_VT_10', 0x1008fe0a); + map.set('Switch_VT_11', 0x1008fe0b); + map.set('Switch_VT_12', 0x1008fe0c); + map.set('Ungrab', 0x1008fe20); + map.set('ClearGrab', 0x1008fe21); + map.set('Next_VMode', 0x1008fe22); + map.set('Prev_VMode', 0x1008fe23); + map.set('LogWindowTree', 0x1008fe24); + map.set('LogGrabInfo', 0x1008fe25); + this.keycodeMap = map; + } } diff --git a/prefs.js b/prefs.js index 38a1c689..0f5f4b0e 100644 --- a/prefs.js +++ b/prefs.js @@ -7,7 +7,6 @@ import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; -import * as AcceleratorParse from './acceleratorparse.js'; import { WorkspaceSettings } from './workspace.js'; import * as KeybindingsPane from './prefsKeybinding.js'; import * as WinpropsPane from './winpropsPane.js'; @@ -24,12 +23,6 @@ export default class PaperWMPrefs extends ExtensionPreferences { Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ); - AcceleratorParse.initKeycodeMap(); - // cleanup on prefs window close request - window.connect('close-request', () => { - AcceleratorParse.destroyKeycodeMap(); - }); - let selectedWorkspace = null; try { const tempFile = Gio.File.new_for_path(GLib.get_tmp_dir()).get_child('paperwm.workspace'); diff --git a/prefsKeybinding.js b/prefsKeybinding.js index 904107d0..c06779a4 100644 --- a/prefsKeybinding.js +++ b/prefsKeybinding.js @@ -4,7 +4,7 @@ import GLib from 'gi://GLib'; import GObject from 'gi://GObject'; import Gtk from 'gi://Gtk'; -import * as Settings from './settings.js'; +import { AcceleratorParse } from './acceleratorparse.js'; const _ = s => s; @@ -189,15 +189,16 @@ const Combo = GObject.registerClass({ ), }, }, class Combo extends GObject.Object { - _init(params) { + _init(params, acceleratorParse) { super._init(params); + this.acceleratorParse = acceleratorParse; } get keycode() { if (this.disabled) { return 0; } else if (!this._keycode) { - let [ok, key, mask] = Settings.accelerator_parse(this.keystr); + let [ok, key, mask] = this.acceleratorParse.accelerator_parse(this.keystr); if (ok && key.length) { return key; @@ -290,9 +291,10 @@ const Keybinding = GObject.registerClass({ changed: {}, }, }, class Keybinding extends GObject.Object { - _init(params = {}, settings) { + _init(params = {}, settings, acceleratorParse) { super._init(params); this._settings = settings; + this.acceleratorParse = acceleratorParse; this._description = _(this._settings.settings_schema.get_key(this.action).get_summary()); this._combos = new Gio.ListStore(); @@ -368,7 +370,7 @@ const Keybinding = GObject.registerClass({ return; this.combos.remove(pos); if (this.combos.get_n_items() === 0) - this.combos.append(new Combo()); + this.combos.append(new Combo({}, this.acceleratorParse)); this._store(); } @@ -410,14 +412,14 @@ const Keybinding = GObject.registerClass({ .map(this._translateAboveTab) .map(keystr => { if (keystr !== '') - return Settings.accelerator_parse(keystr); + return this.acceleratorParse.accelerator_parse(keystr); else return [true, 0, 0]; }) - .map(([, keyval, mods]) => new Combo({ keyval, mods })); + .map(([, keyval, mods]) => new Combo({ keyval, mods }, this.acceleratorParse)); if (combos.length === 0) { - combos.push(new Combo()); + combos.push(new Combo({}, this.acceleratorParse)); } this.combos.splice(0, this.combos.get_n_items(), combos); @@ -456,9 +458,9 @@ export const KeybindingsModel = GObject.registerClass({ }, }, }, class KeybindingsModel extends GObject.Object { - _init(params = {}) { + _init(params = {}, acceleratorParse) { super._init(params); - + this.acceleratorParse = acceleratorParse; this._model = Gio.ListStore.new(Keybinding.$gtype); this._model.connect('items-changed', (_, position, removed, added) => { this.items_changed(position, removed, added); @@ -473,7 +475,7 @@ export const KeybindingsModel = GObject.registerClass({ this._actionToBinding = new Map(); } - setSettings(settings) { + init(settings) { this._settings = settings; this.load(); } @@ -513,7 +515,7 @@ export const KeybindingsModel = GObject.registerClass({ const binding = new Keybinding({ section, action, - }, this._settings); + }, this._settings, this.acceleratorParse); bindings.push(binding); this._actionToBinding.set(action, binding); } @@ -730,14 +732,15 @@ const ComboRow = GObject.registerClass({ // Backspace deletes if (!isModifier && modmask === 0 && keyvalLower === Gdk.KEY_BackSpace) { - this._updateKeybinding(new Combo()); + this._updateKeybinding(new Combo({}, this.acceleratorParse)); return Gdk.EVENT_STOP; } // Remove CapsLock modmask &= ~Gdk.ModifierType.LOCK_MASK; - this._updateKeybinding(new Combo({ keycode, keyval: keyvalLower, mods: modmask })); + this._updateKeybinding(new Combo({ keycode, keyval: keyvalLower, mods: modmask }, + this.acceleratorParse)); return Gdk.EVENT_STOP; } @@ -838,9 +841,9 @@ const KeybindingsRow = GObject.registerClass({ }, }, }, class KeybindingsRow extends Gtk.ListBoxRow { - _init(params = {}) { + _init(params = {}, acceleratorParse) { super._init(params); - + this.acceleratorParse = acceleratorParse; this._actionGroup = new Gio.SimpleActionGroup(); this.insert_action_group('keybinding', this._actionGroup); @@ -853,7 +856,8 @@ const KeybindingsRow = GObject.registerClass({ this._actionGroup.add_action(action); action = new Gio.SimpleAction({ name: 'add' }); - action.connect('activate', () => this.keybinding.add(new Combo({ placeholder: true }))); + action.connect('activate', () => this.keybinding.add(new Combo({ placeholder: true }, + this.acceleratorParse))); this._actionGroup.add_action(action); const gesture = Gtk.GestureClick.new(); @@ -975,7 +979,8 @@ export const KeybindingsPane = GObject.registerClass({ init(extension) { this._settings = extension.getSettings(KEYBINDINGS_KEY); - this._model = new KeybindingsModel(); + this.acceleratorParse = new AcceleratorParse(); + this._model = new KeybindingsModel({}, this.acceleratorParse); this._filter = new Gtk.StringFilter({ expression: Gtk.PropertyExpression.new(Keybinding.$gtype, null, 'description'), @@ -994,7 +999,7 @@ export const KeybindingsPane = GObject.registerClass({ this._expandedRow = null; // send settings to model (which processes and creates rows) - this._model.setSettings(this._settings); + this._model.init(this._settings); } _createHeader(row, before) { @@ -1015,7 +1020,7 @@ export const KeybindingsPane = GObject.registerClass({ } _createRow(keybinding) { - const row = new KeybindingsRow({ keybindings: this._model, keybinding }); + const row = new KeybindingsRow({ keybindings: this._model, keybinding }, this.acceleratorParse); row.connect('notify::expanded', row => this._onRowExpanded(row)); row.connect('collision-activated', (_, binding) => this._onCollisionActivated(binding)); return row; diff --git a/settings.js b/settings.js index 29066889..8d8739ba 100644 --- a/settings.js +++ b/settings.js @@ -1,7 +1,7 @@ import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; -import * as AcceleratorParse from './acceleratorparse.js'; +import { AcceleratorParse } from './acceleratorparse.js'; /** Settings utility shared between the running extension and the preference UI. @@ -17,11 +17,12 @@ const META_KEY_ABOVE_TAB = 0x2f7259c9; export let prefs; let gsettings, keybindSettings, _overriddingConflicts; +let acceleratorParse; export function enable(extension) { gsettings = extension.getSettings(); keybindSettings = extension.getSettings(KEYBINDINGS_KEY); - AcceleratorParse.initKeycodeMap(); + acceleratorParse = new AcceleratorParse(); _overriddingConflicts = false; prefs = {}; ['window-gap', 'vertical-margin', 'vertical-margin-bottom', 'horizontal-margin', @@ -57,8 +58,8 @@ export function enable(extension) { } export function disable() { - AcceleratorParse.destroyKeycodeMap(); gsettings = null; + acceleratorParse = null; _overriddingConflicts = null; prefs = null; conflictSettings = null; @@ -89,7 +90,7 @@ export function getConflictSettings() { // / Keybindings export function accelerator_parse(keystr) { - return AcceleratorParse.accelerator_parse(keystr); + return acceleratorParse.accelerator_parse(keystr); } /** From 89c7bee397edb7ba7b7a5c3f6cc16425395feebd Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Wed, 20 Sep 2023 09:16:48 +1000 Subject: [PATCH 35/50] Added note re `user.js` not working Gnome 45. Now supplying a `user.css` example in user config directory. --- config/user.css | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ config/user.js | 18 ++++++++----- extension.js | 23 +++++++++++----- stylesheet.css | 3 +++ 4 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 config/user.css diff --git a/config/user.css b/config/user.css new file mode 100644 index 00000000..b48283b6 --- /dev/null +++ b/config/user.css @@ -0,0 +1,71 @@ +/* +Users may override the default PaperWM styles to suit their preferences. +Added custom styling in this `user.css` file. + +`Disable` and then `enable` PaperWM extension to apply these styles +(users do NOT need to logout / login). + +DEFAULT STYLES ARE PROVIDED BELOW FOR REFERENCE: +/* + +/* +.topbar-no-background { + background-color: rgba(0, 0, 0, 0); +} + +.topbar-transparent-background { + background-color: rgba(0, 0, 0, 0.35); + box-shadow: none; +} + +.space-workspace-indicator { + padding: 0 10px 0 0; + background-color: transparent; + border-image: none; + background-image: none; + border: none; +} + +.space-focus-mode-icon { + icon-size: 16px; + padding: 0 18px 0 18px; + margin-left: 3px; + background-color: transparent; +} + +.focus-button-tooltip { + background-color: rgba(0, 0, 0, 0.8); + padding: 8px; + border-radius: 8px; + font-weight: 600; +} + +.workspace-icon-button { + -st-icon-style: symbolic; + border: none; + border-radius: 8px; + padding: 8px; +} + +.workspace-icon-button StIcon { + icon-size: 16px; +} + +.paperwm-selection { + border-radius: 12px 12px 0px 0px; +} + +.paperwm-minimap-selection { + border-radius: 8px; +} + +.paperwm-window-position-bar-backdrop { + background-color: rgba(0, 0, 0, 0.35); +} + +.paperwm-window-position-bar { + border: 0; + border-radius: 1px; +} + +*/ \ No newline at end of file diff --git a/config/user.js b/config/user.js index c27ae0f1..9d634295 100644 --- a/config/user.js +++ b/config/user.js @@ -1,12 +1,18 @@ -// -*- mode: gnome-shell -*- -const Extension = imports.misc.extensionUtils.getCurrentExtension(); -const Tiling = Extension.imports.tiling; -const Keybindings = Extension.imports.keybindings; +import * as Tiling from './tiling.js'; +import * as Keybindings from './keybindings.js'; -function enable() { +/** + * IMPORTANT: `user.js` is not working in Gnome 45 due to a change in Gnome + * that stops loading a custom module. We're investigating potential + * alternatives, but please be warned that this functionality might no + * longer be possible in Gnome 45. + * See https://github.com/paperwm/PaperWM/issues/576#issuecomment-1721315729 + */ + +export function enable() { // Runs when extension is enabled } -function disable() { +export function disable() { // Runs when extension is disabled } diff --git a/extension.js b/extension.js index d99de495..91164d2d 100644 --- a/extension.js +++ b/extension.js @@ -105,6 +105,10 @@ export default class PaperWM extends Extension { return this.getConfigDir().get_child("user.js").query_exists(null); } + hasUserStyleFile() { + return this.getConfigDir().get_child("user.css").query_exists(null); + } + /** * Update the metadata.json in user config dir to always keep it up to date. * We copy metadata.json to the config directory so gnome-shell-mode @@ -112,18 +116,27 @@ export default class PaperWM extends Extension { * that trips up the importer: Extension.imports. in * gnome-shell-mode crashes gnome-shell..) */ - updateUserConfigMetadata() { + updateUserConfigFiles() { if (!this.configDirExists()) { return; } + const configDir = this.getConfigDir(); try { - const configDir = this.getConfigDir(); const metadata = this.dir.get_child("metadata.json"); metadata.copy(configDir.get_child("metadata.json"), Gio.FileCopyFlags.OVERWRITE, null, null); } catch (error) { console.error('PaperWM', `could not update user config metadata.json: ${error}`); } + + if (!this.hasUserStyleFile()) { + try { + const user = this.dir.get_child("config/user.css"); + user.copy(configDir.get_child("user.css"), Gio.FileCopyFlags.NONE, null, null); + } catch (error) { + console.error('PaperWM', `could not update user config metadata.json: ${error}`); + } + } } installConfig() { @@ -132,10 +145,6 @@ export default class PaperWM extends Extension { if (!this.configDirExists()) { configDir.make_directory_with_parents(null); } - - // Copy the user.js template to the config directory - const user = this.dir.get_child("config/user.js"); - user.copy(configDir.get_child("user.js"), Gio.FileCopyFlags.NONE, null, null); } enableUserConfig() { @@ -155,7 +164,7 @@ export default class PaperWM extends Extension { } } - this.updateUserConfigMetadata(); + this.updateUserConfigFiles(); /* TODO: figure out something here fmuellner: diff --git a/stylesheet.css b/stylesheet.css index 687e6d37..0683c902 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,3 +1,6 @@ +/* +NOTE: please update `./config/users.css` with any new styles added here. +*/ .topbar-no-background { background-color: rgba(0, 0, 0, 0); } From b53b9cb6b97d7745211ffb4fd5f8ab9ad18503cf Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Wed, 20 Sep 2023 09:20:20 +1000 Subject: [PATCH 36/50] Updated ego generation script to include user.css example file. --- generate-extension-zip.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/generate-extension-zip.sh b/generate-extension-zip.sh index 240e656d..c1c3a947 100755 --- a/generate-extension-zip.sh +++ b/generate-extension-zip.sh @@ -7,6 +7,7 @@ zip -r paperwm@paperwm.github.com.zip \ stylesheet.css \ *.js \ config/user.js \ + config/user.css \ *.ui \ LICENSE \ schemas/gschemas.compiled \ From 6dbd24132de4d7f58ac30c1867eb17e87da54b2f Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Wed, 20 Sep 2023 09:30:27 +1000 Subject: [PATCH 37/50] Updated default vertical margins. --- schemas/gschemas.compiled | Bin 7525 -> 7525 bytes ...gnome.shell.extensions.paperwm.gschema.xml | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index f0b63c97e156020a693af57a8827209218edc0e8..5d291e537120014083e4e15065e59359f5615e45 100644 GIT binary patch delta 21 bcmaEA_0(!Zg9Ibj=0*u|Mj$m)@(eQoS>p#a delta 21 dcmaEA_0(!Zg9IbP=0*u|Mn=}nGbPV30{~e=2POaj diff --git a/schemas/org.gnome.shell.extensions.paperwm.gschema.xml b/schemas/org.gnome.shell.extensions.paperwm.gschema.xml index 32cc38f2..b3811057 100644 --- a/schemas/org.gnome.shell.extensions.paperwm.gschema.xml +++ b/schemas/org.gnome.shell.extensions.paperwm.gschema.xml @@ -317,12 +317,12 @@ - 5 + 10 Minimum margin from windows top edge - 0 + 10 Minimum margin from windows bottom edge From a4ac98c9261e6593642e638197d8893edd6bbe11 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sat, 23 Sep 2023 11:06:32 +1000 Subject: [PATCH 38/50] Update README.md with gnome-45 related stuff. --- README.md | 49 ++++++++++++++++++------------------------------- patches.js | 2 -- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index ed8a93b7..645f6c19 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,16 @@ # PaperWM # +> ### ⚠️ PaperWM [`develop`](https://github.com/paperwm/PaperWM/tree/develop) and [`release`](https://github.com/paperwm/PaperWM/tree/release) branches are now on Gnome 45. +> +> ### If you're using Gnome 42-44, please install via [extensions.gnome.org](https://extensions.gnome.org/extension/6099/paperwm/) OR use the [`gnome-44`](https://github.com/paperwm/PaperWM/tree/gnome-44) branch (see the [Installation](#installation) section for more information). + [![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://paperwm.zulipchat.com) PaperWM is a [Gnome Shell](https://wiki.gnome.org/Projects/GnomeShell) extension which provides scrollable tiling of windows and per monitor workspaces. It's inspired by paper notebooks and tiling window managers. -Supports Gnome Shell from 3.28 to 44 on X11 and wayland. +Can be installed on Gnome Shells from 3.28 to 45 on X11 and wayland. -_While PaperWM can be installed on a wide range of Gnome versions, new features aren't generally backported to versions NOT targeted for current support (see [Installation](#installation) section). Fixes may be backported on request (please submit a [new issue](https://github.com/paperwm/PaperWM/issues/new/choose) if you've identified a recent fix that should be backported and you can help with testing)._ +_While PaperWM can be installed on a wide range of Gnome versions, new features aren't generally backported to previous versions. Fixes may be backported on request (please submit a [new issue](https://github.com/paperwm/PaperWM/issues/new/choose) if you've identified a recent fix that should be backported and you can help with testing)._ While technically an [extension](https://wiki.gnome.org/Projects/GnomeShell/Extensions) it's to a large extent built on top of the Gnome desktop rather than merely extending it. @@ -22,7 +26,8 @@ We often hang out on [zulip](https://paperwm.zulipchat.com). Clone the repo and check out the branch supporting the Gnome Shell version you're running. -- 42-44 (targeted for current support): https://github.com/paperwm/PaperWM/tree/release +- 45 (current Gnome Shell release): https://github.com/paperwm/PaperWM/tree/release +- 42-44: https://github.com/paperwm/PaperWM/tree/gnome-44 - 40-41: https://github.com/paperwm/PaperWM/tree/gnome-40 - 3.28-3.38: https://github.com/paperwm/PaperWM/tree/gnome-3.38 @@ -59,7 +64,7 @@ Users are enouraged to submit [issues](https://github.com/paperwm/PaperWM/issues Most functionality is available using a mouse, eg. activating a window at the edge of the monitor by clicking on it. In wayland its possible to navigate with 3-finger swipes on the trackpad. But the primary focus is making an environment which works well with a keyboard. -All keybindings start with the Super modifier. On most keyboards it's the Windows key, on mac keyboards it's the Command key. It's possible to modify the keyboard layout so that Super is switched with Alt making all the keybindings easier to reach. This can be done through Gnome Tweaks under `Keybard & Mouse` ⟶ `Additional Layout Options` ⟶ `Alt/Win key behavior` ⟶ `Left Alt is swapped with Left Win`. +Most keybindings start with the Super modifier (by default), which is usually the Windows key, or on mac keyboards it's the Command key. It's possible to modify the keyboard layout so that Super is switched with Alt making all the keybindings easier to reach. This can be done through Gnome Tweaks under `Keybard & Mouse` ⟶ `Additional Layout Options` ⟶ `Alt/Win key behavior` ⟶ `Left Alt is swapped with Left Win`. Most keybindings will grab the keyboard while Super is held down, only switching focus when Super is released. Escape will abort the navigation taking you back to the previously active window. @@ -172,6 +177,10 @@ When the tiling is active SuperShiftTab selects ## User configuration & development ## +> ### ⚠️ Gnome 45 removed the ability to add external module files to the search path of extensions. Hence, modifications to PaperWM via `user.js` is [not currently available in Gnome 45](https://github.com/paperwm/PaperWM/issues/576#issuecomment-1721315729). +> +> `user.js` functionality is still available in PaperWM for previous Gnome shell versions. + A default user configuration, `user.js`, is created in `~/.config/paperwm/` with three functions `init`, `enable` and `disable`. `init` will run only once on startup, `enable` and `disable` will be run whenever extensions are being told to disable and enable themselves. You can also supply a custom `user.css` in `~/.config/paperwm/`. This user stylesheet can override the default styles of paperwm (e.g. from `~/.local/share/gnome-shell/extensions/paperwm@paperwm-redux.github.com/user.css` or `/usr/share/gnome-shell/extensions/paperwm@paperwm-redux.github.com/user.css`), gnome or even other extensions. The same rules as for CSS in the browser apply (i.e. CSS rules are additive). @@ -300,32 +309,6 @@ https://user-images.githubusercontent.com/30424662/211422647-79e64d56-5dbb-4054- The `wm_class` or `title` of a window can be found by using looking glass: AltF2 `lg` Return Go to the "Windows" section at the top right and find the window. X11 users can also use the `xprop` command line tool (`title` is referred as `WM_NAME` in `xprop`). The match of `wm_class` and `title` are with an OR condition; and in addition to a plain string matching, a constructed [`RegExp()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/RegExp) can be used to utilise regex matching. For example, e.g. `/.*terminal.*/i` would match on any value that contains the word "terminal" (case-insensitive). - - -Alternatively, you can also define winprops in the `user.js` configuration file. Below is a few examples of setting window properties for _Spotify_ and _Alacritty_. The below examples are best placed in the `init` part of `user.js`: - -```javascript - Tiling.defwinprop({ - wm_class: "Spotify", - title: "Window Title", - scratch_layer: true, - }); - - Tiling.defwinprop({ - wm_class: "firefox", - preferredWidth: "900px", - }); - - Tiling.defwinprop({ - wm_class: /alacritty/i, - preferredWidth: "50%", - }); -``` - -_Note1: `Winprops` defined in the PaperWM extension settings take precedence over `Winprops` defined using the `user.js` method._ - -_Note2: if you use the `user.js` method you will need to restart Gnome shell to have them take effect._ - ### Setting a default window property rule You can use the functionality defined in the [setting window specific properities](#setting-window-specific-properties) section to define a `default` window property rule that will be applied to all windows NOT matched by a more specific window property rule. @@ -338,6 +321,8 @@ This special operator is at a lower precedence, so more specific properties that ### New Window Handlers +> #### ⚠️ Gnome 45 removed the ability to add external module files to the search path of extensions. Hence, the below `user.js` functionality is not currently available in Gnome 45. + If opening a new application window with SuperReturn isn't doing exactly what you want, you can create custom functions to suit your needs. For example, you might want new emacs windows to open the current buffer by default, or have new terminals inherit the current directory. To implement this, you can modify `user.js` as below (see [User configuration & development](#user-configuration--development) section): ```javascript @@ -375,6 +360,8 @@ Due to limitations in the mutter keybinding API we need to steal some built in G #### User defined keybindings +> #### ⚠️ Gnome 45 removed the ability to add external module files to the search path of extensions. Hence, the below `user.js` and `examples/keybindings.js` functionality is not currently available in Gnome 45. + `Extension.imports.keybindings.bindkey(keystr, name, handler, options)` Option | Values | Meaning @@ -508,7 +495,7 @@ There's a few Gnome Shell settings which works poorly with PaperWM. Namely - `edge-tiling`: We don't support the native half tiled windows - `attach-modal-dialogs`: Attached modal dialogs can cause visual glitching -PaperWM manages these settings (disables them) during runtime. It will then restore these settings to their prior values (before PaperWM was enabled). +PaperWM manages these settings (disables them) during runtime. It will then restore these settings to their prior values when PaperWM is disabled. ## Recommended extensions ## diff --git a/patches.js b/patches.js index 883b5654..08460b93 100644 --- a/patches.js +++ b/patches.js @@ -354,8 +354,6 @@ export function setupActions() { actions.forEach(a => global.stage.remove_action(a)); } - - export function sortWindows(a, b) { let aw = a.metaWindow; let bw = b.metaWindow; From 2b26cdfe750a028ae355fa0ade2b4f3b36007403 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 24 Sep 2023 14:40:23 +1000 Subject: [PATCH 39/50] FIX: for `use-workspace-name` issue (that can cause PaperWM to not start).` --- topbar.js | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/topbar.js b/topbar.js index 9256f2db..f361bcfe 100644 --- a/topbar.js +++ b/topbar.js @@ -35,14 +35,12 @@ const colors = [ ]; export let menu, focusButton; -let path, openPrefs, orginalActivitiesText, screenSignals, signals, gsettings; +let path, openPrefs, screenSignals, signals, gsettings; export function enable (extension) { path = extension.path; openPrefs = () => extension.openPreferences(); gsettings = extension.getSettings(); - let label = Main.panel.statusArea.activities.first_child; - orginalActivitiesText = label.text; screenSignals = []; signals = new Utils.Signals(); @@ -51,15 +49,17 @@ export function enable (extension) { menu = new WorkspaceMenu(); focusButton = new FocusButton(); - Main.panel.addToStatusArea('WorkspaceMenu', menu, 0, 'left'); - Main.panel.addToStatusArea('FocusButton', focusButton, 1, 'left'); + Main.panel.addToStatusArea('WorkspaceMenu', menu, 1, 'left'); + Main.panel.addToStatusArea('FocusButton', focusButton, 2, 'left'); Tiling.spaces.forEach(s => { s.workspaceLabel.clutter_text.set_font_description(menu.label.clutter_text.font_description); }); + fixWorkspaceIndicator(); fixFocusModeIcon(); fixStyle(); + showWorkspaceMenu(Settings.prefs.use_workspace_name); screenSignals.push( workspaceManager.connect_after('workspace-switched', @@ -86,6 +86,10 @@ export function enable (extension) { spaces.showWindowPositionBarChanged(); }); + signals.connect(gsettings, 'changed::use-workspace-name', (settings, key) => { + showWorkspaceMenu(Settings.prefs.use_workspace_name); + }); + signals.connect(gsettings, 'changed::show-workspace-indicator', (settings, key) => { fixWorkspaceIndicator(); }); @@ -127,6 +131,17 @@ export function disable() { gsettings = null; } +export function showWorkspaceMenu(show = false) { + if (show) { + Main.panel.statusArea.activities.hide(); + menu.show(); + } + else { + menu.hide(); + Main.panel.statusArea.activities.show(); + } +} + export function createButton(icon_name, accessible_name) { return new St.Button({ reactive: true, @@ -671,10 +686,7 @@ export const WorkspaceMenu = GObject.registerClass( } setName(name) { - if (Settings.prefs.use_workspace_name) - this.label.text = name; - else - this.label.text = orginalActivitiesText; + this.label.text = name; } }); From efc51c0f5c7b601dd4cd6a322fa6c0245e7a64eb Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 24 Sep 2023 15:29:08 +1000 Subject: [PATCH 40/50] FIX: if hide workspace indicator `show-workspace-indicator` is false ==> show Gnome activities instead. --- topbar.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/topbar.js b/topbar.js index f361bcfe..9b6df0ce 100644 --- a/topbar.js +++ b/topbar.js @@ -750,8 +750,15 @@ export function fixTopBar() { } export function fixWorkspaceIndicator() { - Settings.prefs.show_workspace_indicator ? menu.show() : menu.hide(); - Tiling.spaces.forEach(s => s.showWorkspaceIndicator()); + const show = Settings.prefs.show_workspace_indicator; + if (show) { + Main.panel.statusArea.activities.hide(); + menu.show(); + } + else { + menu.hide(); + Main.panel.statusArea.activities.show(); + } } export function fixFocusModeIcon() { From 13bf8fb4220a94cb577ddc33163b58bf6c889341 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 24 Sep 2023 15:33:53 +1000 Subject: [PATCH 41/50] Remove `use-workspace-name` deprecated preference. --- README.md | 8 +------- schemas/gschemas.compiled | Bin 7525 -> 7485 bytes ...gnome.shell.extensions.paperwm.gschema.xml | 5 ----- settings.js | 4 ++-- tiling.js | 7 ------- topbar.js | 5 ----- 6 files changed, 3 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 645f6c19..eb0cc55f 100644 --- a/README.md +++ b/README.md @@ -277,15 +277,9 @@ Setting | Description | Reference --------|-------------|---------- show‑workspace‑indicator| Shows/hides the workspace indicator element in Topbar. | See [The workspace stack & monitors](#the-workspace-stack--monitors). -Setting | Description | Input Type | Default value ---------|-------------|------------|-------------- -use‑workspace‑name | Use PaperWM workspace name in workspace indicator in the TopBar. Setting to false uses the gnome default name (i.e. `Activities`). | _Boolean_ | `true` - -_Note: this does not disable the workspace indicator, but simply makes it looks like default gnome `Activities` button. To show/hide the workspace indicator element use setting_ `show-workspace-indicator`. - __Example:__ ``` -dconf write /org/gnome/shell/extensions/paperwm/use-workspace-name false +dconf write /org/gnome/shell/extensions/paperwm/show-workspace-indicator false ``` Setting | Description | Input Type | Default value diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 5d291e537120014083e4e15065e59359f5615e45..cf4774df0a1a2e281cdfad85cc0ca293cbe671ba 100644 GIT binary patch delta 1873 zcmZuyU1(cn82&nw*`KUQyCrG<+N^Cb(HtlCLaAh}W0Q&wlriSSi=HH>$ze%OIOil? z$F}H2LGXvH2XQcD7yeYoVCh6QkV)q#bQjxtGwIEspo0ny2Aw!{qR(?|x*;BTc%JY1 z{@(BJJ-3H14cF`8L7xy|@6}5!LWqkYA(CQD`~+@-7QhX7fNo$b;063Z&pIOD-bc^}y^flQqOg4(uEE%u&Crb8C#qr;JO+H0 zy7L`<>K^#xU0It2f1@HEgHKiWc{x(ohE@HfC8YqP)8r>4K?s|m4$!f!kG z7g#~vjfz$99l(jD{Ed%Vh*!m3a2ZRRKX$x>KD86=4}(tw{jpO;j$><10Ph;0r}k;| zsXg#lz_)>Owbko7D_G#lxMxn_?2#XD(5I#!1;>ClcMetPQ*VPm3f=>JbXacCrw+r< zgNwkQ+l#N$r)K+i!5;uW#8)rVudxtB#h2g);7+>3te|G3^WX*Gy^kHs^r>C&m%(iT z9Mh*)ex^^|0lx?Q3UJ|zT@m`!+|hCHF<@bKWH)_k96?RgAwCB-?GM#hLEVlH4e&+a z%-7j8eQG!SMeq_3dp~Zsr``g81^f#zd-=Q_5Opj3`{2KTwd~?s9EX|<^8^uO5a&N~ z^?=NZ3oy2#VhMZ`aLza!^r?9n?}C2?-cc62=~H*YZ^e_^20SS58>COoK;vKunEU>z zCHmAHXAHa-c%wLHY{vX{fdh@htN<^BrmO5g9e`g4p9Efh@|k<|skx;MFyD1m(M>fY z7o?)B=hTvv)=X0?q9Hy$QxR7aTB$H485vzRGkFPZG<2$}$|Rn3Je{yceGx0|8yd)K zx_U$_nHz)g*8Dp{R+*411yizKi+C9|l8F7-9|JQv@C~~FCJO{5_~@A!qJRVF0&vOg zB+~|F;=m5tiK7+V2{e;RA2jD>(y(71m`Me94m*N*m}#Ca%Vr)t6MVvo1!9~-SgnDG z74t`}R48ig2}Wo9{V~{aBVpvVNohjMR1B%8Wfe)yXeIW**Mcpu&iTR#E`^(=D~74* zigZYsN~@);VGpogP)j*uhjpUmIgc@^>4%K6oKcJ&?8uZFEU1Plgprxb6cj11sJXl; z8KzP;g!Q4n&w3CHTK-Vyfk_ODcye-iV}Jj1iW?_aR7+}6F5~dzf`Vy=?C;8mh-VWR zrmSlioL^ivth4@ahnvwW*_QC+fy?c^XfT)mt3cg(x-O7 k_kg{?C*H5@_S9(KE20o_VA_8?#}3p?LC=Fz*3EGJA7fB($N&HU delta 1891 zcmZ{kUuYav7{zbmrl!p%n>0=KZ{nuO;%v)}c$`X$Oyi;;nBtP^DnmVNn#rP!+UG zlU2;=n~;w~&x05DJ#~*c{chx+K(B)DrS_tMhaNjuI#hl)UdjX6CF zoq;Zt@UxL#d7T3b@QoN)hGqgnc)Mcr%;{T^PeI=TZ@=eRV@~fyJ_}t1bJwr^!koSq z`5N>N_~YMh@Y>-6qs-}<4~I&q4ky)v zVRt3ycVWPQj)R&OA$S9NAzpH``|vmCdi(iD^xTY%IEevYw=cq+o-20{ngEwi{dkKx zJy&7~dIAiU@{1M+c;apr=ro9(mE3~p>oH*#dJ)vTDqAU2u~S)DE693LHH(@$hO32erdpp3rPUE-G-t~rdTP{?^Lko!$AqLg zX9JOE+!KEP2;v#lvPVr-9@EW}mZ79nc|<@HSOP2GKzhh5jidtYP zX#(1}$ zK!Don't show scratch windows in the overview - - true - Replace the Activities text with the current workspace name - - false Enable pressure barriers at the monitor edges diff --git a/settings.js b/settings.js index 8d8739ba..cc93ab5a 100644 --- a/settings.js +++ b/settings.js @@ -26,8 +26,8 @@ export function enable(extension) { _overriddingConflicts = false; 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', 'swipe-friction', + 'workspace-colors', 'default-background', 'animation-time', 'pressure-barrier', + 'default-show-top-bar', 'swipe-sensitivity', 'swipe-friction', 'cycle-width-steps', 'cycle-height-steps', 'minimap-scale', 'winprops', 'show-workspace-indicator', 'show-window-position-bar', 'show-focus-mode-icon', 'disable-topbar-styling', 'default-focus-mode', 'gesture-enabled', diff --git a/tiling.js b/tiling.js index 6effe0b6..09a61bf9 100644 --- a/tiling.js +++ b/tiling.js @@ -1242,8 +1242,6 @@ export class Space extends Array { this.updateName(); this.updateShowTopBar(); this.signals.connect(this.settings, 'changed::name', this.updateName.bind(this)); - this.signals.connect(gsettings, 'changed::use-workspace-name', - this.updateName.bind(this)); this.signals.connect(this.settings, 'changed::color', this.updateColor.bind(this)); this.signals.connect(this.settings, 'changed::background', @@ -1340,11 +1338,6 @@ border-radius: ${borderWidth}px; } updateName() { - if (Settings.prefs.use_workspace_name) { - this.workspaceLabel.show(); - } else { - this.workspaceLabel.hide(); - } let name = workspaceSettings.getWorkspaceName(this.settings, this.index); Meta.prefs_change_workspace_name(this.index, name); this.workspaceLabel.text = name; diff --git a/topbar.js b/topbar.js index 9b6df0ce..aa3d4eec 100644 --- a/topbar.js +++ b/topbar.js @@ -59,7 +59,6 @@ export function enable (extension) { fixWorkspaceIndicator(); fixFocusModeIcon(); fixStyle(); - showWorkspaceMenu(Settings.prefs.use_workspace_name); screenSignals.push( workspaceManager.connect_after('workspace-switched', @@ -86,10 +85,6 @@ export function enable (extension) { spaces.showWindowPositionBarChanged(); }); - signals.connect(gsettings, 'changed::use-workspace-name', (settings, key) => { - showWorkspaceMenu(Settings.prefs.use_workspace_name); - }); - signals.connect(gsettings, 'changed::show-workspace-indicator', (settings, key) => { fixWorkspaceIndicator(); }); From 41c378406b236b0449ef600a82e0808cdb6f0ce4 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 24 Sep 2023 15:51:21 +1000 Subject: [PATCH 42/50] Workspace indicator mouse scrolling now sequence. --- tiling.js | 10 +++++----- topbar.js | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tiling.js b/tiling.js index 09a61bf9..bd238240 100644 --- a/tiling.js +++ b/tiling.js @@ -2154,7 +2154,7 @@ export const Spaces = class Spaces extends Map { toSpace.monitor === fromSpace.monitor) { // Only start an animation if we're moving between workspaces on the // same monitor - this._initWorkspaceSequence(); + this.initWorkspaceSequence(); } else { this.selectedSpace.setMonitor(this.selectedSpace.monitor); } @@ -2251,7 +2251,7 @@ export const Spaces = class Spaces extends Map { }); } - _initWorkspaceSequence() { + initWorkspaceSequence() { if (inPreview) { return; } @@ -2283,7 +2283,7 @@ export const Spaces = class Spaces extends Map { let monitorSpaces = this._getOrderedSpaces(currentSpace.monitor); if (!inPreview) { - this._initWorkspaceSequence(); + this.initWorkspaceSequence(); } let from = monitorSpaces.indexOf(this.selectedSpace); @@ -2292,7 +2292,7 @@ export const Spaces = class Spaces extends Map { if (move && this.selectedSpace.selectedWindow) { const navigator = Navigator.getNavigator(); - if (navigator._moving == null || + if (navigator._moving === null || (Array.isArray(navigator._moving) && navigator._moving.length === 0)) { takeWindow(this.selectedSpace.selectedWindow, this.selectedSpace, @@ -2330,7 +2330,7 @@ export const Spaces = class Spaces extends Map { let space_y; if (to === 0) { space_y = padding + (space.height + padding) * (i - to) * scale; - } else if (to == last) { + } else if (to === last) { space_y = (center * 2 - padding) + (space.height + padding) * (i - to) * scale; } else { space_y = center + (space.height + padding) * (i - to) * scale; diff --git a/topbar.js b/topbar.js index aa3d4eec..2c0bd7cb 100644 --- a/topbar.js +++ b/topbar.js @@ -528,7 +528,7 @@ export const WorkspaceMenu = GObject.registerClass( if (!this._navigator) { this.state = 'SCROLL'; this._navigator = Navigator.getNavigator(); - Tiling.spaces.initWorkspaceStack(); + Tiling.spaces.initWorkspaceSequence(); this._enterbox = new Clutter.Actor({ reactive: true }); Main.uiGroup.add_actor(this._enterbox); this._enterbox.set_position(panelBox.x, panelBox.y + panelBox.height + 20); @@ -551,10 +551,10 @@ export const WorkspaceMenu = GObject.registerClass( } if (direction === Clutter.ScrollDirection.DOWN) { - Tiling.spaces.selectStackSpace(Meta.MotionDirection.DOWN); + Tiling.spaces.selectSequenceSpace(Meta.MotionDirection.DOWN); } if (direction === Clutter.ScrollDirection.UP) { - Tiling.spaces.selectStackSpace(Meta.MotionDirection.UP); + Tiling.spaces.selectSequenceSpace(Meta.MotionDirection.UP); } } @@ -586,7 +586,7 @@ export const WorkspaceMenu = GObject.registerClass( ) { dy = 0; v = 0.1; - spaces.selectStackSpace(Meta.MotionDirection.UP, false, mode); + spaces.selectSequenceSpace(Meta.MotionDirection.UP); this.selected = spaces.selectedSpace; Easer.removeEase(this.selected.actor); Easer.addEase(this.selected.actor, @@ -598,7 +598,7 @@ export const WorkspaceMenu = GObject.registerClass( ) { dy = 0; v = 0.1; - spaces.selectStackSpace(Meta.MotionDirection.DOWN, false, mode); + spaces.selectSequenceSpace(Meta.MotionDirection.DOWN); this.selected = spaces.selectedSpace; Easer.removeEase(this.selected.actor); Easer.addEase(this.selected.actor, @@ -639,11 +639,11 @@ export const WorkspaceMenu = GObject.registerClass( this._navigator.finish(); return; } else if (y > downEdge) { - spaces.selectStackSpace(Meta.MotionDirection.DOWN, false, mode); + spaces.selectSequenceSpace(Meta.MotionDirection.DOWN); this.selected = spaces.selectedSpace; } else { - spaces.selectStackSpace(Meta.MotionDirection.DOWN); - spaces.selectStackSpace(Meta.MotionDirection.UP); + spaces.selectSequenceSpace(Meta.MotionDirection.DOWN); + spaces.selectSequenceSpace(Meta.MotionDirection.UP); } } else { this.time = t; From e6b9e54de5fe0cb13b10119aec6443d989e3c45a Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 24 Sep 2023 15:57:20 +1000 Subject: [PATCH 43/50] FIX: for FocusIcon on spaces. --- topbar.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/topbar.js b/topbar.js index 2c0bd7cb..a32df404 100644 --- a/topbar.js +++ b/topbar.js @@ -35,9 +35,8 @@ const colors = [ ]; export let menu, focusButton; -let path, openPrefs, screenSignals, signals, gsettings; +let openPrefs, screenSignals, signals, gsettings; export function enable (extension) { - path = extension.path; openPrefs = () => extension.openPreferences(); gsettings = extension.getSettings(); @@ -121,7 +120,6 @@ export function disable() { screenSignals.forEach(id => workspaceManager.disconnect(id)); screenSignals = []; panelBox.scale_y = 1; - path = null; openPrefs = null; gsettings = null; } @@ -276,8 +274,9 @@ export const FocusIcon = GObject.registerClass( this.tooltip_x_point = tooltip_x_point; // read in focus icons from resources folder - this.gIconDefault = Gio.icon_new_for_string(`${path}/resources/focus-mode-default-symbolic.svg`); - this.gIconCenter = Gio.icon_new_for_string(`${path}/resources/focus-mode-center-symbolic.svg`); + const pather = relativePath => GLib.uri_resolve_relative(import.meta.url, relativePath, GLib.UriFlags.NONE); + this.gIconDefault = Gio.icon_new_for_string(pather('./resources/focus-mode-default-symbolic.svg')); + this.gIconCenter = Gio.icon_new_for_string(pather('./resources/focus-mode-center-symbolic.svg')); this._initToolTip(); this.setMode(); From aef81ca0ad3ac5aa107051eb39836fd8d539d253 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Sun, 24 Sep 2023 18:41:07 +1000 Subject: [PATCH 44/50] FIX: moving windows in workspace sequence (regression). --- tiling.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tiling.js b/tiling.js index bd238240..4ef9bba5 100644 --- a/tiling.js +++ b/tiling.js @@ -2292,7 +2292,7 @@ export const Spaces = class Spaces extends Map { if (move && this.selectedSpace.selectedWindow) { const navigator = Navigator.getNavigator(); - if (navigator._moving === null || + if (navigator._moving == null || (Array.isArray(navigator._moving) && navigator._moving.length === 0)) { takeWindow(this.selectedSpace.selectedWindow, this.selectedSpace, From 42c821f14662ea5a18594aaace98377339c27330 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Fri, 29 Sep 2023 22:12:20 +1000 Subject: [PATCH 45/50] FIX #608. --- patches.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/patches.js b/patches.js index 08460b93..cb8fb7a3 100644 --- a/patches.js +++ b/patches.js @@ -7,6 +7,7 @@ import * as Workspace from 'resource:///org/gnome/shell/ui/workspace.js'; import * as WorkspaceThumbnail from 'resource:///org/gnome/shell/ui/workspaceThumbnail.js'; import * as WorkspaceAnimation from 'resource:///org/gnome/shell/ui/workspaceAnimation.js'; import * as WindowManager from 'resource:///org/gnome/shell/ui/windowManager.js'; +import * as WindowPreview from 'resource:///org/gnome/shell/ui/windowPreview.js'; import * as Params from 'resource:///org/gnome/shell/misc/params.js'; import { Utils, Tiling, Scratch } from './imports.js'; @@ -131,7 +132,8 @@ export function setupOverrides() { registerOverridePrototype(WorkspaceAnimation.WorkspaceAnimationController, '_prepareWorkspaceSwitch', function (workspaceIndices) { - const saved = getSavedPrototype(WorkspaceAnimation.WorkspaceAnimationController, '_prepareWorkspaceSwitch'); + const saved = getSavedPrototype(WorkspaceAnimation.WorkspaceAnimationController, + '_prepareWorkspaceSwitch'); // hide selection during workspace switch Tiling.spaces.forEach(s => s.hideSelection()); saved.call(this, workspaceIndices); @@ -139,7 +141,8 @@ export function setupOverrides() { registerOverridePrototype(WorkspaceAnimation.WorkspaceAnimationController, '_finishWorkspaceSwitch', function (switchData) { - const saved = getSavedPrototype(WorkspaceAnimation.WorkspaceAnimationController, '_finishWorkspaceSwitch'); + const saved = getSavedPrototype(WorkspaceAnimation.WorkspaceAnimationController, + '_finishWorkspaceSwitch'); // ensure selection is shown after workspaces swtching Tiling.spaces.forEach(s => s.showSelection()); saved.call(this, switchData); @@ -211,6 +214,22 @@ export function setupOverrides() { return onSpace && onMonitor; }); + /** + * Resolve issue where window that is set to minimise-on-close should be removed + * from tiling (stick) before closing. See https://github.com/paperwm/PaperWM/issues/608. + */ + registerOverridePrototype(WindowPreview.WindowPreview, '_deleteAll', function() { + const windows = this.window_container.layout_manager.get_windows(); + + // Delete all windows, starting from the bottom-most (most-modal) one + for (const window of windows.reverse()) { + window.stick(); + window.delete(global.get_current_time()); + } + + this._closeRequested = true; + }); + /** * Always show workspace thumbnails in overview if more than one workspace. * See original function at: From 9ace145b050d8190466418578b8971e28a508bc6 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Tue, 3 Oct 2023 00:17:12 +1100 Subject: [PATCH 46/50] FIXES to minimap sizing and label placement. --- minimap.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/minimap.js b/minimap.js index dab90e8c..d9fd5267 100644 --- a/minimap.js +++ b/minimap.js @@ -44,7 +44,6 @@ var Minimap = class Minimap extends Array { this.clip = clip; let container = new St.Widget({ name: 'minimap-container' }); this.container = container; - container.height = Math.round(space.height * Settings.prefs.minimap_scale) - Settings.prefs.window_gap; actor.add_actor(highlight); actor.add_actor(label); @@ -149,7 +148,6 @@ var Minimap = class Minimap extends Array { container.meta_window = mw; container.add_actor(clone); this.container.add_actor(container); - this._allocateClone(container); return container; } @@ -160,8 +158,7 @@ var Minimap = class Minimap extends Array { let frame = meta_window.get_frame_rect(); let scale = Settings.prefs.minimap_scale; clone.set_size(buffer.width * scale, buffer.height * scale - Settings.prefs.window_gap); - clone.set_position((buffer.x - frame.x) * scale, - (buffer.y - frame.y) * scale); + clone.set_position((buffer.x - frame.x) * scale, (buffer.y - frame.y) * scale); container.set_size(frame.width * scale, frame.height * scale); } @@ -237,18 +234,14 @@ var Minimap = class Minimap extends Array { highlight.set_size(Math.round(selected.width + gap), Math.round(Math.min(selected.height, this.clip.height + gap) + gap)); - let x = highlight.x + - (highlight.width - label.width) / 2; + let x = highlight.x + (highlight.width - label.width) / 2; if (x + label.width > clip.x + clip.width) x = clip.x + clip.width - label.width + 5; if (x < 0) x = clip.x - 5; - label.set_position( - Math.round(x), - clip.y + Math.round(clip.height + 20)); - - this.actor.height = this.label.y + this.label.height + 12; + label.set_position(Math.round(x), this.clip.y + this.clip.height + 8); + this.actor.height = this.clip.y + this.clip.height + 40; } destroy() { From 825d2a575c1762aa9b6d1b91f0452d48b1d2b8ad Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Wed, 4 Oct 2023 15:50:11 +1100 Subject: [PATCH 47/50] FIXES: removed "opacity" actor hack for opening animations. Essentially removed opening "scale" animation which results in a cleaner/snappier opening of apps (while avoiding the clipping issue). --- stylesheet.css | 2 +- tiling.js | 11 ++--------- topbar.js | 4 ++-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/stylesheet.css b/stylesheet.css index 687e6d37..c63c2dff 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,4 +1,4 @@ -.topbar-no-background { +.background-clear { background-color: rgba(0, 0, 0, 0); } diff --git a/tiling.js b/tiling.js index eaaf02da..01bab7fc 100644 --- a/tiling.js +++ b/tiling.js @@ -3113,9 +3113,9 @@ function insertWindow(metaWindow, { existing }) { const space = spaces.spaceOfWindow(metaWindow); const connectSizeChanged = tiled => { - if (tiled) + if (tiled) { animateWindow(metaWindow); - actor.opacity = 255; + } metaWindow.unmapped && signals.connect(metaWindow, 'size-changed', resizeHandler); delete metaWindow.unmapped; }; @@ -3220,15 +3220,10 @@ function insertWindow(metaWindow, { existing }) { space.layout(); if (!existing) { - actor.opacity = 0; - actor.visible = false; clone.x = clone.targetX; clone.y = clone.targetY; - clone.set_scale(0, 1); space.hideSelection(); Easer.addEase(clone, { - scale_x: 1, - scale_y: 1, time: Settings.prefs.animation_time, onStopped: () => { connectSizeChanged(true); @@ -3608,9 +3603,7 @@ function showHandler(actor) { if (!metaWindow.clone.get_parent() && !metaWindow.unmapped) return; - // HACK: use opacity instead of hidden on new windows if (metaWindow.unmapped) { - actor.opacity = 0; return; } diff --git a/topbar.js b/topbar.js index c1e771c2..bad72508 100644 --- a/topbar.js +++ b/topbar.js @@ -681,7 +681,7 @@ function setNoBackgroundStyle() { return; } removeStyles(); - Main.panel.add_style_class_name('topbar-no-background'); + Main.panel.add_style_class_name('background-clear'); } function setTransparentStyle() { @@ -693,7 +693,7 @@ function setTransparentStyle() { } function removeStyles() { - ['topbar-no-background', 'topbar-transparent-background'].forEach(s => { + ['background-clear', 'topbar-transparent-background'].forEach(s => { Main.panel.remove_style_class_name(s); }); } From 1b3a9cc5b883de8b3f336762988ddf54279f19c0 Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Wed, 4 Oct 2023 15:56:22 +1100 Subject: [PATCH 48/50] Removed opening animation easer. --- tiling.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tiling.js b/tiling.js index 01bab7fc..76b9a6f4 100644 --- a/tiling.js +++ b/tiling.js @@ -3222,15 +3222,8 @@ function insertWindow(metaWindow, { existing }) { if (!existing) { clone.x = clone.targetX; clone.y = clone.targetY; - space.hideSelection(); - Easer.addEase(clone, { - time: Settings.prefs.animation_time, - onStopped: () => { - connectSizeChanged(true); - space.layout(); - space.showSelection(); - }, - }); + connectSizeChanged(true); + space.layout(); } else { animateWindow(metaWindow); } From 0164abbef5a48c1904397b70e5094f4ad271393b Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Wed, 4 Oct 2023 23:09:05 +1100 Subject: [PATCH 49/50] Added option to use Gnome workspace indicator pill. --- Settings.ui | 38 ++++++++++++++++++++++++++++++++++++++ prefs.js | 6 ++++++ 2 files changed, 44 insertions(+) diff --git a/Settings.ui b/Settings.ui index 85796466..acbbb5e5 100644 --- a/Settings.ui +++ b/Settings.ui @@ -810,6 +810,7 @@ False + Enables PaperWM's Window Position Bar (colored bar overlay on the Gnome topbar) 1 Enable Window Position Bar 0 @@ -831,6 +832,43 @@ + + + False + False + + + False + Replaces PaperWM's workspace indicator with the Gnome Workspace Indicator Pill (introduced in Gnome 45) + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Enable Gnome workspace indicator pill + 0 + + 0 + 0 + + + + + + + 1 + 0 + + + + + + + diff --git a/prefs.js b/prefs.js index dd2a69c7..73b678b0 100644 --- a/prefs.js +++ b/prefs.js @@ -233,6 +233,12 @@ class SettingsWidget { this._settings.set_boolean('show-window-position-bar', state); }); + const enableGnomePill = this.builder.get_object('use-gnome-pill'); + enableGnomePill.active = !this._settings.get_boolean('show-workspace-indicator'); + enableGnomePill.connect('state-set', (obj, state) => { + this._settings.set_boolean('show-workspace-indicator', !state); + }); + // Workspaces const defaultBackgroundSwitch = this.builder.get_object('use-default-background'); From ca62ca5f93d45cd86618a1e9e703971818f1fbdc Mon Sep 17 00:00:00 2001 From: Jay Ta'ala Date: Wed, 4 Oct 2023 23:19:06 +1100 Subject: [PATCH 50/50] Moved prefs "Settings" box to the top of general tab (most used settings). --- Settings.ui | 466 ++++++++++++++++++++++++++-------------------------- 1 file changed, 233 insertions(+), 233 deletions(-) diff --git a/Settings.ui b/Settings.ui index acbbb5e5..79fcfd3f 100644 --- a/Settings.ui +++ b/Settings.ui @@ -93,7 +93,7 @@ start True - Gaps and margins + Settings @@ -108,22 +108,24 @@ - + False False - + False + Sets the duration of PaperWM animated transitions (e.g. switching windows, workspaces etc.). Lower values result in faster transitions. 12 12 6 6 32 - + False 1 - Gap between windows + Animation / transition time (seconds) + 1 0 0 @@ -132,12 +134,13 @@ - - 2 - 2 - window_gap - 1 + + 3 + 3 + animation_time_adjustment 1 + 2 + 1 if-valid 1 @@ -150,14 +153,13 @@ - + False False - - + False - The minimum margin to the left and right monitor edge + Controls the "size" of mini-map tiles (as shown during window navigation keybinds), as compared to their actual window size (e.g. "15" corresponds to a mini-map tile size being approximately 15% of the actual window size) 12 12 6 @@ -167,7 +169,8 @@ False 1 - Horizontal margin + Mini-map scale (%) <i>(0 hides Mini-map)</i> + 1 0 0 @@ -176,11 +179,10 @@ - + 2 2 - 0 - horizontal_margin + minimap_scale 1 1 if-valid @@ -195,12 +197,13 @@ - + False False - + False + Controls the "size" of tiling edge window previews, as compared to their actual window size (e.g. "15" corresponds to an edge preview size being approximately 15% of the actual window size) 12 12 6 @@ -210,7 +213,8 @@ False 1 - Top margin + Tiling edge preview scale (%) <i>(0 hides edge previews)</i> + 1 0 0 @@ -219,11 +223,10 @@ - + 2 2 - 0 - vertical_margin + edge_preview_scale 1 1 if-valid @@ -244,6 +247,7 @@ False + Controls the "size" of window switcher previews (e.g. Super+Tab switcher), as compared to their actual window size (e.g. "15" corresponds to an edge preview size being approximately 15% of the actual window size) 12 12 6 @@ -253,7 +257,8 @@ False 1 - Bottom margin + Window-switcher preview scale (%) + 1 0 0 @@ -262,11 +267,10 @@ - + 2 2 - 0 - vertical_margin_bottom + window_switcher_preview_scale 1 1 if-valid @@ -284,7 +288,49 @@ False False - Semicolon separated values of "useful window widths" that will be cycled through. Values types can be either percentage (of available screen width), e.g. "50%" or pixel values, e.g. "500px". Mixed value types are not supported. + + + False + 12 + 12 + 6 + 6 + 32 + + + False + 1 + Show scratch windows in overview + 0 + + 0 + 0 + + + + + + False + 0 + + Always + Only + Never + + + 1 + 0 + + + + + + + + + + False + False False @@ -296,8 +342,9 @@ False + Enables PaperWM's Window Position Bar (colored bar overlay on the Gnome topbar) 1 - Useful window widths + Enable Window Position Bar 0 0 @@ -306,29 +353,12 @@ - + 1 0 - - - 8 - reset - Resets width values to the default PaperWM width values - - - - - 24 - 24 - - 2 - 0 - - - - + @@ -338,10 +368,10 @@ False False - Semicolon separated values of "useful window heights" that will be cycled through. Values types can be either percentage (of available screen width), e.g. "50%" or pixel values, e.g. "500px". Mixed value types are not supported. False + Replaces PaperWM's workspace indicator with the Gnome Workspace Indicator Pill (introduced in Gnome 45) 12 12 6 @@ -351,7 +381,7 @@ False 1 - Useful window heights + Enable Gnome Workspace Indicator Pill 0 0 @@ -360,29 +390,12 @@ - + 1 0 - - - 8 - reset - Resets height values to the default PaperWM height values - - - - - 24 - 24 - - 1 - 0 - - - - + @@ -394,7 +407,7 @@ start True - Three-finger swipes + Gaps and margins @@ -409,23 +422,22 @@ - + False False - + False 12 12 6 6 - 12 32 - + False 1 - Horizontal sensitivity + Gap between windows 0 0 @@ -434,14 +446,10 @@ - - True - True + 2 2 - 0 - horizontal-sensitivity-adjustment - 1 + window_gap 1 1 if-valid @@ -451,56 +459,29 @@ - - - False - 1 - Horizontal friction - 0 - - 0 - 1 - - - - - - 2 - 2 - 0,0 - horizontal-friction-adjustment - 1 - 1 - 1 - if-valid - - 1 - 1 - - - - + False False + - + False + The minimum margin to the left and right monitor edge 12 12 6 6 - 12 32 False 1 - Vertical sensitivity + Horizontal margin 0 0 @@ -509,12 +490,11 @@ - + 2 2 0 - vertical-sensitivity-adjustment - 1 + horizontal_margin 1 1 if-valid @@ -524,31 +504,46 @@ + + + + + + + False + False + + + False + 12 + 12 + 6 + 6 + 32 False 1 - Vertical friction + Top margin 0 0 - 1 + 0 - + 2 2 - 0,0 - vertical-friction-adjustment - 1 + 0 + vertical_margin 1 1 if-valid 1 - 1 + 0 @@ -556,25 +551,6 @@ - - - - - start - True - Settings - - - - - - - - False - none - False @@ -582,7 +558,6 @@ False - Sets the duration of PaperWM animated transitions (e.g. switching windows, workspaces etc.). Lower values result in faster transitions. 12 12 6 @@ -592,8 +567,7 @@ False 1 - Animation / transition time (seconds) - 1 + Bottom margin 0 0 @@ -602,13 +576,13 @@ - - 3 - 3 - animation_time_adjustment - 1 - 2 + + 2 + 2 + 0 + vertical_margin_bottom 1 + 1 if-valid 1 @@ -624,10 +598,10 @@ False False + Semicolon separated values of "useful window widths" that will be cycled through. Values types can be either percentage (of available screen width), e.g. "50%" or pixel values, e.g. "500px". Mixed value types are not supported. False - Controls the "size" of mini-map tiles (as shown during window navigation keybinds), as compared to their actual window size (e.g. "15" corresponds to a mini-map tile size being approximately 15% of the actual window size) 12 12 6 @@ -637,8 +611,7 @@ False 1 - Mini-map scale (%) <i>(0 hides Mini-map)</i> - 1 + Useful window widths 0 0 @@ -647,18 +620,29 @@ - - 2 - 2 - minimap_scale - 1 - 1 - if-valid + 1 0 - + + + 8 + reset + Resets width values to the default PaperWM width values + + + + + 24 + 24 + + 2 + 0 + + + + @@ -668,10 +652,10 @@ False False + Semicolon separated values of "useful window heights" that will be cycled through. Values types can be either percentage (of available screen width), e.g. "50%" or pixel values, e.g. "500px". Mixed value types are not supported. False - Controls the "size" of tiling edge window previews, as compared to their actual window size (e.g. "15" corresponds to an edge preview size being approximately 15% of the actual window size) 12 12 6 @@ -681,8 +665,7 @@ False 1 - Tiling edge preview scale (%) <i>(0 hides edge previews)</i> - 1 + Useful window heights 0 0 @@ -691,42 +674,71 @@ - - 2 - 2 - edge_preview_scale - 1 - 1 - if-valid + 1 0 - + + + 8 + reset + Resets height values to the default PaperWM height values + + + + + 24 + 24 + + 1 + 0 + + + + + + + + + start + True + Three-finger swipes + + + + + + + + False + none + False False - + False - Controls the "size" of window switcher previews (e.g. Super+Tab switcher), as compared to their actual window size (e.g. "15" corresponds to an edge preview size being approximately 15% of the actual window size) 12 12 6 6 + 12 32 - + False 1 - Window-switcher preview scale (%) - 1 + Horizontal sensitivity 0 0 @@ -735,10 +747,14 @@ - + + True + True 2 2 - window_switcher_preview_scale + 0 + horizontal-sensitivity-adjustment + 1 1 1 if-valid @@ -748,46 +764,31 @@ - - - - - - - False - False - - - False - 12 - 12 - 6 - 6 - 32 - + False 1 - Show scratch windows in overview + Horizontal friction 0 0 - 0 + 1 - - False - 0 - - Always - Only - Never - + + 2 + 2 + 0,0 + horizontal-friction-adjustment + 1 + 1 + 1 + if-valid 1 - 0 + 1 @@ -806,13 +807,13 @@ 12 6 6 + 12 32 False - Enables PaperWM's Window Position Bar (colored bar overlay on the Gnome topbar) 1 - Enable Window Position Bar + Vertical sensitivity 0 0 @@ -821,47 +822,46 @@ - + + 2 + 2 + 0 + vertical-sensitivity-adjustment + 1 + 1 + 1 + if-valid 1 0 - - - - - - - False - False - - - False - Replaces PaperWM's workspace indicator with the Gnome Workspace Indicator Pill (introduced in Gnome 45) - 12 - 12 - 6 - 6 - 32 False 1 - Enable Gnome workspace indicator pill + Vertical friction 0 0 - 0 + 1 - + + 2 + 2 + 0,0 + vertical-friction-adjustment + 1 + 1 + 1 + if-valid 1 - 0 + 1