mirror of
https://github.com/morgan9e/dash-to-panel
synced 2026-04-14 00:04:17 +09:00
Format code
This commit is contained in:
930
overview.js
930
overview.js
@@ -16,503 +16,537 @@
|
||||
*
|
||||
* Credits:
|
||||
* This file is based on code from the Dash to Dock extension by micheleg
|
||||
*
|
||||
*
|
||||
* Some code was also adapted from the upstream Gnome Shell source code.
|
||||
*/
|
||||
|
||||
import * as Intellihide from './intellihide.js';
|
||||
import * as Utils from './utils.js';
|
||||
import * as Intellihide from './intellihide.js'
|
||||
import * as Utils from './utils.js'
|
||||
|
||||
import Clutter from 'gi://Clutter';
|
||||
import Gio from 'gi://Gio';
|
||||
import Shell from 'gi://Shell';
|
||||
import St from 'gi://St';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import * as WindowManager from 'resource:///org/gnome/shell/ui/windowManager.js';
|
||||
import {WindowPreview} from 'resource:///org/gnome/shell/ui/windowPreview.js';
|
||||
import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||
import {SETTINGS} from './extension.js';
|
||||
import Clutter from 'gi://Clutter'
|
||||
import Gio from 'gi://Gio'
|
||||
import Shell from 'gi://Shell'
|
||||
import St from 'gi://St'
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
|
||||
import * as WindowManager from 'resource:///org/gnome/shell/ui/windowManager.js'
|
||||
import { WindowPreview } from 'resource:///org/gnome/shell/ui/windowPreview.js'
|
||||
import { InjectionManager } from 'resource:///org/gnome/shell/extensions/extension.js'
|
||||
import { SETTINGS } from './extension.js'
|
||||
|
||||
const GS_HOTKEYS_KEY = 'switch-to-application-';
|
||||
const GS_HOTKEYS_KEY = 'switch-to-application-'
|
||||
|
||||
// When the dash is shown, workspace window preview bottom labels go over it (default
|
||||
// gnome-shell behavior), but when the extension hides the dash, leave some space
|
||||
// so those labels don't go over a bottom panel
|
||||
const LABEL_MARGIN = 60;
|
||||
const LABEL_MARGIN = 60
|
||||
|
||||
//timeout names
|
||||
const T1 = 'swipeEndTimeout';
|
||||
const T2 = 'numberOverlayTimeout';
|
||||
const T1 = 'swipeEndTimeout'
|
||||
const T2 = 'numberOverlayTimeout'
|
||||
|
||||
export const Overview = class {
|
||||
constructor() {
|
||||
this._injectionManager = new InjectionManager()
|
||||
this._numHotkeys = 10
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this._injectionManager = new InjectionManager();
|
||||
this._numHotkeys = 10;
|
||||
enable(primaryPanel) {
|
||||
this._panel = primaryPanel
|
||||
this.taskbar = primaryPanel.taskbar
|
||||
|
||||
this._injectionsHandler = new Utils.InjectionsHandler()
|
||||
this._signalsHandler = new Utils.GlobalSignalsHandler()
|
||||
this._timeoutsHandler = new Utils.TimeoutsHandler()
|
||||
|
||||
this._optionalWorkspaceIsolation()
|
||||
this._optionalHotKeys()
|
||||
this._optionalNumberOverlay()
|
||||
this._optionalClickToExit()
|
||||
|
||||
this.toggleDash()
|
||||
this._adaptAlloc()
|
||||
|
||||
this._signalsHandler.add([
|
||||
SETTINGS,
|
||||
['changed::stockgs-keep-dash', 'changed::panel-sizes'],
|
||||
() => this.toggleDash(),
|
||||
])
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._signalsHandler.destroy()
|
||||
this._injectionsHandler.destroy()
|
||||
this._timeoutsHandler.destroy()
|
||||
this._injectionManager.clear()
|
||||
|
||||
this.toggleDash(true)
|
||||
|
||||
// Remove key bindings
|
||||
this._disableHotKeys()
|
||||
this._disableExtraShortcut()
|
||||
this._disableClickToExit()
|
||||
}
|
||||
|
||||
toggleDash(visible) {
|
||||
if (visible === undefined) {
|
||||
visible = SETTINGS.get_boolean('stockgs-keep-dash')
|
||||
}
|
||||
|
||||
enable (primaryPanel) {
|
||||
this._panel = primaryPanel;
|
||||
this.taskbar = primaryPanel.taskbar;
|
||||
let visibilityFunc = visible ? 'show' : 'hide'
|
||||
let height = visible ? -1 : LABEL_MARGIN * Utils.getScaleFactor()
|
||||
let overviewControls = Main.overview._overview._controls
|
||||
|
||||
this._injectionsHandler = new Utils.InjectionsHandler();
|
||||
this._signalsHandler = new Utils.GlobalSignalsHandler();
|
||||
this._timeoutsHandler = new Utils.TimeoutsHandler();
|
||||
overviewControls.dash[visibilityFunc]()
|
||||
overviewControls.dash.set_height(height)
|
||||
}
|
||||
|
||||
this._optionalWorkspaceIsolation();
|
||||
this._optionalHotKeys();
|
||||
this._optionalNumberOverlay();
|
||||
this._optionalClickToExit();
|
||||
_adaptAlloc() {
|
||||
let overviewControls = Main.overview._overview._controls
|
||||
|
||||
this.toggleDash();
|
||||
this._adaptAlloc();
|
||||
this._injectionManager.overrideMethod(
|
||||
Object.getPrototypeOf(overviewControls),
|
||||
'vfunc_allocate',
|
||||
(originalAllocate) => (box) => {
|
||||
let focusedPanel = this._panel.panelManager.focusedMonitorPanel
|
||||
|
||||
this._signalsHandler.add([
|
||||
SETTINGS,
|
||||
[
|
||||
'changed::stockgs-keep-dash',
|
||||
'changed::panel-sizes'
|
||||
],
|
||||
() => this.toggleDash()
|
||||
]);
|
||||
}
|
||||
if (focusedPanel) {
|
||||
let position = focusedPanel.geom.position
|
||||
let isBottom = position == St.Side.BOTTOM
|
||||
|
||||
disable() {
|
||||
this._signalsHandler.destroy();
|
||||
this._injectionsHandler.destroy();
|
||||
this._timeoutsHandler.destroy();
|
||||
this._injectionManager.clear();
|
||||
if (focusedPanel.intellihide?.enabled) {
|
||||
// Panel intellihide is enabled (struts aren't taken into account on overview allocation),
|
||||
// dynamically modify the overview box to follow the reveal/hide animation
|
||||
let { transitioning, finalState, progress } =
|
||||
overviewControls._stateAdjustment.getStateTransitionParams()
|
||||
let size =
|
||||
focusedPanel.geom[focusedPanel.checkIfVertical() ? 'w' : 'h'] *
|
||||
(transitioning
|
||||
? Math.abs((finalState != 0 ? 0 : 1) - progress)
|
||||
: 1)
|
||||
|
||||
this.toggleDash(true);
|
||||
|
||||
// Remove key bindings
|
||||
this._disableHotKeys();
|
||||
this._disableExtraShortcut();
|
||||
this._disableClickToExit();
|
||||
}
|
||||
|
||||
toggleDash(visible) {
|
||||
if (visible === undefined) {
|
||||
visible = SETTINGS.get_boolean('stockgs-keep-dash');
|
||||
if (isBottom || position == St.Side.RIGHT)
|
||||
box[focusedPanel.fixedCoord.c2] -= size
|
||||
else box[focusedPanel.fixedCoord.c1] += size
|
||||
} else if (isBottom)
|
||||
// The default overview allocation takes into account external
|
||||
// struts, everywhere but the bottom where the dash is usually fixed anyway.
|
||||
// If there is a bottom panel under the dash location, give it some space here
|
||||
box.y2 -= focusedPanel.geom.h
|
||||
}
|
||||
|
||||
let visibilityFunc = visible ? 'show' : 'hide';
|
||||
let height = visible ? -1 : LABEL_MARGIN * Utils.getScaleFactor();
|
||||
let overviewControls = Main.overview._overview._controls;
|
||||
originalAllocate.call(overviewControls, box)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
overviewControls.dash[visibilityFunc]();
|
||||
overviewControls.dash.set_height(height);
|
||||
/**
|
||||
* Isolate overview to open new windows for inactive apps
|
||||
*/
|
||||
_optionalWorkspaceIsolation() {
|
||||
let label = 'optionalWorkspaceIsolation'
|
||||
|
||||
let enable = () => {
|
||||
this._injectionsHandler.removeWithLabel(label)
|
||||
|
||||
this._injectionsHandler.addWithLabel(label, [
|
||||
Shell.App.prototype,
|
||||
'activate',
|
||||
IsolatedOverview,
|
||||
])
|
||||
|
||||
this._signalsHandler.removeWithLabel(label)
|
||||
|
||||
this._signalsHandler.addWithLabel(label, [
|
||||
global.window_manager,
|
||||
'switch-workspace',
|
||||
() =>
|
||||
this._panel.panelManager.allPanels.forEach((p) =>
|
||||
p.taskbar.handleIsolatedWorkspaceSwitch(),
|
||||
),
|
||||
])
|
||||
}
|
||||
|
||||
_adaptAlloc() {
|
||||
let overviewControls = Main.overview._overview._controls
|
||||
let disable = () => {
|
||||
this._signalsHandler.removeWithLabel(label)
|
||||
this._injectionsHandler.removeWithLabel(label)
|
||||
}
|
||||
|
||||
this._injectionManager.overrideMethod(Object.getPrototypeOf(overviewControls), 'vfunc_allocate',
|
||||
(originalAllocate) =>
|
||||
(box) => {
|
||||
let focusedPanel = this._panel.panelManager.focusedMonitorPanel
|
||||
|
||||
if (focusedPanel) {
|
||||
let position = focusedPanel.geom.position
|
||||
let isBottom = position == St.Side.BOTTOM
|
||||
function IsolatedOverview() {
|
||||
// These lines take care of Nautilus for icons on Desktop
|
||||
let activeWorkspace =
|
||||
Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace()
|
||||
let windows = this.get_windows().filter(
|
||||
(w) => w.get_workspace().index() == activeWorkspace.index(),
|
||||
)
|
||||
|
||||
if (focusedPanel.intellihide?.enabled) {
|
||||
// Panel intellihide is enabled (struts aren't taken into account on overview allocation),
|
||||
// dynamically modify the overview box to follow the reveal/hide animation
|
||||
let { transitioning, finalState, progress } = overviewControls._stateAdjustment.getStateTransitionParams()
|
||||
let size = focusedPanel.geom[focusedPanel.checkIfVertical() ? 'w' : 'h'] *
|
||||
(transitioning ? Math.abs((finalState != 0 ? 0 : 1) - progress) : 1)
|
||||
if (
|
||||
windows.length > 0 &&
|
||||
(!(windows.length == 1 && windows[0].skip_taskbar) ||
|
||||
this.is_on_workspace(activeWorkspace))
|
||||
)
|
||||
return Main.activateWindow(windows[0])
|
||||
|
||||
if (isBottom || position == St.Side.RIGHT)
|
||||
box[focusedPanel.fixedCoord.c2] -= size
|
||||
else
|
||||
box[focusedPanel.fixedCoord.c1] += size
|
||||
} else if (isBottom)
|
||||
// The default overview allocation takes into account external
|
||||
// struts, everywhere but the bottom where the dash is usually fixed anyway.
|
||||
// If there is a bottom panel under the dash location, give it some space here
|
||||
box.y2 -= focusedPanel.geom.h
|
||||
}
|
||||
|
||||
originalAllocate.call(overviewControls, box)
|
||||
return this.open_new_window(-1)
|
||||
}
|
||||
|
||||
this._signalsHandler.add([
|
||||
SETTINGS,
|
||||
'changed::isolate-workspaces',
|
||||
() => {
|
||||
this._panel.panelManager.allPanels.forEach((p) =>
|
||||
p.taskbar.resetAppIcons(),
|
||||
)
|
||||
|
||||
if (SETTINGS.get_boolean('isolate-workspaces')) enable()
|
||||
else disable()
|
||||
},
|
||||
])
|
||||
|
||||
if (SETTINGS.get_boolean('isolate-workspaces')) enable()
|
||||
}
|
||||
|
||||
// Hotkeys
|
||||
_activateApp(appIndex, modifiers) {
|
||||
let seenApps = {}
|
||||
let apps = []
|
||||
|
||||
this.taskbar._getAppIcons().forEach((appIcon) => {
|
||||
if (!seenApps[appIcon.app] || this.taskbar.allowSplitApps) {
|
||||
apps.push(appIcon)
|
||||
}
|
||||
|
||||
seenApps[appIcon.app] = (seenApps[appIcon.app] || 0) + 1
|
||||
})
|
||||
|
||||
this._showOverlay()
|
||||
|
||||
if (appIndex < apps.length) {
|
||||
let appIcon = apps[appIndex]
|
||||
let seenAppCount = seenApps[appIcon.app]
|
||||
let windowCount =
|
||||
appIcon.window || appIcon._hotkeysCycle
|
||||
? seenAppCount
|
||||
: appIcon._nWindows
|
||||
|
||||
if (
|
||||
SETTINGS.get_boolean('shortcut-previews') &&
|
||||
windowCount > 1 &&
|
||||
!(
|
||||
modifiers &
|
||||
~(Clutter.ModifierType.MOD1_MASK | Clutter.ModifierType.SUPER_MASK)
|
||||
)
|
||||
) {
|
||||
//ignore the alt (MOD1_MASK) and super key (SUPER_MASK)
|
||||
if (
|
||||
this._hotkeyPreviewCycleInfo &&
|
||||
this._hotkeyPreviewCycleInfo.appIcon != appIcon
|
||||
) {
|
||||
this._endHotkeyPreviewCycle()
|
||||
}
|
||||
|
||||
if (!this._hotkeyPreviewCycleInfo) {
|
||||
this._hotkeyPreviewCycleInfo = {
|
||||
appIcon: appIcon,
|
||||
currentWindow: appIcon.window,
|
||||
keyFocusOutId: appIcon.connect('key-focus-out', () =>
|
||||
appIcon.grab_key_focus(),
|
||||
),
|
||||
capturedEventId: global.stage.connect(
|
||||
'captured-event',
|
||||
(actor, e) => {
|
||||
if (
|
||||
e.type() == Clutter.EventType.KEY_RELEASE &&
|
||||
e.get_key_symbol() == (Clutter.KEY_Super_L || Clutter.Super_L)
|
||||
) {
|
||||
this._endHotkeyPreviewCycle(true)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Isolate overview to open new windows for inactive apps
|
||||
*/
|
||||
_optionalWorkspaceIsolation() {
|
||||
let label = 'optionalWorkspaceIsolation';
|
||||
|
||||
let enable = () => {
|
||||
this._injectionsHandler.removeWithLabel(label);
|
||||
return Clutter.EVENT_PROPAGATE
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
this._injectionsHandler.addWithLabel(label, [
|
||||
Shell.App.prototype,
|
||||
'activate',
|
||||
IsolatedOverview
|
||||
]);
|
||||
|
||||
this._signalsHandler.removeWithLabel(label);
|
||||
|
||||
this._signalsHandler.addWithLabel(label, [
|
||||
global.window_manager,
|
||||
'switch-workspace',
|
||||
() => this._panel.panelManager.allPanels.forEach(p => p.taskbar.handleIsolatedWorkspaceSwitch())
|
||||
]);
|
||||
appIcon._hotkeysCycle = appIcon.window
|
||||
appIcon.window = null
|
||||
appIcon._previewMenu.open(appIcon, true)
|
||||
appIcon.grab_key_focus()
|
||||
}
|
||||
|
||||
let disable = () => {
|
||||
this._signalsHandler.removeWithLabel(label);
|
||||
this._injectionsHandler.removeWithLabel(label);
|
||||
appIcon._previewMenu.focusNext()
|
||||
} else {
|
||||
// Activate with button = 1, i.e. same as left click
|
||||
let button = 1
|
||||
this._endHotkeyPreviewCycle()
|
||||
appIcon.activate(button, modifiers, !this.taskbar.allowSplitApps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_endHotkeyPreviewCycle(focusWindow) {
|
||||
if (this._hotkeyPreviewCycleInfo) {
|
||||
global.stage.disconnect(this._hotkeyPreviewCycleInfo.capturedEventId)
|
||||
this._hotkeyPreviewCycleInfo.appIcon.disconnect(
|
||||
this._hotkeyPreviewCycleInfo.keyFocusOutId,
|
||||
)
|
||||
|
||||
if (focusWindow) {
|
||||
this._hotkeyPreviewCycleInfo.appIcon._previewMenu.activateFocused()
|
||||
} else this._hotkeyPreviewCycleInfo.appIcon._previewMenu.close()
|
||||
|
||||
this._hotkeyPreviewCycleInfo.appIcon.window =
|
||||
this._hotkeyPreviewCycleInfo.currentWindow
|
||||
delete this._hotkeyPreviewCycleInfo.appIcon._hotkeysCycle
|
||||
this._hotkeyPreviewCycleInfo = 0
|
||||
}
|
||||
}
|
||||
|
||||
_optionalHotKeys() {
|
||||
this._hotKeysEnabled = false
|
||||
if (SETTINGS.get_boolean('hot-keys')) this._enableHotKeys()
|
||||
|
||||
this._signalsHandler.add([
|
||||
SETTINGS,
|
||||
'changed::hot-keys',
|
||||
() => {
|
||||
if (SETTINGS.get_boolean('hot-keys')) this._enableHotKeys()
|
||||
else this._disableHotKeys()
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
_resetHotkeys() {
|
||||
this._disableHotKeys()
|
||||
this._enableHotKeys()
|
||||
}
|
||||
|
||||
_enableHotKeys() {
|
||||
if (this._hotKeysEnabled) return
|
||||
|
||||
//3.32 introduced app hotkeys, disable them to prevent conflicts
|
||||
if (Main.wm._switchToApplication) {
|
||||
for (let i = 1; i < 10; ++i) {
|
||||
Utils.removeKeybinding(GS_HOTKEYS_KEY + i)
|
||||
}
|
||||
}
|
||||
|
||||
// Setup keyboard bindings for taskbar elements
|
||||
let shortcutNumKeys = SETTINGS.get_string('shortcut-num-keys')
|
||||
let bothNumKeys = shortcutNumKeys == 'BOTH'
|
||||
let keys = []
|
||||
let prefixModifiers = Clutter.ModifierType.SUPER_MASK
|
||||
|
||||
if (SETTINGS.get_string('hotkey-prefix-text') == 'SuperAlt')
|
||||
prefixModifiers |= Clutter.ModifierType.MOD1_MASK
|
||||
|
||||
if (bothNumKeys || shortcutNumKeys == 'NUM_ROW') {
|
||||
keys.push('app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-') // Regular numbers
|
||||
}
|
||||
|
||||
if (bothNumKeys || shortcutNumKeys == 'NUM_KEYPAD') {
|
||||
keys.push('app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-') // Key-pad numbers
|
||||
}
|
||||
|
||||
keys.forEach(function (key) {
|
||||
let modifiers = prefixModifiers
|
||||
|
||||
// for some reason, in gnome-shell >= 40 Clutter.get_current_event() is now empty
|
||||
// for keyboard events. Create here the modifiers that are needed in appicon.activate
|
||||
modifiers |=
|
||||
key.indexOf('-shift-') >= 0 ? Clutter.ModifierType.SHIFT_MASK : 0
|
||||
modifiers |=
|
||||
key.indexOf('-ctrl-') >= 0 ? Clutter.ModifierType.CONTROL_MASK : 0
|
||||
|
||||
for (let i = 0; i < this._numHotkeys; i++) {
|
||||
let appNum = i
|
||||
|
||||
Utils.addKeybinding(key + (i + 1), SETTINGS, () =>
|
||||
this._activateApp(appNum, modifiers),
|
||||
)
|
||||
}
|
||||
}, this)
|
||||
|
||||
this._hotKeysEnabled = true
|
||||
|
||||
if (SETTINGS.get_string('hotkeys-overlay-combo') === 'ALWAYS')
|
||||
this.taskbar.toggleNumberOverlay(true)
|
||||
}
|
||||
|
||||
_disableHotKeys() {
|
||||
if (!this._hotKeysEnabled) return
|
||||
|
||||
let keys = [
|
||||
'app-hotkey-',
|
||||
'app-shift-hotkey-',
|
||||
'app-ctrl-hotkey-', // Regular numbers
|
||||
'app-hotkey-kp-',
|
||||
'app-shift-hotkey-kp-',
|
||||
'app-ctrl-hotkey-kp-',
|
||||
] // Key-pad numbers
|
||||
keys.forEach(function (key) {
|
||||
for (let i = 0; i < this._numHotkeys; i++) {
|
||||
Utils.removeKeybinding(key + (i + 1))
|
||||
}
|
||||
}, this)
|
||||
|
||||
if (Main.wm._switchToApplication) {
|
||||
let gsSettings = new Gio.Settings({
|
||||
schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA,
|
||||
})
|
||||
|
||||
for (let i = 1; i < 10; ++i) {
|
||||
Utils.addKeybinding(
|
||||
GS_HOTKEYS_KEY + i,
|
||||
gsSettings,
|
||||
Main.wm._switchToApplication.bind(Main.wm),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
this._hotKeysEnabled = false
|
||||
|
||||
this.taskbar.toggleNumberOverlay(false)
|
||||
}
|
||||
|
||||
_optionalNumberOverlay() {
|
||||
// Enable extra shortcut
|
||||
if (SETTINGS.get_boolean('hot-keys')) this._enableExtraShortcut()
|
||||
|
||||
this._signalsHandler.add(
|
||||
[SETTINGS, 'changed::hot-keys', this._checkHotkeysOptions.bind(this)],
|
||||
[
|
||||
SETTINGS,
|
||||
'changed::hotkeys-overlay-combo',
|
||||
() => {
|
||||
if (
|
||||
SETTINGS.get_boolean('hot-keys') &&
|
||||
SETTINGS.get_string('hotkeys-overlay-combo') === 'ALWAYS'
|
||||
)
|
||||
this.taskbar.toggleNumberOverlay(true)
|
||||
else this.taskbar.toggleNumberOverlay(false)
|
||||
},
|
||||
],
|
||||
[SETTINGS, 'changed::shortcut-num-keys', () => this._resetHotkeys()],
|
||||
)
|
||||
}
|
||||
|
||||
_checkHotkeysOptions() {
|
||||
if (SETTINGS.get_boolean('hot-keys')) this._enableExtraShortcut()
|
||||
else this._disableExtraShortcut()
|
||||
}
|
||||
|
||||
_enableExtraShortcut() {
|
||||
Utils.addKeybinding('shortcut', SETTINGS, () => this._showOverlay(true))
|
||||
}
|
||||
|
||||
_disableExtraShortcut() {
|
||||
Utils.removeKeybinding('shortcut')
|
||||
}
|
||||
|
||||
_showOverlay(overlayFromShortcut) {
|
||||
//wait for intellihide timeout initialization
|
||||
if (!this._panel.intellihide) {
|
||||
return
|
||||
}
|
||||
|
||||
// Restart the counting if the shortcut is pressed again
|
||||
let hotkey_option = SETTINGS.get_string('hotkeys-overlay-combo')
|
||||
|
||||
if (hotkey_option === 'NEVER') return
|
||||
|
||||
if (hotkey_option === 'TEMPORARILY' || overlayFromShortcut)
|
||||
this.taskbar.toggleNumberOverlay(true)
|
||||
|
||||
this._panel.intellihide.revealAndHold(Intellihide.Hold.TEMPORARY)
|
||||
|
||||
let timeout = SETTINGS.get_int('overlay-timeout')
|
||||
|
||||
if (overlayFromShortcut) {
|
||||
timeout = SETTINGS.get_int('shortcut-timeout')
|
||||
}
|
||||
|
||||
// Hide the overlay/dock after the timeout
|
||||
this._timeoutsHandler.add([
|
||||
T2,
|
||||
timeout,
|
||||
() => {
|
||||
if (hotkey_option != 'ALWAYS') {
|
||||
this.taskbar.toggleNumberOverlay(false)
|
||||
}
|
||||
|
||||
function IsolatedOverview() {
|
||||
// These lines take care of Nautilus for icons on Desktop
|
||||
let activeWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace();
|
||||
let windows = this.get_windows().filter(w => w.get_workspace().index() == activeWorkspace.index());
|
||||
this._panel.intellihide.release(Intellihide.Hold.TEMPORARY)
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
if (windows.length > 0 &&
|
||||
(!(windows.length == 1 && windows[0].skip_taskbar) ||
|
||||
this.is_on_workspace(activeWorkspace)))
|
||||
return Main.activateWindow(windows[0]);
|
||||
|
||||
return this.open_new_window(-1);
|
||||
}
|
||||
_optionalClickToExit() {
|
||||
this._clickToExitEnabled = false
|
||||
if (SETTINGS.get_boolean('overview-click-to-exit'))
|
||||
this._enableClickToExit()
|
||||
|
||||
this._signalsHandler.add([
|
||||
SETTINGS,
|
||||
'changed::isolate-workspaces',
|
||||
() => {
|
||||
this._panel.panelManager.allPanels.forEach(p => p.taskbar.resetAppIcons());
|
||||
|
||||
if (SETTINGS.get_boolean('isolate-workspaces'))
|
||||
enable();
|
||||
else
|
||||
disable();
|
||||
}
|
||||
]);
|
||||
|
||||
if (SETTINGS.get_boolean('isolate-workspaces'))
|
||||
enable();
|
||||
}
|
||||
|
||||
// Hotkeys
|
||||
_activateApp(appIndex, modifiers) {
|
||||
let seenApps = {};
|
||||
let apps = [];
|
||||
|
||||
this.taskbar._getAppIcons().forEach(appIcon => {
|
||||
if (!seenApps[appIcon.app] || this.taskbar.allowSplitApps) {
|
||||
apps.push(appIcon);
|
||||
}
|
||||
|
||||
seenApps[appIcon.app] = (seenApps[appIcon.app] || 0) + 1;
|
||||
});
|
||||
|
||||
this._showOverlay();
|
||||
|
||||
if (appIndex < apps.length) {
|
||||
let appIcon = apps[appIndex];
|
||||
let seenAppCount = seenApps[appIcon.app];
|
||||
let windowCount = appIcon.window || appIcon._hotkeysCycle ? seenAppCount : appIcon._nWindows;
|
||||
|
||||
if (SETTINGS.get_boolean('shortcut-previews') && windowCount > 1 &&
|
||||
!(modifiers & ~(Clutter.ModifierType.MOD1_MASK | Clutter.ModifierType.SUPER_MASK))) { //ignore the alt (MOD1_MASK) and super key (SUPER_MASK)
|
||||
if (this._hotkeyPreviewCycleInfo && this._hotkeyPreviewCycleInfo.appIcon != appIcon) {
|
||||
this._endHotkeyPreviewCycle();
|
||||
}
|
||||
|
||||
if (!this._hotkeyPreviewCycleInfo) {
|
||||
this._hotkeyPreviewCycleInfo = {
|
||||
appIcon: appIcon,
|
||||
currentWindow: appIcon.window,
|
||||
keyFocusOutId: appIcon.connect('key-focus-out', () => appIcon.grab_key_focus()),
|
||||
capturedEventId: global.stage.connect('captured-event', (actor, e) => {
|
||||
if (e.type() == Clutter.EventType.KEY_RELEASE && e.get_key_symbol() == (Clutter.KEY_Super_L || Clutter.Super_L)) {
|
||||
this._endHotkeyPreviewCycle(true);
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
})
|
||||
};
|
||||
|
||||
appIcon._hotkeysCycle = appIcon.window;
|
||||
appIcon.window = null;
|
||||
appIcon._previewMenu.open(appIcon, true);
|
||||
appIcon.grab_key_focus();
|
||||
}
|
||||
|
||||
appIcon._previewMenu.focusNext();
|
||||
} else {
|
||||
// Activate with button = 1, i.e. same as left click
|
||||
let button = 1;
|
||||
this._endHotkeyPreviewCycle();
|
||||
appIcon.activate(button, modifiers, !this.taskbar.allowSplitApps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_endHotkeyPreviewCycle(focusWindow) {
|
||||
if (this._hotkeyPreviewCycleInfo) {
|
||||
global.stage.disconnect(this._hotkeyPreviewCycleInfo.capturedEventId);
|
||||
this._hotkeyPreviewCycleInfo.appIcon.disconnect(this._hotkeyPreviewCycleInfo.keyFocusOutId);
|
||||
|
||||
if (focusWindow) {
|
||||
this._hotkeyPreviewCycleInfo.appIcon._previewMenu.activateFocused();
|
||||
} else
|
||||
this._hotkeyPreviewCycleInfo.appIcon._previewMenu.close()
|
||||
|
||||
this._hotkeyPreviewCycleInfo.appIcon.window = this._hotkeyPreviewCycleInfo.currentWindow;
|
||||
delete this._hotkeyPreviewCycleInfo.appIcon._hotkeysCycle;
|
||||
this._hotkeyPreviewCycleInfo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_optionalHotKeys() {
|
||||
this._hotKeysEnabled = false;
|
||||
if (SETTINGS.get_boolean('hot-keys'))
|
||||
this._enableHotKeys();
|
||||
|
||||
this._signalsHandler.add([
|
||||
SETTINGS,
|
||||
'changed::hot-keys',
|
||||
() => {
|
||||
if (SETTINGS.get_boolean('hot-keys'))
|
||||
this._enableHotKeys();
|
||||
else
|
||||
this._disableHotKeys();
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
_resetHotkeys() {
|
||||
this._disableHotKeys();
|
||||
this._enableHotKeys();
|
||||
}
|
||||
|
||||
_enableHotKeys() {
|
||||
if (this._hotKeysEnabled)
|
||||
return;
|
||||
|
||||
//3.32 introduced app hotkeys, disable them to prevent conflicts
|
||||
if (Main.wm._switchToApplication) {
|
||||
for (let i = 1; i < 10; ++i) {
|
||||
Utils.removeKeybinding(GS_HOTKEYS_KEY + i);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup keyboard bindings for taskbar elements
|
||||
let shortcutNumKeys = SETTINGS.get_string('shortcut-num-keys');
|
||||
let bothNumKeys = shortcutNumKeys == 'BOTH';
|
||||
let keys = [];
|
||||
let prefixModifiers = Clutter.ModifierType.SUPER_MASK
|
||||
|
||||
if (SETTINGS.get_string('hotkey-prefix-text') == 'SuperAlt')
|
||||
prefixModifiers |= Clutter.ModifierType.MOD1_MASK
|
||||
|
||||
if (bothNumKeys || shortcutNumKeys == 'NUM_ROW') {
|
||||
keys.push('app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-'); // Regular numbers
|
||||
}
|
||||
|
||||
if (bothNumKeys || shortcutNumKeys == 'NUM_KEYPAD') {
|
||||
keys.push('app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-'); // Key-pad numbers
|
||||
}
|
||||
|
||||
keys.forEach( function(key) {
|
||||
let modifiers = prefixModifiers
|
||||
|
||||
// for some reason, in gnome-shell >= 40 Clutter.get_current_event() is now empty
|
||||
// for keyboard events. Create here the modifiers that are needed in appicon.activate
|
||||
modifiers |= (key.indexOf('-shift-') >= 0 ? Clutter.ModifierType.SHIFT_MASK : 0)
|
||||
modifiers |= (key.indexOf('-ctrl-') >= 0 ? Clutter.ModifierType.CONTROL_MASK : 0)
|
||||
|
||||
for (let i = 0; i < this._numHotkeys; i++) {
|
||||
let appNum = i;
|
||||
|
||||
Utils.addKeybinding(key + (i + 1), SETTINGS, () => this._activateApp(appNum, modifiers));
|
||||
}
|
||||
}, this);
|
||||
|
||||
this._hotKeysEnabled = true;
|
||||
|
||||
if (SETTINGS.get_string('hotkeys-overlay-combo') === 'ALWAYS')
|
||||
this.taskbar.toggleNumberOverlay(true);
|
||||
}
|
||||
|
||||
_disableHotKeys() {
|
||||
if (!this._hotKeysEnabled)
|
||||
return;
|
||||
|
||||
let keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-', // Regular numbers
|
||||
'app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-']; // Key-pad numbers
|
||||
keys.forEach( function(key) {
|
||||
for (let i = 0; i < this._numHotkeys; i++) {
|
||||
Utils.removeKeybinding(key + (i + 1));
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (Main.wm._switchToApplication) {
|
||||
let gsSettings = new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA });
|
||||
|
||||
for (let i = 1; i < 10; ++i) {
|
||||
Utils.addKeybinding(GS_HOTKEYS_KEY + i, gsSettings, Main.wm._switchToApplication.bind(Main.wm));
|
||||
}
|
||||
}
|
||||
|
||||
this._hotKeysEnabled = false;
|
||||
|
||||
this.taskbar.toggleNumberOverlay(false);
|
||||
}
|
||||
|
||||
_optionalNumberOverlay() {
|
||||
// Enable extra shortcut
|
||||
if (SETTINGS.get_boolean('hot-keys'))
|
||||
this._enableExtraShortcut();
|
||||
|
||||
this._signalsHandler.add([
|
||||
SETTINGS,
|
||||
'changed::hot-keys',
|
||||
this._checkHotkeysOptions.bind(this)
|
||||
], [
|
||||
SETTINGS,
|
||||
'changed::hotkeys-overlay-combo',
|
||||
() => {
|
||||
if (SETTINGS.get_boolean('hot-keys') && SETTINGS.get_string('hotkeys-overlay-combo') === 'ALWAYS')
|
||||
this.taskbar.toggleNumberOverlay(true);
|
||||
else
|
||||
this.taskbar.toggleNumberOverlay(false);
|
||||
}
|
||||
], [
|
||||
SETTINGS,
|
||||
'changed::shortcut-num-keys',
|
||||
() => this._resetHotkeys()
|
||||
]);
|
||||
}
|
||||
|
||||
_checkHotkeysOptions() {
|
||||
if (SETTINGS.get_boolean('hot-keys'))
|
||||
this._enableExtraShortcut();
|
||||
else
|
||||
this._disableExtraShortcut();
|
||||
}
|
||||
|
||||
_enableExtraShortcut() {
|
||||
Utils.addKeybinding('shortcut', SETTINGS, () => this._showOverlay(true));
|
||||
}
|
||||
|
||||
_disableExtraShortcut() {
|
||||
Utils.removeKeybinding('shortcut');
|
||||
}
|
||||
|
||||
_showOverlay(overlayFromShortcut) {
|
||||
//wait for intellihide timeout initialization
|
||||
if (!this._panel.intellihide) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Restart the counting if the shortcut is pressed again
|
||||
let hotkey_option = SETTINGS.get_string('hotkeys-overlay-combo');
|
||||
|
||||
if (hotkey_option === 'NEVER')
|
||||
return;
|
||||
|
||||
if (hotkey_option === 'TEMPORARILY' || overlayFromShortcut)
|
||||
this.taskbar.toggleNumberOverlay(true);
|
||||
|
||||
this._panel.intellihide.revealAndHold(Intellihide.Hold.TEMPORARY);
|
||||
|
||||
let timeout = SETTINGS.get_int('overlay-timeout');
|
||||
|
||||
if (overlayFromShortcut) {
|
||||
timeout = SETTINGS.get_int('shortcut-timeout');
|
||||
}
|
||||
|
||||
// Hide the overlay/dock after the timeout
|
||||
this._timeoutsHandler.add([T2, timeout, () => {
|
||||
if (hotkey_option != 'ALWAYS') {
|
||||
this.taskbar.toggleNumberOverlay(false);
|
||||
}
|
||||
|
||||
this._panel.intellihide.release(Intellihide.Hold.TEMPORARY);
|
||||
}]);
|
||||
}
|
||||
|
||||
_optionalClickToExit() {
|
||||
this._clickToExitEnabled = false;
|
||||
this._signalsHandler.add([
|
||||
SETTINGS,
|
||||
'changed::overview-click-to-exit',
|
||||
() => {
|
||||
if (SETTINGS.get_boolean('overview-click-to-exit'))
|
||||
this._enableClickToExit();
|
||||
this._enableClickToExit()
|
||||
else this._disableClickToExit()
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
this._signalsHandler.add([
|
||||
SETTINGS,
|
||||
'changed::overview-click-to-exit',
|
||||
() => {
|
||||
if (SETTINGS.get_boolean('overview-click-to-exit'))
|
||||
this._enableClickToExit();
|
||||
else
|
||||
this._disableClickToExit();
|
||||
}
|
||||
]);
|
||||
}
|
||||
_enableClickToExit() {
|
||||
if (this._clickToExitEnabled) return
|
||||
|
||||
_enableClickToExit() {
|
||||
if (this._clickToExitEnabled)
|
||||
return;
|
||||
this._signalsHandler.addWithLabel('click-to-exit', [
|
||||
Main.layoutManager.overviewGroup,
|
||||
'button-release-event',
|
||||
() => {
|
||||
let [x, y] = global.get_pointer()
|
||||
let pickedActor = global.stage.get_actor_at_pos(
|
||||
Clutter.PickMode.REACTIVE,
|
||||
x,
|
||||
y,
|
||||
)
|
||||
|
||||
this._signalsHandler.addWithLabel('click-to-exit', [
|
||||
Main.layoutManager.overviewGroup,
|
||||
'button-release-event',
|
||||
() => {
|
||||
let [x, y] = global.get_pointer();
|
||||
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
||||
|
||||
if (pickedActor) {
|
||||
let parent = pickedActor.get_parent();
|
||||
if (pickedActor) {
|
||||
let parent = pickedActor.get_parent()
|
||||
|
||||
if (
|
||||
(
|
||||
pickedActor.has_style_class_name &&
|
||||
pickedActor.has_style_class_name('apps-scroll-view') &&
|
||||
!pickedActor.has_style_pseudo_class('first-child')
|
||||
) || (
|
||||
parent?.has_style_class_name &&
|
||||
parent.has_style_class_name('window-picker')
|
||||
) ||
|
||||
Main.overview._overview._controls._searchEntryBin.contains(pickedActor) ||
|
||||
pickedActor instanceof WindowPreview
|
||||
)
|
||||
return Clutter.EVENT_PROPAGATE
|
||||
}
|
||||
if (
|
||||
(pickedActor.has_style_class_name &&
|
||||
pickedActor.has_style_class_name('apps-scroll-view') &&
|
||||
!pickedActor.has_style_pseudo_class('first-child')) ||
|
||||
(parent?.has_style_class_name &&
|
||||
parent.has_style_class_name('window-picker')) ||
|
||||
Main.overview._overview._controls._searchEntryBin.contains(
|
||||
pickedActor,
|
||||
) ||
|
||||
pickedActor instanceof WindowPreview
|
||||
)
|
||||
return Clutter.EVENT_PROPAGATE
|
||||
}
|
||||
|
||||
Main.overview.toggle()
|
||||
}
|
||||
]);
|
||||
Main.overview.toggle()
|
||||
},
|
||||
])
|
||||
|
||||
this._clickToExitEnabled = true;
|
||||
}
|
||||
this._clickToExitEnabled = true
|
||||
}
|
||||
|
||||
_disableClickToExit() {
|
||||
if (!this._clickToExitEnabled)
|
||||
return;
|
||||
|
||||
this._signalsHandler.removeWithLabel('click-to-exit')
|
||||
_disableClickToExit() {
|
||||
if (!this._clickToExitEnabled) return
|
||||
|
||||
this._clickToExitEnabled = false;
|
||||
}
|
||||
this._signalsHandler.removeWithLabel('click-to-exit')
|
||||
|
||||
_onSwipeBegin() {
|
||||
this._swiping = true;
|
||||
return true;
|
||||
}
|
||||
this._clickToExitEnabled = false
|
||||
}
|
||||
|
||||
_onSwipeEnd() {
|
||||
this._timeoutsHandler.add([
|
||||
T1,
|
||||
0,
|
||||
() => this._swiping = false
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
_onSwipeBegin() {
|
||||
this._swiping = true
|
||||
return true
|
||||
}
|
||||
|
||||
_onSwipeEnd() {
|
||||
this._timeoutsHandler.add([T1, 0, () => (this._swiping = false)])
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user