diff options
Diffstat (limited to 'extensions/vertical-workspaces/util.js')
-rw-r--r-- | extensions/vertical-workspaces/util.js | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/extensions/vertical-workspaces/util.js b/extensions/vertical-workspaces/util.js new file mode 100644 index 0000000..e0a625b --- /dev/null +++ b/extensions/vertical-workspaces/util.js @@ -0,0 +1,270 @@ +/** + * Vertical Workspaces + * util.js + * + * @author GdH <G-dH@github.com> + * @copyright 2022 - 2023 + * @license GPL-3.0 + * + */ + +'use strict'; + +const Gi = imports._gi; +const { Shell, Meta } = imports.gi; + +const Config = imports.misc.config; +const Main = imports.ui.main; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +var shellVersion = parseFloat(Config.PACKAGE_VERSION); + +var Overrides = class { + constructor() { + this._overrides = {}; + this._injections = {}; + } + + addOverride(name, prototype, overrideList) { + this._overrides[name] = { + originals: this.overrideProto(prototype, overrideList), + prototype, + }; + } + + removeOverride(name) { + const override = this._overrides[name]; + if (!override) + return false; + + this.overrideProto(override.prototype, override.originals); + this._overrides[name] = undefined; + return true; + } + + /* + className.prototype + .injections.funcName1 + .funcName2 + */ + addInjection(className, prototype, injections) { + if (!this._injections[className]) + this._injections[className] = { + prototype, + injections: {}, + }; + + for (let name in injections) { + this._injections[className].injections[name] = { + original: this.injectToFunction(prototype, name, injections[name]), + } + } + } + + removeInjection(className, funcName) { + if (this._injections[className]) return false; + const prototype = this._injections[className].prototype; + + const injection = this._injections[className].injections[funcName]; + if (!injection) return false; + + prototype[funcName] = injection.original; + this._injections[funcName] = undefined; + return true; + } + + removeAll() { + for (let name in this._overrides) { + this.removeOverride(name); + this._overrides[name] = undefined; + } + + for (let className in this._injections) { + const injt = this._injections[className]; + const prototype = injt.prototype; + for (let funcName in injt.injections) { + prototype[funcName] = injt.injections[funcName].original; + } + this._injections[className] = undefined; + } + } + + hookVfunc(proto, symbol, func) { + proto[Gi.hook_up_vfunc_symbol](symbol, func); + } + + overrideProto(proto, overrides) { + const backup = {}; + + for (let symbol in overrides) { + if (symbol.startsWith('after_')) { + const actualSymbol = symbol.slice('after_'.length); + const fn = proto[actualSymbol]; + const afterFn = overrides[symbol] + proto[actualSymbol] = function() { + const args = Array.prototype.slice.call(arguments); + const res = fn.apply(this, args); + afterFn.apply(this, args); + return res; + }; + backup[actualSymbol] = fn; + } + else { + backup[symbol] = proto[symbol]; + if (symbol.startsWith('vfunc')) { + if (shellVersion < 42) { + this.hookVfunc(proto, symbol.slice(6), overrides[symbol]); + } else { + this.hookVfunc(proto[Gi.gobject_prototype_symbol], symbol.slice(6), overrides[symbol]); + } + } + else { + proto[symbol] = overrides[symbol]; + } + } + } + return backup; + } + + injectToFunction(parent, name, func) { + let origin = parent[name]; + parent[name] = function() { + let ret; + ret = origin.apply(this, arguments); + func.apply(this, arguments); + return ret; + } + + return origin; + } +} + +//------- Common functions ----------------------------------------------------------------------- + +function getOverviewTranslations(opt, dash, tmbBox, searchEntryBin) { + //const tmbBox = Main.overview._overview._controls._thumbnailsBox; + let searchTranslation_y = 0; + if (searchEntryBin.visible) { + const offset = (dash.visible && (!opt.DASH_VERTICAL ? dash.height + 12 : 0)) + + (opt.WS_TMB_TOP ? tmbBox.height + 12 : 0); + searchTranslation_y = - searchEntryBin.height - offset - 30; + } + + let tmbTranslation_x = 0; + let tmbTranslation_y = 0; + let offset; + if (tmbBox.visible) { + switch (opt.WS_TMB_POSITION) { + case 3: // left + offset = 10 + ((dash?.visible && opt.DASH_LEFT) ? dash.width : 0); + tmbTranslation_x = - tmbBox.width - offset; + tmbTranslation_y = 0; + break; + case 1: // right + offset = 10 + ((dash?.visible && opt.DASH_RIGHT) ? dash.width : 0); + tmbTranslation_x = tmbBox.width + offset; + tmbTranslation_y = 0; + break; + case 0: // top + offset = 10 + ((dash?.visible && opt.DASH_TOP) ? dash.height : 0) + Main.panel.height; + tmbTranslation_x = 0; + tmbTranslation_y = - tmbBox.height - offset; + break; + case 2: // bottom + offset = 10 + ((dash?.visible && opt.DASH_BOTTOM) ? dash.height : 0) + Main.panel.height; // just for case the panel is at bottom + tmbTranslation_x = 0; + tmbTranslation_y = tmbBox.height + offset; + break; + } + } + + let dashTranslation_x = 0; + let dashTranslation_y = 0; + let position = opt.DASH_POSITION; + // if DtD replaced the original Dash, read its position + if (dashIsDashToDock()) { + position = dash._position; + } + if (dash?.visible) { + switch (position) { + case 0: // top + dashTranslation_x = 0; + dashTranslation_y = - dash.height - dash.margin_bottom - Main.panel.height; + break; + case 1: // right + dashTranslation_x = dash.width; + dashTranslation_y = 0; + break; + case 2: // bottom + dashTranslation_x = 0; + dashTranslation_y = dash.height + dash.margin_bottom + Main.panel.height; + break; + case 3: // left + dashTranslation_x = - dash.width; + dashTranslation_y = 0; + break; + } + } + + return [tmbTranslation_x, tmbTranslation_y, dashTranslation_x, dashTranslation_y, searchTranslation_y]; +} + +function openPreferences() { + const windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null); + let tracker = Shell.WindowTracker.get_default(); + let metaWin, isVW = null; + + for (let win of windows) { + const app = tracker.get_window_app(win); + if (win.get_title().includes(Me.metadata.name) && app.get_name() === 'Extensions') { + // this is our existing window + metaWin = win; + isVW = true; + break; + } else if (win.wm_class.includes('org.gnome.Shell.Extensions')) { + // this is prefs window of another extension + metaWin = win; + isVW = false; + } + } + + if (metaWin && !isVW) { + // other prefs window blocks opening another prefs window, so close it + metaWin.delete(global.get_current_time()); + } else if (metaWin && isVW) { + // if prefs window already exist, move it to the current WS and activate it + metaWin.change_workspace(global.workspace_manager.get_active_workspace()); + metaWin.activate(global.get_current_time()); + } + + if (!metaWin || (metaWin && !isVW)) { + try { + Main.extensionManager.openExtensionPrefs(Me.metadata.uuid, '', {}); + } catch (e) { + log(e); + } + } +} + +function activateSearchProvider(prefix = '') { + const searchEntry = Main.overview.searchEntry; + if (!searchEntry.get_text() || !searchEntry.get_text().startsWith(prefix)) { + prefix = _(prefix + ' '); + const position = prefix.length; + searchEntry.set_text(prefix); + searchEntry.get_first_child().set_cursor_position(position); + searchEntry.get_first_child().set_selection(position, position); + } else { + searchEntry.set_text(''); + } +} + +function dashNotDefault() { + return Main.overview.dash !== Main.overview._overview._controls.layoutManager._dash; +} + +function dashIsDashToDock() { + return Main.overview.dash._isHorizontal !== undefined; +} |