Format code

This commit is contained in:
Charles Gagnon
2025-01-31 11:49:22 -05:00
parent a0d831c25e
commit d04104ff8a
22 changed files with 14374 additions and 10716 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ dash-to-panel@jderose9.github.com*.zip
*.mo
po/dash-to-panel.pot
ui/*.ui.h
node_modules/

5
.prettierrc Normal file
View File

@@ -0,0 +1,5 @@
{
"semi": false,
"arrowParens": "always",
"singleQuote": true
}

File diff suppressed because it is too large Load Diff

View File

@@ -55,111 +55,117 @@
*
*******************************************************************************/
import GLib from 'gi://GLib';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as ExtensionUtils from 'resource:///org/gnome/shell/misc/extensionUtils.js';
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
import GLib from 'gi://GLib'
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
import * as ExtensionUtils from 'resource:///org/gnome/shell/misc/extensionUtils.js'
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js'
const IDENTIFIER_UUID = "130cbc66-235c-4bd6-8571-98d2d8bba5e2";
const IDENTIFIER_UUID = '130cbc66-235c-4bd6-8571-98d2d8bba5e2'
export class DesktopIconsUsableAreaClass {
_checkIfExtensionIsEnabled(extension) {
return (extension?.state === ExtensionUtils.ExtensionState.ENABLED) ||
(extension?.state === ExtensionUtils.ExtensionState.ACTIVE);
}
_checkIfExtensionIsEnabled(extension) {
return (
extension?.state === ExtensionUtils.ExtensionState.ENABLED ||
extension?.state === ExtensionUtils.ExtensionState.ACTIVE
)
}
constructor() {
const Me = Extension.lookupByURL(import.meta.url);
this._UUID = Me.uuid;
this._extensionManager = Main.extensionManager;
this._timedMarginsID = 0;
this._margins = {};
this._emID = this._extensionManager.connect('extension-state-changed', (_obj, extension) => {
if (!extension)
return;
constructor() {
const Me = Extension.lookupByURL(import.meta.url)
this._UUID = Me.uuid
this._extensionManager = Main.extensionManager
this._timedMarginsID = 0
this._margins = {}
this._emID = this._extensionManager.connect(
'extension-state-changed',
(_obj, extension) => {
if (!extension) return
// If an extension is being enabled and lacks the DesktopIconsUsableArea object, we can avoid launching a refresh
if (this._checkIfExtensionIsEnabled(extension)) {
this._sendMarginsToExtension(extension);
return;
}
// if the extension is being disabled, we must do a full refresh, because if there were other extensions originally
// loaded after that extension, those extensions will be disabled and enabled again without notification
this._changedMargins();
});
}
/**
* Sets or updates the top, bottom, left and right margins for a
* monitor. Values are measured from the monitor border (and NOT from
* the workspace border).
*
* @param {int} monitor Monitor number to which set the margins.
* A negative value means "the primary monitor".
* @param {int} top Top margin in pixels
* @param {int} bottom Bottom margin in pixels
* @param {int} left Left margin in pixels
* @param {int} right Right margin in pixels
*/
setMargins(monitor, top, bottom, left, right) {
this._margins[monitor] = {
'top': top,
'bottom': bottom,
'left': left,
'right': right
};
this._changedMargins();
}
/**
* Clears the current margins. Must be called before configuring the monitors
* margins with setMargins().
*/
resetMargins() {
this._margins = {};
this._changedMargins();
}
/**
* Disconnects all the signals and removes the margins.
*/
destroy() {
if (this._emID) {
this._extensionManager.disconnect(this._emID);
this._emID = 0;
// If an extension is being enabled and lacks the DesktopIconsUsableArea object, we can avoid launching a refresh
if (this._checkIfExtensionIsEnabled(extension)) {
this._sendMarginsToExtension(extension)
return
}
if (this._timedMarginsID) {
GLib.source_remove(this._timedMarginsID);
this._timedMarginsID = 0;
}
this._margins = null;
this._changedMargins();
}
// if the extension is being disabled, we must do a full refresh, because if there were other extensions originally
// loaded after that extension, those extensions will be disabled and enabled again without notification
this._changedMargins()
},
)
}
_changedMargins() {
if (this._timedMarginsID) {
GLib.source_remove(this._timedMarginsID);
}
this._timedMarginsID = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, ()=> {
this._sendMarginsToAll();
this._timedMarginsID = 0;
return GLib.SOURCE_REMOVE;
});
/**
* Sets or updates the top, bottom, left and right margins for a
* monitor. Values are measured from the monitor border (and NOT from
* the workspace border).
*
* @param {int} monitor Monitor number to which set the margins.
* A negative value means "the primary monitor".
* @param {int} top Top margin in pixels
* @param {int} bottom Bottom margin in pixels
* @param {int} left Left margin in pixels
* @param {int} right Right margin in pixels
*/
setMargins(monitor, top, bottom, left, right) {
this._margins[monitor] = {
top: top,
bottom: bottom,
left: left,
right: right,
}
this._changedMargins()
}
_sendMarginsToAll() {
this._extensionManager.getUuids().forEach(uuid =>
this._sendMarginsToExtension(this._extensionManager.lookup(uuid)));
/**
* Clears the current margins. Must be called before configuring the monitors
* margins with setMargins().
*/
resetMargins() {
this._margins = {}
this._changedMargins()
}
/**
* Disconnects all the signals and removes the margins.
*/
destroy() {
if (this._emID) {
this._extensionManager.disconnect(this._emID)
this._emID = 0
}
_sendMarginsToExtension(extension) {
// check that the extension is an extension that has the logic to accept
// working margins
if (!this._checkIfExtensionIsEnabled(extension))
return;
const usableArea = extension?.stateObj?.DesktopIconsUsableArea;
if (usableArea?.uuid === IDENTIFIER_UUID)
usableArea.setMarginsForExtension(this._UUID, this._margins);
if (this._timedMarginsID) {
GLib.source_remove(this._timedMarginsID)
this._timedMarginsID = 0
}
this._margins = null
this._changedMargins()
}
_changedMargins() {
if (this._timedMarginsID) {
GLib.source_remove(this._timedMarginsID)
}
this._timedMarginsID = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, () => {
this._sendMarginsToAll()
this._timedMarginsID = 0
return GLib.SOURCE_REMOVE
})
}
_sendMarginsToAll() {
this._extensionManager
.getUuids()
.forEach((uuid) =>
this._sendMarginsToExtension(this._extensionManager.lookup(uuid)),
)
}
_sendMarginsToExtension(extension) {
// check that the extension is an extension that has the logic to accept
// working margins
if (!this._checkIfExtensionIsEnabled(extension)) return
const usableArea = extension?.stateObj?.DesktopIconsUsableArea
if (usableArea?.uuid === IDENTIFIER_UUID)
usableArea.setMarginsForExtension(this._UUID, this._margins)
}
}

9
eslint.config.js Normal file
View File

@@ -0,0 +1,9 @@
import globals from 'globals'
import pluginJs from '@eslint/js'
import eslintConfigPrettier from 'eslint-config-prettier'
export default [
{ languageOptions: { globals: globals.node } },
pluginJs.configs.recommended,
eslintConfigPrettier,
]

View File

@@ -17,114 +17,129 @@
*
*/
import Gio from 'gi://Gio'
import Gio from 'gi://Gio';
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
import { EventEmitter } from 'resource:///org/gnome/shell/misc/signals.js'
import {
Extension,
gettext as _,
} from 'resource:///org/gnome/shell/extensions/extension.js'
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import {EventEmitter} from 'resource:///org/gnome/shell/misc/signals.js';
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as PanelManager from './panelManager.js'
import * as AppIcons from './appIcons.js'
import * as PanelManager from './panelManager.js';
import * as AppIcons from './appIcons.js';
const UBUNTU_DOCK_UUID = 'ubuntu-dock@ubuntu.com'
let panelManager
let extensionChangedHandler
let startupCompleteHandler
let extensionSystem = Main.extensionManager
const UBUNTU_DOCK_UUID = 'ubuntu-dock@ubuntu.com';
let panelManager;
let extensionChangedHandler;
let startupCompleteHandler;
let extensionSystem = Main.extensionManager;
export let DTP_EXTENSION = null;
export let SETTINGS = null;
export let DESKTOPSETTINGS = null;
export let TERMINALSETTINGS = null;
export let PERSISTENTSTORAGE = null;
export let EXTENSION_UUID = null;
export let EXTENSION_PATH = null;
export let DTP_EXTENSION = null
export let SETTINGS = null
export let DESKTOPSETTINGS = null
export let TERMINALSETTINGS = null
export let PERSISTENTSTORAGE = null
export let EXTENSION_UUID = null
export let EXTENSION_PATH = null
export default class DashToPanelExtension extends Extension {
constructor(metadata) {
super(metadata);
constructor(metadata) {
super(metadata)
this._realHasOverview = Main.sessionMode.hasOverview;
//create an object that persists until gnome-shell is restarted, even if the extension is disabled
PERSISTENTSTORAGE = {};
}
this._realHasOverview = Main.sessionMode.hasOverview
enable() {
DTP_EXTENSION = this;
//create an object that persists until gnome-shell is restarted, even if the extension is disabled
PERSISTENTSTORAGE = {}
}
// The Ubuntu Dock extension might get enabled after this extension
extensionChangedHandler = extensionSystem.connect('extension-state-changed', (data, extension) => {
if (extension.uuid === UBUNTU_DOCK_UUID && extension.state === 1) {
_enable(this);
}
});
enable() {
DTP_EXTENSION = this
//create a global object that can emit signals and conveniently expose functionalities to other extensions
global.dashToPanel = new EventEmitter();
_enable(this);
}
disable(reset = false) {
panelManager.disable();
DTP_EXTENSION = null;
SETTINGS = null;
DESKTOPSETTINGS = null;
TERMINALSETTINGS = null;
panelManager = null;
if (!reset) {
extensionSystem.disconnect(extensionChangedHandler);
delete global.dashToPanel;
AppIcons.resetRecentlyClickedApp();
// The Ubuntu Dock extension might get enabled after this extension
extensionChangedHandler = extensionSystem.connect(
'extension-state-changed',
(data, extension) => {
if (extension.uuid === UBUNTU_DOCK_UUID && extension.state === 1) {
_enable(this)
}
},
)
if (startupCompleteHandler) {
Main.layoutManager.disconnect(startupCompleteHandler);
startupCompleteHandler = null;
}
//create a global object that can emit signals and conveniently expose functionalities to other extensions
global.dashToPanel = new EventEmitter()
Main.sessionMode.hasOverview = this._realHasOverview;
_enable(this)
}
disable(reset = false) {
panelManager.disable()
DTP_EXTENSION = null
SETTINGS = null
DESKTOPSETTINGS = null
TERMINALSETTINGS = null
panelManager = null
if (!reset) {
extensionSystem.disconnect(extensionChangedHandler)
delete global.dashToPanel
AppIcons.resetRecentlyClickedApp()
}
if (startupCompleteHandler) {
Main.layoutManager.disconnect(startupCompleteHandler)
startupCompleteHandler = null
}
Main.sessionMode.hasOverview = this._realHasOverview
}
}
function _enable(extension) {
let enabled = global.settings.get_strv('enabled-extensions');
let enabled = global.settings.get_strv('enabled-extensions')
if (enabled?.indexOf(UBUNTU_DOCK_UUID) >= 0)
extensionSystem.disableExtension(UBUNTU_DOCK_UUID);
if (enabled?.indexOf(UBUNTU_DOCK_UUID) >= 0)
extensionSystem.disableExtension(UBUNTU_DOCK_UUID)
if (panelManager)
return
if (panelManager) return
SETTINGS = extension.getSettings('org.gnome.shell.extensions.dash-to-panel');
DESKTOPSETTINGS = new Gio.Settings({schema_id: 'org.gnome.desktop.interface'});
TERMINALSETTINGS = new Gio.Settings({schema_id: 'org.gnome.desktop.default-applications.terminal'})
EXTENSION_UUID = extension.uuid
EXTENSION_PATH = extension.path
SETTINGS = extension.getSettings('org.gnome.shell.extensions.dash-to-panel')
DESKTOPSETTINGS = new Gio.Settings({
schema_id: 'org.gnome.desktop.interface',
})
TERMINALSETTINGS = new Gio.Settings({
schema_id: 'org.gnome.desktop.default-applications.terminal',
})
EXTENSION_UUID = extension.uuid
EXTENSION_PATH = extension.path
Main.layoutManager.startInOverview = !SETTINGS.get_boolean('hide-overview-on-startup');
Main.layoutManager.startInOverview = !SETTINGS.get_boolean(
'hide-overview-on-startup',
)
if (SETTINGS.get_boolean('hide-overview-on-startup') && Main.layoutManager._startingUp) {
Main.sessionMode.hasOverview = false;
startupCompleteHandler = Main.layoutManager.connect('startup-complete', () => {
Main.sessionMode.hasOverview = extension._realHasOverview
});
}
if (
SETTINGS.get_boolean('hide-overview-on-startup') &&
Main.layoutManager._startingUp
) {
Main.sessionMode.hasOverview = false
startupCompleteHandler = Main.layoutManager.connect(
'startup-complete',
() => {
Main.sessionMode.hasOverview = extension._realHasOverview
},
)
}
// show the donate icon every 120 days (10368000000 milliseconds)
let donateIconUnixtime = SETTINGS.get_string('hide-donate-icon-unixtime')
// show the donate icon every 120 days (10368000000 milliseconds)
let donateIconUnixtime = SETTINGS.get_string('hide-donate-icon-unixtime')
if (donateIconUnixtime && donateIconUnixtime < Date.now() - 10368000000)
SETTINGS.set_string('hide-donate-icon-unixtime', '')
if (donateIconUnixtime && donateIconUnixtime < Date.now() - 10368000000)
SETTINGS.set_string('hide-donate-icon-unixtime', '')
panelManager = new PanelManager.PanelManager();
panelManager = new PanelManager.PanelManager()
panelManager.enable();
}
panelManager.enable()
}

View File

@@ -15,413 +15,474 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import Clutter from 'gi://Clutter';
import Meta from 'gi://Meta';
import Shell from 'gi://Shell';
import St from 'gi://St';
import Clutter from 'gi://Clutter'
import Meta from 'gi://Meta'
import Shell from 'gi://Shell'
import St from 'gi://St'
import * as GrabHelper from 'resource:///org/gnome/shell/ui/grabHelper.js';
import * as Layout from 'resource:///org/gnome/shell/ui/layout.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js';
import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.js';
import * as GrabHelper from 'resource:///org/gnome/shell/ui/grabHelper.js'
import * as Layout from 'resource:///org/gnome/shell/ui/layout.js'
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js'
import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.js'
import * as Proximity from './proximity.js';
import * as Utils from './utils.js';
import {SETTINGS} from './extension.js';
import * as Proximity from './proximity.js'
import * as Utils from './utils.js'
import { SETTINGS } from './extension.js'
//timeout intervals
const CHECK_POINTER_MS = 200;
const CHECK_GRAB_MS = 400;
const POST_ANIMATE_MS = 50;
const MIN_UPDATE_MS = 250;
const CHECK_POINTER_MS = 200
const CHECK_GRAB_MS = 400
const POST_ANIMATE_MS = 50
const MIN_UPDATE_MS = 250
//timeout names
const T1 = 'checkGrabTimeout';
const T2 = 'limitUpdateTimeout';
const T3 = 'postAnimateTimeout';
const T1 = 'checkGrabTimeout'
const T2 = 'limitUpdateTimeout'
const T3 = 'postAnimateTimeout'
const SIDE_CONTROLS_ANIMATION_TIME = OverviewControls.SIDE_CONTROLS_ANIMATION_TIME / (OverviewControls.SIDE_CONTROLS_ANIMATION_TIME > 1 ? 1000 : 1);
const SIDE_CONTROLS_ANIMATION_TIME =
OverviewControls.SIDE_CONTROLS_ANIMATION_TIME /
(OverviewControls.SIDE_CONTROLS_ANIMATION_TIME > 1 ? 1000 : 1)
export const Hold = {
NONE: 0,
TEMPORARY: 1,
PERMANENT: 2
};
NONE: 0,
TEMPORARY: 1,
PERMANENT: 2,
}
export const Intellihide = class {
constructor(dtpPanel) {
this._dtpPanel = dtpPanel
this._panelBox = dtpPanel.panelBox
this._panelManager = dtpPanel.panelManager
this._proximityManager = this._panelManager.proximityManager
this._holdStatus = Hold.NONE
constructor(dtpPanel) {
this._dtpPanel = dtpPanel;
this._panelBox = dtpPanel.panelBox;
this._panelManager = dtpPanel.panelManager;
this._proximityManager = this._panelManager.proximityManager;
this._holdStatus = Hold.NONE;
this._signalsHandler = new Utils.GlobalSignalsHandler();
this._timeoutsHandler = new Utils.TimeoutsHandler();
this._signalsHandler = new Utils.GlobalSignalsHandler()
this._timeoutsHandler = new Utils.TimeoutsHandler()
this._intellihideChangedId = SETTINGS.connect('changed::intellihide', () => this._changeEnabledStatus());
this._intellihideOnlySecondaryChangedId = SETTINGS.connect('changed::intellihide-only-secondary', () => this._changeEnabledStatus());
this._intellihideChangedId = SETTINGS.connect('changed::intellihide', () =>
this._changeEnabledStatus(),
)
this._intellihideOnlySecondaryChangedId = SETTINGS.connect(
'changed::intellihide-only-secondary',
() => this._changeEnabledStatus(),
)
this.enabled = false;
this._changeEnabledStatus();
this.enabled = false
this._changeEnabledStatus()
}
enable() {
this.enabled = true
this._monitor = this._dtpPanel.monitor
this._animationDestination = -1
this._pendingUpdate = false
this._hoveredOut = false
this._windowOverlap = false
this._translationProp =
'translation_' + (this._dtpPanel.checkIfVertical() ? 'x' : 'y')
this._panelBox.translation_y = 0
this._panelBox.translation_x = 0
this._setTrackPanel(true)
this._bindGeneralSignals()
if (SETTINGS.get_boolean('intellihide-hide-from-windows')) {
this._proximityWatchId = this._proximityManager.createWatch(
this._panelBox.get_parent(),
this._dtpPanel.monitor.index,
Proximity.Mode[SETTINGS.get_string('intellihide-behaviour')],
0,
0,
(overlap) => {
this._windowOverlap = overlap
this._queueUpdatePanelPosition()
},
)
}
enable() {
this.enabled = true;
this._monitor = this._dtpPanel.monitor;
this._animationDestination = -1;
this._pendingUpdate = false;
this._hoveredOut = false;
this._windowOverlap = false;
this._translationProp = 'translation_' + (this._dtpPanel.checkIfVertical() ? 'x' : 'y');
this._setRevealMechanism()
this._queueUpdatePanelPosition()
}
this._panelBox.translation_y = 0;
this._panelBox.translation_x = 0;
disable(reset) {
if (this._proximityWatchId) {
this._proximityManager.removeWatch(this._proximityWatchId)
}
this._setTrackPanel(true);
this._bindGeneralSignals();
this._setTrackPanel(false)
if (SETTINGS.get_boolean('intellihide-hide-from-windows')) {
this._proximityWatchId = this._proximityManager.createWatch(
this._panelBox.get_parent(),
this._dtpPanel.monitor.index,
Proximity.Mode[SETTINGS.get_string('intellihide-behaviour')],
0, 0,
overlap => {
this._windowOverlap = overlap;
this._queueUpdatePanelPosition();
}
);
this._signalsHandler.destroy()
this._timeoutsHandler.destroy()
this._removeRevealMechanism()
this._revealPanel(!reset)
this.enabled = false
}
destroy() {
SETTINGS.disconnect(this._intellihideChangedId)
SETTINGS.disconnect(this._intellihideOnlySecondaryChangedId)
if (this.enabled) {
this.disable()
}
}
toggle() {
this[this._holdStatus & Hold.PERMANENT ? 'release' : 'revealAndHold'](
Hold.PERMANENT,
)
}
revealAndHold(holdStatus) {
if (this.enabled && !this._holdStatus) {
this._revealPanel()
}
this._holdStatus |= holdStatus
}
release(holdStatus) {
this._holdStatus -= holdStatus
if (this.enabled && !this._holdStatus) {
this._queueUpdatePanelPosition()
}
}
reset() {
this.disable(true)
this.enable()
}
_changeEnabledStatus() {
let intellihide = SETTINGS.get_boolean('intellihide')
let onlySecondary = SETTINGS.get_boolean('intellihide-only-secondary')
let enabled = intellihide && !(this._dtpPanel.isPrimary && onlySecondary)
if (this.enabled !== enabled) {
this[enabled ? 'enable' : 'disable']()
}
}
_bindGeneralSignals() {
this._signalsHandler.add(
[
this._dtpPanel.taskbar,
['menu-closed', 'end-drag'],
() => {
this._panelBox.sync_hover()
this._onHoverChanged()
},
],
[
SETTINGS,
[
'changed::intellihide-use-pressure',
'changed::intellihide-hide-from-windows',
'changed::intellihide-behaviour',
'changed::intellihide-pressure-threshold',
'changed::intellihide-pressure-time',
],
() => this.reset(),
],
[this._panelBox, 'notify::hover', () => this._onHoverChanged()],
[
this._dtpPanel.taskbar.previewMenu,
'open-state-changed',
() => this._queueUpdatePanelPosition(),
],
[
Main.overview,
['showing', 'hiding'],
() => this._queueUpdatePanelPosition(),
],
)
if (Meta.is_wayland_compositor()) {
this._signalsHandler.add([
this._panelBox,
'notify::visible',
() => Utils.setDisplayUnredirect(!this._panelBox.visible),
])
}
}
_onHoverChanged() {
this._hoveredOut = !this._panelBox.hover
this._queueUpdatePanelPosition()
}
_setTrackPanel(enable) {
let actorData = Utils.getTrackedActorData(this._panelBox)
actorData.affectsStruts = !enable
actorData.trackFullscreen = !enable
this._panelBox.track_hover = enable
this._panelBox.reactive = enable
this._panelBox.visible = enable ? enable : this._panelBox.visible
Main.layoutManager._queueUpdateRegions()
}
_setRevealMechanism() {
let barriers = Meta.BackendCapabilities.BARRIERS
if (
(global.backend.capabilities & barriers) === barriers &&
SETTINGS.get_boolean('intellihide-use-pressure')
) {
this._edgeBarrier = this._createBarrier()
this._pressureBarrier = new Layout.PressureBarrier(
SETTINGS.get_int('intellihide-pressure-threshold'),
SETTINGS.get_int('intellihide-pressure-time'),
Shell.ActionMode.NORMAL,
)
this._pressureBarrier.addBarrier(this._edgeBarrier)
this._signalsHandler.add([
this._pressureBarrier,
'trigger',
() => this._queueUpdatePanelPosition(true),
])
} else {
this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(
CHECK_POINTER_MS,
(x, y) => this._checkMousePointer(x, y),
)
}
}
_removeRevealMechanism() {
if (this._pointerWatch) {
PointerWatcher.getPointerWatcher()._removeWatch(this._pointerWatch)
}
if (this._pressureBarrier) {
this._pressureBarrier.destroy()
this._edgeBarrier.destroy()
this._pressureBarrier = 0
}
}
_createBarrier() {
let position = this._dtpPanel.geom.position
let opts = { backend: global.backend }
if (this._dtpPanel.checkIfVertical()) {
opts.y1 = this._monitor.y
opts.y2 = this._monitor.y + this._monitor.height
opts.x1 = opts.x2 = this._monitor.x
} else {
opts.x1 = this._monitor.x
opts.x2 = this._monitor.x + this._monitor.width
opts.y1 = opts.y2 = this._monitor.y
}
if (position == St.Side.TOP) {
opts.directions = Meta.BarrierDirection.POSITIVE_Y
} else if (position == St.Side.BOTTOM) {
opts.y1 = opts.y2 = opts.y1 + this._monitor.height
opts.directions = Meta.BarrierDirection.NEGATIVE_Y
} else if (position == St.Side.LEFT) {
opts.directions = Meta.BarrierDirection.POSITIVE_X
} else {
opts.x1 = opts.x2 = opts.x1 + this._monitor.width
opts.directions = Meta.BarrierDirection.NEGATIVE_X
}
return new Meta.Barrier(opts)
}
_checkMousePointer(x, y) {
let position = this._dtpPanel.geom.position
if (
!this._panelBox.hover &&
!Main.overview.visible &&
((position == St.Side.TOP && y <= this._monitor.y + 1) ||
(position == St.Side.BOTTOM &&
y >= this._monitor.y + this._monitor.height - 1) ||
(position == St.Side.LEFT && x <= this._monitor.x + 1) ||
(position == St.Side.RIGHT &&
x >= this._monitor.x + this._monitor.width - 1)) &&
x >= this._monitor.x &&
x < this._monitor.x + this._monitor.width &&
y >= this._monitor.y &&
y < this._monitor.y + this._monitor.height
) {
this._queueUpdatePanelPosition(true)
}
}
_queueUpdatePanelPosition(fromRevealMechanism) {
if (
!fromRevealMechanism &&
this._timeoutsHandler.getId(T2) &&
!Main.overview.visible
) {
//unless this is a mouse interaction or entering/leaving the overview, limit the number
//of updates, but remember to update again when the limit timeout is reached
this._pendingUpdate = true
} else if (!this._holdStatus) {
this._checkIfShouldBeVisible(fromRevealMechanism)
? this._revealPanel()
: this._hidePanel()
this._timeoutsHandler.add([
T2,
MIN_UPDATE_MS,
() => this._endLimitUpdate(),
])
}
}
_endLimitUpdate() {
if (this._pendingUpdate) {
this._pendingUpdate = false
this._queueUpdatePanelPosition()
}
}
_checkIfShouldBeVisible(fromRevealMechanism) {
if (
Main.overview.visibleTarget ||
this._dtpPanel.taskbar.previewMenu.opened ||
this._dtpPanel.taskbar._dragMonitor ||
this._panelBox.get_hover() ||
this._checkIfGrab()
) {
return true
}
if (fromRevealMechanism) {
let mouseBtnIsPressed =
global.get_pointer()[2] & Clutter.ModifierType.BUTTON1_MASK
//the user is trying to reveal the panel
if (this._monitor.inFullscreen && !mouseBtnIsPressed) {
return SETTINGS.get_boolean('intellihide-show-in-fullscreen')
}
return !mouseBtnIsPressed
}
if (!SETTINGS.get_boolean('intellihide-hide-from-windows')) {
return this._panelBox.hover
}
return !this._windowOverlap
}
_checkIfGrab() {
let isGrab
if (GrabHelper._grabHelperStack)
// gnome-shell < 42
isGrab = GrabHelper._grabHelperStack.some(
(gh) => gh._owner == this._dtpPanel.panel,
)
else if (global.stage.get_grab_actor) {
// gnome-shell >= 42
let grabActor = global.stage.get_grab_actor()
let sourceActor = grabActor?._sourceActor || grabActor
isGrab =
sourceActor &&
(sourceActor == Main.layoutManager.dummyCursor ||
this._dtpPanel.statusArea.quickSettings?.menu.actor.contains(
sourceActor,
) ||
this._dtpPanel.panel.contains(sourceActor))
}
if (isGrab)
//there currently is a grab on a child of the panel, check again soon to catch its release
this._timeoutsHandler.add([
T1,
CHECK_GRAB_MS,
() => this._queueUpdatePanelPosition(),
])
return isGrab
}
_revealPanel(immediate) {
if (!this._panelBox.visible) {
this._panelBox.visible = true
this._dtpPanel.taskbar._shownInitially = false
}
this._animatePanel(0, immediate)
}
_hidePanel(immediate) {
let position = this._dtpPanel.geom.position
let size =
this._panelBox[
position == St.Side.LEFT || position == St.Side.RIGHT
? 'width'
: 'height'
]
let coefficient =
position == St.Side.TOP || position == St.Side.LEFT ? -1 : 1
this._animatePanel(size * coefficient, immediate)
}
_animatePanel(destination, immediate) {
let animating = Utils.isAnimating(this._panelBox, this._translationProp)
if (
!(
(animating && destination === this._animationDestination) ||
(!animating && destination === this._panelBox[this._translationProp])
)
) {
//the panel isn't already at, or animating to the asked destination
if (animating) {
Utils.stopAnimations(this._panelBox)
}
this._animationDestination = destination
if (immediate) {
this._panelBox[this._translationProp] = destination
this._panelBox.visible = !destination
} else {
let tweenOpts = {
//when entering/leaving the overview, use its animation time instead of the one from the settings
time: Main.overview.visible
? SIDE_CONTROLS_ANIMATION_TIME
: SETTINGS.get_int('intellihide-animation-time') * 0.001,
//only delay the animation when hiding the panel after the user hovered out
delay:
destination != 0 && this._hoveredOut
? SETTINGS.get_int('intellihide-close-delay') * 0.001
: 0,
transition: 'easeOutQuad',
onComplete: () => {
this._panelBox.visible = !destination
Main.layoutManager._queueUpdateRegions()
this._timeoutsHandler.add([
T3,
POST_ANIMATE_MS,
() => this._queueUpdatePanelPosition(),
])
},
}
this._setRevealMechanism();
this._queueUpdatePanelPosition();
tweenOpts[this._translationProp] = destination
Utils.animate(this._panelBox, tweenOpts)
}
}
disable(reset) {
if (this._proximityWatchId) {
this._proximityManager.removeWatch(this._proximityWatchId);
}
this._setTrackPanel(false);
this._signalsHandler.destroy();
this._timeoutsHandler.destroy();
this._removeRevealMechanism();
this._revealPanel(!reset);
this.enabled = false;
}
destroy() {
SETTINGS.disconnect(this._intellihideChangedId);
SETTINGS.disconnect(this._intellihideOnlySecondaryChangedId);
if (this.enabled) {
this.disable();
}
}
toggle() {
this[this._holdStatus & Hold.PERMANENT ? 'release' : 'revealAndHold'](Hold.PERMANENT);
}
revealAndHold(holdStatus) {
if (this.enabled && !this._holdStatus) {
this._revealPanel();
}
this._holdStatus |= holdStatus;
}
release(holdStatus) {
this._holdStatus -= holdStatus;
if (this.enabled && !this._holdStatus) {
this._queueUpdatePanelPosition();
}
}
reset() {
this.disable(true);
this.enable();
}
_changeEnabledStatus() {
let intellihide = SETTINGS.get_boolean('intellihide');
let onlySecondary = SETTINGS.get_boolean('intellihide-only-secondary');
let enabled = intellihide && !(this._dtpPanel.isPrimary && onlySecondary);
if (this.enabled !== enabled) {
this[enabled ? 'enable' : 'disable']();
}
}
_bindGeneralSignals() {
this._signalsHandler.add(
[
this._dtpPanel.taskbar,
['menu-closed', 'end-drag'],
() => {
this._panelBox.sync_hover();
this._onHoverChanged();
}
],
[
SETTINGS,
[
'changed::intellihide-use-pressure',
'changed::intellihide-hide-from-windows',
'changed::intellihide-behaviour',
'changed::intellihide-pressure-threshold',
'changed::intellihide-pressure-time'
],
() => this.reset()
],
[
this._panelBox,
'notify::hover',
() => this._onHoverChanged()
],
[
this._dtpPanel.taskbar.previewMenu,
'open-state-changed',
() => this._queueUpdatePanelPosition()
],
[
Main.overview,
[
'showing',
'hiding'
],
() => this._queueUpdatePanelPosition()
]
);
if (Meta.is_wayland_compositor()) {
this._signalsHandler.add([
this._panelBox,
'notify::visible',
() => Utils.setDisplayUnredirect(!this._panelBox.visible)
]);
}
}
_onHoverChanged() {
this._hoveredOut = !this._panelBox.hover;
this._queueUpdatePanelPosition();
}
_setTrackPanel(enable) {
let actorData = Utils.getTrackedActorData(this._panelBox)
actorData.affectsStruts = !enable;
actorData.trackFullscreen = !enable;
this._panelBox.track_hover = enable;
this._panelBox.reactive = enable;
this._panelBox.visible = enable ? enable : this._panelBox.visible;
Main.layoutManager._queueUpdateRegions();
}
_setRevealMechanism() {
let barriers = Meta.BackendCapabilities.BARRIERS
if ((global.backend.capabilities & barriers) === barriers && SETTINGS.get_boolean('intellihide-use-pressure')) {
this._edgeBarrier = this._createBarrier();
this._pressureBarrier = new Layout.PressureBarrier(
SETTINGS.get_int('intellihide-pressure-threshold'),
SETTINGS.get_int('intellihide-pressure-time'),
Shell.ActionMode.NORMAL
);
this._pressureBarrier.addBarrier(this._edgeBarrier);
this._signalsHandler.add([this._pressureBarrier, 'trigger', () => this._queueUpdatePanelPosition(true)]);
} else {
this._pointerWatch = PointerWatcher.getPointerWatcher()
.addWatch(CHECK_POINTER_MS, (x, y) => this._checkMousePointer(x, y));
}
}
_removeRevealMechanism() {
if (this._pointerWatch) {
PointerWatcher.getPointerWatcher()._removeWatch(this._pointerWatch);
}
if (this._pressureBarrier) {
this._pressureBarrier.destroy();
this._edgeBarrier.destroy();
this._pressureBarrier = 0;
}
}
_createBarrier() {
let position = this._dtpPanel.geom.position;
let opts = { backend: global.backend };
if (this._dtpPanel.checkIfVertical()) {
opts.y1 = this._monitor.y;
opts.y2 = this._monitor.y + this._monitor.height;
opts.x1 = opts.x2 = this._monitor.x;
} else {
opts.x1 = this._monitor.x;
opts.x2 = this._monitor.x + this._monitor.width;
opts.y1 = opts.y2 = this._monitor.y;
}
if (position == St.Side.TOP) {
opts.directions = Meta.BarrierDirection.POSITIVE_Y;
} else if (position == St.Side.BOTTOM) {
opts.y1 = opts.y2 = opts.y1 + this._monitor.height;
opts.directions = Meta.BarrierDirection.NEGATIVE_Y;
} else if (position == St.Side.LEFT) {
opts.directions = Meta.BarrierDirection.POSITIVE_X;
} else {
opts.x1 = opts.x2 = opts.x1 + this._monitor.width;
opts.directions = Meta.BarrierDirection.NEGATIVE_X;
}
return new Meta.Barrier(opts);
}
_checkMousePointer(x, y) {
let position = this._dtpPanel.geom.position;
if (!this._panelBox.hover && !Main.overview.visible &&
((position == St.Side.TOP && y <= this._monitor.y + 1) ||
(position == St.Side.BOTTOM && y >= this._monitor.y + this._monitor.height - 1) ||
(position == St.Side.LEFT && x <= this._monitor.x + 1) ||
(position == St.Side.RIGHT && x >= this._monitor.x + this._monitor.width - 1)) &&
((x >= this._monitor.x && x < this._monitor.x + this._monitor.width) &&
(y >= this._monitor.y && y < this._monitor.y + this._monitor.height))) {
this._queueUpdatePanelPosition(true);
}
}
_queueUpdatePanelPosition(fromRevealMechanism) {
if (!fromRevealMechanism && this._timeoutsHandler.getId(T2) && !Main.overview.visible) {
//unless this is a mouse interaction or entering/leaving the overview, limit the number
//of updates, but remember to update again when the limit timeout is reached
this._pendingUpdate = true;
} else if (!this._holdStatus) {
this._checkIfShouldBeVisible(fromRevealMechanism) ? this._revealPanel() : this._hidePanel();
this._timeoutsHandler.add([T2, MIN_UPDATE_MS, () => this._endLimitUpdate()]);
}
}
_endLimitUpdate() {
if (this._pendingUpdate) {
this._pendingUpdate = false;
this._queueUpdatePanelPosition();
}
}
_checkIfShouldBeVisible(fromRevealMechanism) {
if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.opened ||
this._dtpPanel.taskbar._dragMonitor || this._panelBox.get_hover() || this._checkIfGrab()) {
return true;
}
if (fromRevealMechanism) {
let mouseBtnIsPressed = global.get_pointer()[2] & Clutter.ModifierType.BUTTON1_MASK;
//the user is trying to reveal the panel
if (this._monitor.inFullscreen && !mouseBtnIsPressed) {
return SETTINGS.get_boolean('intellihide-show-in-fullscreen');
}
return !mouseBtnIsPressed;
}
if (!SETTINGS.get_boolean('intellihide-hide-from-windows')) {
return this._panelBox.hover;
}
return !this._windowOverlap;
}
_checkIfGrab() {
let isGrab
if (GrabHelper._grabHelperStack)
// gnome-shell < 42
isGrab = GrabHelper._grabHelperStack.some(gh => gh._owner == this._dtpPanel.panel)
else if (global.stage.get_grab_actor) {
// gnome-shell >= 42
let grabActor = global.stage.get_grab_actor()
let sourceActor = grabActor?._sourceActor || grabActor
isGrab = sourceActor &&
(sourceActor == Main.layoutManager.dummyCursor ||
this._dtpPanel.statusArea.quickSettings?.menu.actor.contains(sourceActor) ||
this._dtpPanel.panel.contains(sourceActor))
}
if (isGrab)
//there currently is a grab on a child of the panel, check again soon to catch its release
this._timeoutsHandler.add([T1, CHECK_GRAB_MS, () => this._queueUpdatePanelPosition()]);
return isGrab;
}
_revealPanel(immediate) {
if (!this._panelBox.visible) {
this._panelBox.visible = true;
this._dtpPanel.taskbar._shownInitially = false;
}
this._animatePanel(0, immediate);
}
_hidePanel(immediate) {
let position = this._dtpPanel.geom.position;
let size = this._panelBox[position == St.Side.LEFT || position == St.Side.RIGHT ? 'width' : 'height'];
let coefficient = position == St.Side.TOP || position == St.Side.LEFT ? -1 : 1;
this._animatePanel(size * coefficient, immediate);
}
_animatePanel(destination, immediate) {
let animating = Utils.isAnimating(this._panelBox, this._translationProp);
if (!((animating && destination === this._animationDestination) ||
(!animating && destination === this._panelBox[this._translationProp]))) {
//the panel isn't already at, or animating to the asked destination
if (animating) {
Utils.stopAnimations(this._panelBox);
}
this._animationDestination = destination;
if (immediate) {
this._panelBox[this._translationProp] = destination;
this._panelBox.visible = !destination;
} else {
let tweenOpts = {
//when entering/leaving the overview, use its animation time instead of the one from the settings
time: Main.overview.visible ?
SIDE_CONTROLS_ANIMATION_TIME :
SETTINGS.get_int('intellihide-animation-time') * 0.001,
//only delay the animation when hiding the panel after the user hovered out
delay: destination != 0 && this._hoveredOut ? SETTINGS.get_int('intellihide-close-delay') * 0.001 : 0,
transition: 'easeOutQuad',
onComplete: () => {
this._panelBox.visible = !destination;
Main.layoutManager._queueUpdateRegions();
this._timeoutsHandler.add([T3, POST_ANIMATE_MS, () => this._queueUpdatePanelPosition()]);
}
};
tweenOpts[this._translationProp] = destination;
Utils.animate(this._panelBox, tweenOpts);
}
}
this._hoveredOut = false;
}
this._hoveredOut = false
}
}

View File

@@ -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
}
}

13
package.json Normal file
View File

@@ -0,0 +1,13 @@
{
"type": "module",
"scripts": {
"lint": "prettier 'src/**/*.js' --write && eslint 'src/**/*.js' --fix"
},
"devDependencies": {
"@eslint/js": "^9.19.0",
"eslint": "^9.19.0",
"eslint-config-prettier": "^10.0.1",
"globals": "^15.14.0",
"prettier": "^3.4.2"
}
}

2195
panel.js

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -15,47 +15,47 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
export const SHOW_APPS_BTN = 'showAppsButton';
export const ACTIVITIES_BTN = 'activitiesButton';
export const TASKBAR = 'taskbar';
export const DATE_MENU = 'dateMenu';
export const SYSTEM_MENU = 'systemMenu';
export const LEFT_BOX = 'leftBox';
export const CENTER_BOX = 'centerBox';
export const RIGHT_BOX = 'rightBox';
export const DESKTOP_BTN = 'desktopButton';
export const SHOW_APPS_BTN = 'showAppsButton'
export const ACTIVITIES_BTN = 'activitiesButton'
export const TASKBAR = 'taskbar'
export const DATE_MENU = 'dateMenu'
export const SYSTEM_MENU = 'systemMenu'
export const LEFT_BOX = 'leftBox'
export const CENTER_BOX = 'centerBox'
export const RIGHT_BOX = 'rightBox'
export const DESKTOP_BTN = 'desktopButton'
export const STACKED_TL = 'stackedTL';
export const STACKED_BR = 'stackedBR';
export const CENTERED = 'centered';
export const CENTERED_MONITOR = 'centerMonitor';
export const STACKED_TL = 'stackedTL'
export const STACKED_BR = 'stackedBR'
export const CENTERED = 'centered'
export const CENTERED_MONITOR = 'centerMonitor'
export const TOP = 'TOP';
export const BOTTOM = 'BOTTOM';
export const LEFT = 'LEFT';
export const RIGHT = 'RIGHT';
export const TOP = 'TOP'
export const BOTTOM = 'BOTTOM'
export const LEFT = 'LEFT'
export const RIGHT = 'RIGHT'
export const START = 'START';
export const MIDDLE = 'MIDDLE';
export const END = 'END';
export const START = 'START'
export const MIDDLE = 'MIDDLE'
export const END = 'END'
export const defaults = [
{ element: SHOW_APPS_BTN, visible: true, position: STACKED_TL },
{ element: ACTIVITIES_BTN, visible: false, position: STACKED_TL },
{ element: LEFT_BOX, visible: true, position: STACKED_TL },
{ element: TASKBAR, visible: true, position: STACKED_TL },
{ element: CENTER_BOX, visible: true, position: STACKED_BR },
{ element: RIGHT_BOX, visible: true, position: STACKED_BR },
{ element: DATE_MENU, visible: true, position: STACKED_BR },
{ element: SYSTEM_MENU, visible: true, position: STACKED_BR },
{ element: DESKTOP_BTN, visible: true, position: STACKED_BR },
];
{ element: SHOW_APPS_BTN, visible: true, position: STACKED_TL },
{ element: ACTIVITIES_BTN, visible: false, position: STACKED_TL },
{ element: LEFT_BOX, visible: true, position: STACKED_TL },
{ element: TASKBAR, visible: true, position: STACKED_TL },
{ element: CENTER_BOX, visible: true, position: STACKED_BR },
{ element: RIGHT_BOX, visible: true, position: STACKED_BR },
{ element: DATE_MENU, visible: true, position: STACKED_BR },
{ element: SYSTEM_MENU, visible: true, position: STACKED_BR },
{ element: DESKTOP_BTN, visible: true, position: STACKED_BR },
]
export const optionDialogFunctions = {};
export const optionDialogFunctions = {}
optionDialogFunctions[SHOW_APPS_BTN] = '_showShowAppsButtonOptions';
optionDialogFunctions[DESKTOP_BTN] = '_showDesktopButtonOptions';
optionDialogFunctions[SHOW_APPS_BTN] = '_showShowAppsButtonOptions'
optionDialogFunctions[DESKTOP_BTN] = '_showDesktopButtonOptions'
export function checkIfCentered(position) {
return position == CENTERED || position == CENTERED_MONITOR;
return position == CENTERED || position == CENTERED_MONITOR
}

View File

@@ -15,43 +15,43 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import * as Pos from './panelPositions.js';
import * as Pos from './panelPositions.js'
/** Return object representing a settings value that is stored as JSON. */
export function getSettingsJson(settings, setting) {
try {
return JSON.parse(settings.get_string(setting));
} catch(e) {
log('Error parsing positions: ' + e.message);
}
try {
return JSON.parse(settings.get_string(setting))
} catch (e) {
log('Error parsing positions: ' + e.message)
}
}
/** Write value object as JSON to setting in settings. */
export function setSettingsJson(settings, setting, value) {
try {
const json = JSON.stringify(value);
settings.set_string(setting, json);
} catch(e) {
log('Error serializing setting: ' + e.message);
}
try {
const json = JSON.stringify(value)
settings.set_string(setting, json)
} catch (e) {
log('Error serializing setting: ' + e.message)
}
}
/** Returns size of panel on a specific monitor, in pixels. */
export function getPanelSize(settings, monitorIndex) {
const sizes = getSettingsJson(settings, 'panel-sizes');
// Pull in deprecated setting if panel-sizes does not have setting for monitor.
const fallbackSize = settings.get_int('panel-size');
const theDefault = 48;
return sizes[monitorIndex] || fallbackSize || theDefault;
const sizes = getSettingsJson(settings, 'panel-sizes')
// Pull in deprecated setting if panel-sizes does not have setting for monitor.
const fallbackSize = settings.get_int('panel-size')
const theDefault = 48
return sizes[monitorIndex] || fallbackSize || theDefault
}
export function setPanelSize(settings, monitorIndex, value) {
if (!(Number.isInteger(value) && value <= 128 && value >= 16)) {
log('Not setting invalid panel size: ' + value);
return;
}
let sizes = getSettingsJson(settings, 'panel-sizes');
sizes[monitorIndex] = value;
setSettingsJson(settings, 'panel-sizes', sizes);
if (!(Number.isInteger(value) && value <= 128 && value >= 16)) {
log('Not setting invalid panel size: ' + value)
return
}
let sizes = getSettingsJson(settings, 'panel-sizes')
sizes[monitorIndex] = value
setSettingsJson(settings, 'panel-sizes', sizes)
}
/**
@@ -59,53 +59,59 @@ export function setPanelSize(settings, monitorIndex, value) {
* from settings. e.g. 100
*/
export function getPanelLength(settings, monitorIndex) {
const lengths = getSettingsJson(settings, 'panel-lengths');
const theDefault = 100;
return lengths[monitorIndex] || theDefault;
const lengths = getSettingsJson(settings, 'panel-lengths')
const theDefault = 100
return lengths[monitorIndex] || theDefault
}
export function setPanelLength(settings, monitorIndex, value) {
if (!(Number.isInteger(value) && value <= 100 && value >= 0)) {
log('Not setting invalid panel length: ' + value);
return;
}
let lengths = getSettingsJson(settings, 'panel-lengths');
lengths[monitorIndex] = value;
setSettingsJson(settings, 'panel-lengths', lengths);
if (!(Number.isInteger(value) && value <= 100 && value >= 0)) {
log('Not setting invalid panel length: ' + value)
return
}
let lengths = getSettingsJson(settings, 'panel-lengths')
lengths[monitorIndex] = value
setSettingsJson(settings, 'panel-lengths', lengths)
}
/** Returns position of panel on a specific monitor. */
export function getPanelPosition(settings, monitorIndex) {
const positions = getSettingsJson(settings, 'panel-positions');
const fallbackPosition = settings.get_string('panel-position');
const theDefault = Pos.BOTTOM;
return positions[monitorIndex] || fallbackPosition || theDefault;
const positions = getSettingsJson(settings, 'panel-positions')
const fallbackPosition = settings.get_string('panel-position')
const theDefault = Pos.BOTTOM
return positions[monitorIndex] || fallbackPosition || theDefault
}
export function setPanelPosition(settings, monitorIndex, value) {
if (!(value === Pos.TOP || value === Pos.BOTTOM || value === Pos.LEFT
|| value === Pos.RIGHT)) {
log('Not setting invalid panel position: ' + value);
return;
}
const positions = getSettingsJson(settings, 'panel-positions');
positions[monitorIndex] = value;
setSettingsJson(settings, 'panel-positions', positions);
if (
!(
value === Pos.TOP ||
value === Pos.BOTTOM ||
value === Pos.LEFT ||
value === Pos.RIGHT
)
) {
log('Not setting invalid panel position: ' + value)
return
}
const positions = getSettingsJson(settings, 'panel-positions')
positions[monitorIndex] = value
setSettingsJson(settings, 'panel-positions', positions)
}
/** Returns anchor location of panel on a specific monitor. */
export function getPanelAnchor(settings, monitorIndex) {
const anchors = getSettingsJson(settings, 'panel-anchors');
const theDefault = Pos.MIDDLE;
return anchors[monitorIndex] || theDefault;
const anchors = getSettingsJson(settings, 'panel-anchors')
const theDefault = Pos.MIDDLE
return anchors[monitorIndex] || theDefault
}
export function setPanelAnchor(settings, monitorIndex, value) {
if (!(value === Pos.START || value === Pos.MIDDLE || value === Pos.END)) {
log('Not setting invalid panel anchor: ' + value);
return;
}
const anchors = getSettingsJson(settings, 'panel-anchors');
anchors[monitorIndex] = value;
setSettingsJson(settings, 'panel-anchors', anchors);
if (!(value === Pos.START || value === Pos.MIDDLE || value === Pos.END)) {
log('Not setting invalid panel anchor: ' + value)
return
}
const anchors = getSettingsJson(settings, 'panel-anchors')
anchors[monitorIndex] = value
setSettingsJson(settings, 'panel-anchors', anchors)
}

View File

@@ -21,294 +21,323 @@
* mathematical.coffee@gmail.com
*/
import * as Utils from './utils.js';
import {SETTINGS} from './extension.js';
import * as Utils from './utils.js'
import { SETTINGS } from './extension.js'
export const PanelStyle = class {
enable(panel) {
this.panel = panel
enable(panel) {
this.panel = panel;
this._applyStyles()
this._applyStyles();
this._bindSettingsChanges()
}
this._bindSettingsChanges();
disable() {
for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) {
SETTINGS.disconnect(this._dtpSettingsSignalIds[i])
}
disable() {
for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) {
SETTINGS.disconnect(this._dtpSettingsSignalIds[i]);
this._removeStyles()
}
_bindSettingsChanges() {
let configKeys = [
'tray-size',
'leftbox-size',
'tray-padding',
'leftbox-padding',
'status-icon-padding',
]
this._dtpSettingsSignalIds = []
for (let i in configKeys) {
this._dtpSettingsSignalIds.push(
SETTINGS.connect('changed::' + configKeys[i], () => {
this._removeStyles()
this._applyStyles()
}),
)
}
}
_applyStyles() {
this._rightBoxOperations = []
let trayPadding = SETTINGS.get_int('tray-padding')
let isVertical = this.panel.checkIfVertical()
let paddingStyle = 'padding: ' + (isVertical ? '%dpx 0' : '0 %dpx')
if (trayPadding >= 0) {
let operation = {}
let trayPaddingStyleLine
if (isVertical) {
trayPaddingStyleLine = paddingStyle.format(trayPadding)
operation.compareFn = function (actor) {
let parent = actor.get_parent()
return (
(parent &&
parent.has_style_class_name &&
parent.has_style_class_name('panel-button') &&
!parent.has_style_class_name('clock-display')) ||
(actor.has_style_class_name && actor.has_style_class_name('clock'))
)
}
} else {
trayPaddingStyleLine = '-natural-hpadding: %dpx'.format(trayPadding)
if (trayPadding < 6) {
trayPaddingStyleLine += '; -minimum-hpadding: %dpx'.format(
trayPadding,
)
}
this._removeStyles();
operation.compareFn = function (actor) {
return (
actor.has_style_class_name &&
actor.has_style_class_name('panel-button')
)
}
}
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, trayPaddingStyleLine, operationIdx)
this._refreshPanelButton(actor)
}
this._rightBoxOperations.push(operation)
}
_bindSettingsChanges() {
let configKeys = [
"tray-size",
"leftbox-size",
"tray-padding",
"leftbox-padding",
"status-icon-padding",
];
this._dtpSettingsSignalIds = [];
for(let i in configKeys) {
this._dtpSettingsSignalIds.push(SETTINGS.connect('changed::' + configKeys[i], () => {
this._removeStyles();
this._applyStyles();
}));
}
let statusIconPadding = SETTINGS.get_int('status-icon-padding')
if (statusIconPadding >= 0) {
let statusIconPaddingStyleLine = paddingStyle.format(statusIconPadding)
let operation = {}
operation.compareFn = function (actor) {
return (
actor.has_style_class_name &&
actor.has_style_class_name('system-status-icon')
)
}
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, statusIconPaddingStyleLine, operationIdx)
}
this._rightBoxOperations.push(operation)
}
_applyStyles() {
this._rightBoxOperations = [];
let trayPadding = SETTINGS.get_int('tray-padding');
let isVertical = this.panel.checkIfVertical();
let paddingStyle = 'padding: ' + (isVertical ? '%dpx 0' : '0 %dpx');
let trayContentSize = SETTINGS.get_int('tray-size')
if (trayContentSize > 0) {
let trayIconSizeStyleLine = 'icon-size: %dpx'.format(trayContentSize)
let operation = {}
operation.compareFn = function (actor) {
return actor.constructor && actor.constructor.name == 'St_Icon'
}
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, trayIconSizeStyleLine, operationIdx)
}
this._rightBoxOperations.push(operation)
if(trayPadding >= 0) {
let operation = {};
let trayPaddingStyleLine;
let trayContentSizeStyleLine = 'font-size: %dpx'.format(trayContentSize)
operation = {}
operation.compareFn = function (actor) {
return actor.constructor && actor.constructor.name == 'St_Label'
}
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, trayContentSizeStyleLine, operationIdx)
}
this._rightBoxOperations.push(operation)
if (isVertical) {
trayPaddingStyleLine = paddingStyle.format(trayPadding);
operation.compareFn = function (actor) {
let parent = actor.get_parent();
return ((parent && parent.has_style_class_name && (parent.has_style_class_name('panel-button') && !parent.has_style_class_name('clock-display'))) ||
(actor.has_style_class_name && actor.has_style_class_name('clock')));
};
} else {
trayPaddingStyleLine = '-natural-hpadding: %dpx'.format(trayPadding);
if (trayPadding < 6) {
trayPaddingStyleLine += '; -minimum-hpadding: %dpx'.format(trayPadding);
}
operation.compareFn = function (actor) {
return (actor.has_style_class_name && actor.has_style_class_name('panel-button'));
};
}
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, trayPaddingStyleLine, operationIdx);
this._refreshPanelButton(actor);
};
this._rightBoxOperations.push(operation);
}
let statusIconPadding = SETTINGS.get_int('status-icon-padding');
if(statusIconPadding >= 0) {
let statusIconPaddingStyleLine = paddingStyle.format(statusIconPadding)
let operation = {};
operation.compareFn = function (actor) {
return (actor.has_style_class_name && actor.has_style_class_name('system-status-icon'));
};
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, statusIconPaddingStyleLine, operationIdx);
};
this._rightBoxOperations.push(operation);
}
let trayContentSize = SETTINGS.get_int('tray-size');
if(trayContentSize > 0) {
let trayIconSizeStyleLine = 'icon-size: %dpx'.format(trayContentSize)
let operation = {};
operation.compareFn = function (actor) {
return (actor.constructor && actor.constructor.name == 'St_Icon');
};
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, trayIconSizeStyleLine, operationIdx);
};
this._rightBoxOperations.push(operation);
let trayContentSizeStyleLine = 'font-size: %dpx'.format(trayContentSize)
operation = {};
operation.compareFn = function (actor) {
return (actor.constructor && actor.constructor.name == 'St_Label');
};
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, trayContentSizeStyleLine, operationIdx);
};
this._rightBoxOperations.push(operation);
this._overrideStyle(this.panel._rightBox, trayContentSizeStyleLine, 0);
this._overrideStyle(this.panel._centerBox, trayContentSizeStyleLine, 0);
}
// center box has been moved next to the right box and will be treated the same
this._centerBoxOperations = this._rightBoxOperations;
this._leftBoxOperations = [];
let leftboxPadding = SETTINGS.get_int('leftbox-padding');
if(leftboxPadding >= 0) {
let leftboxPaddingStyleLine = paddingStyle.format(leftboxPadding);
let operation = {};
operation.compareFn = function (actor) {
let parent = actor.get_parent();
return (parent && parent.has_style_class_name && parent.has_style_class_name('panel-button'));
};
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, leftboxPaddingStyleLine, operationIdx);
};
this._leftBoxOperations.push(operation);
}
let leftboxContentSize = SETTINGS.get_int('leftbox-size');
if(leftboxContentSize > 0) {
let leftboxIconSizeStyleLine = 'icon-size: %dpx'.format(leftboxContentSize)
let operation = {};
operation.compareFn = function (actor) {
return (actor.constructor && actor.constructor.name == 'St_Icon');
};
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, leftboxIconSizeStyleLine, operationIdx);
};
this._leftBoxOperations.push(operation);
let leftboxContentSizeStyleLine = 'font-size: %dpx'.format(leftboxContentSize)
operation = {};
operation.compareFn = function (actor) {
return (actor.constructor && actor.constructor.name == 'St_Label');
};
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, leftboxContentSizeStyleLine, operationIdx);
};
this._leftBoxOperations.push(operation);
this._overrideStyle(this.panel._leftBox, leftboxContentSizeStyleLine, 0);
}
this._applyStylesRecursively();
/* connect signal */
this._rightBoxActorAddedID = this.panel._rightBox.connect('child-added',
(container, actor) => {
if(this._rightBoxOperations.length && !this._ignoreAddedChild)
this._recursiveApply(actor, this._rightBoxOperations);
this._ignoreAddedChild = 0;
}
);
this._centerBoxActorAddedID = this.panel._centerBox.connect('child-added',
(container, actor) => {
if(this._centerBoxOperations.length && !this._ignoreAddedChild)
this._recursiveApply(actor, this._centerBoxOperations);
this._ignoreAddedChild = 0;
}
);
this._leftBoxActorAddedID = this.panel._leftBox.connect('child-added',
(container, actor) => {
if(this._leftBoxOperations.length)
this._recursiveApply(actor, this._leftBoxOperations);
}
);
this._overrideStyle(this.panel._rightBox, trayContentSizeStyleLine, 0)
this._overrideStyle(this.panel._centerBox, trayContentSizeStyleLine, 0)
}
_removeStyles() {
/* disconnect signal */
if (this._rightBoxActorAddedID)
this.panel._rightBox.disconnect(this._rightBoxActorAddedID);
if (this._centerBoxActorAddedID)
this.panel._centerBox.disconnect(this._centerBoxActorAddedID);
if (this._leftBoxActorAddedID)
this.panel._leftBox.disconnect(this._leftBoxActorAddedID);
// center box has been moved next to the right box and will be treated the same
this._centerBoxOperations = this._rightBoxOperations
this._restoreOriginalStyle(this.panel._rightBox);
this._restoreOriginalStyle(this.panel._centerBox);
this._restoreOriginalStyle(this.panel._leftBox);
this._leftBoxOperations = []
this._applyStylesRecursively(true);
let leftboxPadding = SETTINGS.get_int('leftbox-padding')
if (leftboxPadding >= 0) {
let leftboxPaddingStyleLine = paddingStyle.format(leftboxPadding)
let operation = {}
operation.compareFn = function (actor) {
let parent = actor.get_parent()
return (
parent &&
parent.has_style_class_name &&
parent.has_style_class_name('panel-button')
)
}
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, leftboxPaddingStyleLine, operationIdx)
}
this._leftBoxOperations.push(operation)
}
_applyStylesRecursively(restore) {
/*recurse actors */
if(this._rightBoxOperations.length) {
// add the system menu as we move it from the rightbox to the panel to position it independently
let children = this.panel._rightBox.get_children().concat([this.panel.statusArea[Utils.getSystemMenuInfo().name].container]);
for(let i in children)
this._recursiveApply(children[i], this._rightBoxOperations, restore);
}
let leftboxContentSize = SETTINGS.get_int('leftbox-size')
if (leftboxContentSize > 0) {
let leftboxIconSizeStyleLine = 'icon-size: %dpx'.format(
leftboxContentSize,
)
let operation = {}
operation.compareFn = function (actor) {
return actor.constructor && actor.constructor.name == 'St_Icon'
}
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, leftboxIconSizeStyleLine, operationIdx)
}
this._leftBoxOperations.push(operation)
if(this._centerBoxOperations.length) {
// add the date menu as we move it from the centerbox to the panel to position it independently
let children = this.panel._centerBox.get_children().concat([this.panel.statusArea.dateMenu.container]);
for(let i in children)
this._recursiveApply(children[i], this._centerBoxOperations, restore);
}
let leftboxContentSizeStyleLine = 'font-size: %dpx'.format(
leftboxContentSize,
)
operation = {}
operation.compareFn = function (actor) {
return actor.constructor && actor.constructor.name == 'St_Label'
}
operation.applyFn = (actor, operationIdx) => {
this._overrideStyle(actor, leftboxContentSizeStyleLine, operationIdx)
}
this._leftBoxOperations.push(operation)
if(this._leftBoxOperations.length) {
let children = this.panel._leftBox.get_children();
for(let i in children)
this._recursiveApply(children[i], this._leftBoxOperations, restore);
}
this._overrideStyle(this.panel._leftBox, leftboxContentSizeStyleLine, 0)
}
_recursiveApply(actor, operations, restore) {
for(let i in operations) {
let o = operations[i];
if(o.compareFn(actor))
if(restore)
o.restoreFn ? o.restoreFn(actor) : this._restoreOriginalStyle(actor);
else
o.applyFn(actor, i);
}
this._applyStylesRecursively()
if(actor.get_children) {
let children = actor.get_children();
for(let i in children) {
this._recursiveApply(children[i], operations, restore);
}
}
}
_overrideStyle(actor, styleLine, operationIdx) {
if (actor._dtp_original_inline_style === undefined) {
actor._dtp_original_inline_style = actor.get_style();
}
/* connect signal */
this._rightBoxActorAddedID = this.panel._rightBox.connect(
'child-added',
(container, actor) => {
if (this._rightBoxOperations.length && !this._ignoreAddedChild)
this._recursiveApply(actor, this._rightBoxOperations)
if(actor._dtp_style_overrides === undefined) {
actor._dtp_style_overrides = {};
}
this._ignoreAddedChild = 0
},
)
this._centerBoxActorAddedID = this.panel._centerBox.connect(
'child-added',
(container, actor) => {
if (this._centerBoxOperations.length && !this._ignoreAddedChild)
this._recursiveApply(actor, this._centerBoxOperations)
actor._dtp_style_overrides[operationIdx] = styleLine;
let newStyleLine = '';
for(let i in actor._dtp_style_overrides)
newStyleLine += actor._dtp_style_overrides[i] + '; ';
actor.set_style(newStyleLine + (actor._dtp_original_inline_style || ''));
}
this._ignoreAddedChild = 0
},
)
this._leftBoxActorAddedID = this.panel._leftBox.connect(
'child-added',
(container, actor) => {
if (this._leftBoxOperations.length)
this._recursiveApply(actor, this._leftBoxOperations)
},
)
}
_restoreOriginalStyle(actor) {
if (actor._dtp_original_inline_style !== undefined) {
actor.set_style(actor._dtp_original_inline_style);
delete actor._dtp_original_inline_style;
delete actor._dtp_style_overrides;
}
_removeStyles() {
/* disconnect signal */
if (this._rightBoxActorAddedID)
this.panel._rightBox.disconnect(this._rightBoxActorAddedID)
if (this._centerBoxActorAddedID)
this.panel._centerBox.disconnect(this._centerBoxActorAddedID)
if (this._leftBoxActorAddedID)
this.panel._leftBox.disconnect(this._leftBoxActorAddedID)
if (actor.has_style_class_name('panel-button')) {
this._refreshPanelButton(actor);
}
this._restoreOriginalStyle(this.panel._rightBox)
this._restoreOriginalStyle(this.panel._centerBox)
this._restoreOriginalStyle(this.panel._leftBox)
this._applyStylesRecursively(true)
}
_applyStylesRecursively(restore) {
/*recurse actors */
if (this._rightBoxOperations.length) {
// add the system menu as we move it from the rightbox to the panel to position it independently
let children = this.panel._rightBox
.get_children()
.concat([
this.panel.statusArea[Utils.getSystemMenuInfo().name].container,
])
for (let i in children)
this._recursiveApply(children[i], this._rightBoxOperations, restore)
}
_refreshPanelButton(actor) {
if (actor.visible) {
//force gnome 3.34+ to refresh (having problem with the -natural-hpadding)
let parent = actor.get_parent();
let children = parent.get_children();
let actorIndex = 0;
if (children.length > 1) {
actorIndex = children.indexOf(actor);
}
this._ignoreAddedChild = [this.panel._centerBox, this.panel._rightBox].indexOf(parent) >= 0;
parent.remove_child(actor);
parent.insert_child_at_index(actor, actorIndex);
}
if (this._centerBoxOperations.length) {
// add the date menu as we move it from the centerbox to the panel to position it independently
let children = this.panel._centerBox
.get_children()
.concat([this.panel.statusArea.dateMenu.container])
for (let i in children)
this._recursiveApply(children[i], this._centerBoxOperations, restore)
}
if (this._leftBoxOperations.length) {
let children = this.panel._leftBox.get_children()
for (let i in children)
this._recursiveApply(children[i], this._leftBoxOperations, restore)
}
}
_recursiveApply(actor, operations, restore) {
for (let i in operations) {
let o = operations[i]
if (o.compareFn(actor))
if (restore)
o.restoreFn ? o.restoreFn(actor) : this._restoreOriginalStyle(actor)
else o.applyFn(actor, i)
}
if (actor.get_children) {
let children = actor.get_children()
for (let i in children) {
this._recursiveApply(children[i], operations, restore)
}
}
}
_overrideStyle(actor, styleLine, operationIdx) {
if (actor._dtp_original_inline_style === undefined) {
actor._dtp_original_inline_style = actor.get_style()
}
if (actor._dtp_style_overrides === undefined) {
actor._dtp_style_overrides = {}
}
actor._dtp_style_overrides[operationIdx] = styleLine
let newStyleLine = ''
for (let i in actor._dtp_style_overrides)
newStyleLine += actor._dtp_style_overrides[i] + '; '
actor.set_style(newStyleLine + (actor._dtp_original_inline_style || ''))
}
_restoreOriginalStyle(actor) {
if (actor._dtp_original_inline_style !== undefined) {
actor.set_style(actor._dtp_original_inline_style)
delete actor._dtp_original_inline_style
delete actor._dtp_style_overrides
}
if (actor.has_style_class_name('panel-button')) {
this._refreshPanelButton(actor)
}
}
_refreshPanelButton(actor) {
if (actor.visible) {
//force gnome 3.34+ to refresh (having problem with the -natural-hpadding)
let parent = actor.get_parent()
let children = parent.get_children()
let actorIndex = 0
if (children.length > 1) {
actorIndex = children.indexOf(actor)
}
this._ignoreAddedChild =
[this.panel._centerBox, this.panel._rightBox].indexOf(parent) >= 0
parent.remove_child(actor)
parent.insert_child_at_index(actor, actorIndex)
}
}
}

5977
prefs.js

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -15,242 +15,267 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import Meta from 'gi://Meta';
import Mtk from 'gi://Mtk';
import Meta from 'gi://Meta'
import Mtk from 'gi://Mtk'
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
import * as Utils from './utils.js';
import * as Utils from './utils.js'
//timeout intervals
const MIN_UPDATE_MS = 200;
const MIN_UPDATE_MS = 200
//timeout names
const T1 = 'limitUpdateTimeout';
const T1 = 'limitUpdateTimeout'
export const Mode = {
ALL_WINDOWS: 0,
FOCUSED_WINDOWS: 1,
MAXIMIZED_WINDOWS: 2
};
ALL_WINDOWS: 0,
FOCUSED_WINDOWS: 1,
MAXIMIZED_WINDOWS: 2,
}
export class ProximityWatch {
constructor(actor, monitorIndex, mode, xThreshold, yThreshold, handler) {
this.actor = actor
this.monitorIndex = monitorIndex
this.overlap = false
this.mode = mode
this.threshold = [xThreshold, yThreshold]
this.handler = handler
constructor(actor, monitorIndex, mode, xThreshold, yThreshold, handler) {
this.actor = actor;
this.monitorIndex = monitorIndex
this.overlap = false;
this.mode = mode;
this.threshold = [xThreshold, yThreshold];
this.handler = handler;
this._allocationChangedId = actor.connect('notify::allocation', () =>
this._updateWatchRect(),
)
this._allocationChangedId = actor.connect('notify::allocation', () => this._updateWatchRect());
this._updateWatchRect()
}
this._updateWatchRect();
}
destroy() {
this.actor.disconnect(this._allocationChangedId)
}
destroy() {
this.actor.disconnect(this._allocationChangedId);
}
_updateWatchRect() {
let [actorX, actorY] = this.actor.get_position()
_updateWatchRect() {
let [actorX, actorY] = this.actor.get_position();
this.rect = new Mtk.Rectangle({
x: actorX - this.threshold[0],
y: actorY - this.threshold[1],
width: this.actor.width + this.threshold[0] * 2,
height: this.actor.height + this.threshold[1] * 2
});
}
};
this.rect = new Mtk.Rectangle({
x: actorX - this.threshold[0],
y: actorY - this.threshold[1],
width: this.actor.width + this.threshold[0] * 2,
height: this.actor.height + this.threshold[1] * 2,
})
}
}
export const ProximityManager = class {
constructor() {
this._counter = 1
this._watches = {}
this._focusedWindowInfo = null
constructor() {
this._counter = 1;
this._watches = {};
this._focusedWindowInfo = null;
this._signalsHandler = new Utils.GlobalSignalsHandler()
this._timeoutsHandler = new Utils.TimeoutsHandler()
this._signalsHandler = new Utils.GlobalSignalsHandler();
this._timeoutsHandler = new Utils.TimeoutsHandler();
this._bindSignals()
this._setFocusedWindow()
}
this._bindSignals();
this._setFocusedWindow();
createWatch(actor, monitorIndex, mode, xThreshold, yThreshold, handler) {
let watch = new ProximityWatch(
actor,
monitorIndex,
mode,
xThreshold,
yThreshold,
handler,
)
this._watches[this._counter] = watch
this.update()
return this._counter++
}
removeWatch(id) {
if (this._watches[id]) {
this._watches[id].destroy()
delete this._watches[id]
}
}
createWatch(actor, monitorIndex, mode, xThreshold, yThreshold, handler) {
let watch = new ProximityWatch(actor, monitorIndex, mode, xThreshold, yThreshold, handler);
update() {
this._queueUpdate(true)
}
this._watches[this._counter] = watch;
this.update();
return this._counter++;
destroy() {
this._signalsHandler.destroy()
this._timeoutsHandler.destroy()
this._disconnectFocusedWindow()
Object.keys(this._watches).forEach((id) => this.removeWatch(id))
}
_bindSignals() {
this._signalsHandler.add(
[global.window_manager, 'switch-workspace', () => this._queueUpdate()],
[Main.overview, 'hidden', () => this._queueUpdate()],
[
global.display,
'notify::focus-window',
() => {
this._setFocusedWindow()
this._queueUpdate()
},
],
[global.display, 'restacked', () => this._queueUpdate()],
)
}
_setFocusedWindow() {
this._disconnectFocusedWindow()
let focusedWindow = global.display.focus_window
if (focusedWindow) {
let focusedWindowInfo = this._getFocusedWindowInfo(focusedWindow)
if (
focusedWindowInfo &&
this._checkIfHandledWindowType(focusedWindowInfo.metaWindow)
) {
focusedWindowInfo.allocationId = focusedWindowInfo.window.connect(
'notify::allocation',
() => this._queueUpdate(),
)
focusedWindowInfo.destroyId = focusedWindowInfo.window.connect(
'destroy',
() => this._disconnectFocusedWindow(true),
)
this._focusedWindowInfo = focusedWindowInfo
}
}
}
removeWatch(id) {
if (this._watches[id]) {
this._watches[id].destroy();
delete this._watches[id];
_getFocusedWindowInfo(focusedWindow) {
let window = focusedWindow.get_compositor_private()
let focusedWindowInfo
if (window) {
focusedWindowInfo = { window: window }
focusedWindowInfo.metaWindow = focusedWindow
if (focusedWindow.is_attached_dialog()) {
let mainMetaWindow = focusedWindow.get_transient_for()
if (
focusedWindowInfo.metaWindow.get_frame_rect().height <
mainMetaWindow.get_frame_rect().height
) {
focusedWindowInfo.window = mainMetaWindow.get_compositor_private()
focusedWindowInfo.metaWindow = mainMetaWindow
}
}
}
update() {
this._queueUpdate(true);
return focusedWindowInfo
}
_disconnectFocusedWindow(destroy) {
if (this._focusedWindowInfo && !destroy) {
this._focusedWindowInfo.window.disconnect(
this._focusedWindowInfo.allocationId,
)
this._focusedWindowInfo.window.disconnect(
this._focusedWindowInfo.destroyId,
)
}
destroy() {
this._signalsHandler.destroy();
this._timeoutsHandler.destroy();
this._disconnectFocusedWindow();
Object.keys(this._watches).forEach(id => this.removeWatch(id));
this._focusedWindowInfo = null
}
_getHandledWindows() {
return Utils.getCurrentWorkspace()
.list_windows()
.filter((mw) => this._checkIfHandledWindow(mw))
}
_checkIfHandledWindow(metaWindow) {
return (
metaWindow &&
!metaWindow.minimized &&
!metaWindow.customJS_ding &&
this._checkIfHandledWindowType(metaWindow)
)
}
_checkIfHandledWindowType(metaWindow) {
let metaWindowType = metaWindow.get_window_type()
//https://www.roojs.org/seed/gir-1.2-gtk-3.0/seed/Meta.WindowType.html
return (
metaWindowType <= Meta.WindowType.SPLASHSCREEN &&
metaWindowType != Meta.WindowType.DESKTOP
)
}
_queueUpdate(noDelay) {
if (!noDelay && this._timeoutsHandler.getId(T1)) {
//limit the number of updates
this._pendingUpdate = true
return
}
_bindSignals() {
this._signalsHandler.add(
[
global.window_manager,
'switch-workspace',
() => this._queueUpdate()
],
[
Main.overview,
'hidden',
() => this._queueUpdate()
],
[
global.display,
'notify::focus-window',
() => {
this._setFocusedWindow();
this._queueUpdate();
}
],
[
global.display,
'restacked',
() => this._queueUpdate()
]
);
this._timeoutsHandler.add([T1, MIN_UPDATE_MS, () => this._endLimitUpdate()])
let metaWindows = this._getHandledWindows()
Object.keys(this._watches).forEach((id) => {
let watch = this._watches[id]
let overlap = !!this._update(watch, metaWindows)
if (overlap !== watch.overlap) {
watch.handler(overlap)
watch.overlap = overlap
}
})
}
_endLimitUpdate() {
if (this._pendingUpdate) {
this._pendingUpdate = false
this._queueUpdate()
}
}
_setFocusedWindow() {
this._disconnectFocusedWindow();
_update(watch, metaWindows) {
if (watch.mode === Mode.FOCUSED_WINDOWS)
return (
this._focusedWindowInfo &&
this._checkIfHandledWindow(this._focusedWindowInfo.metaWindow) &&
this._checkProximity(this._focusedWindowInfo.metaWindow, watch)
)
let focusedWindow = global.display.focus_window;
if (watch.mode === Mode.MAXIMIZED_WINDOWS)
return metaWindows.some(
(mw) =>
mw.maximized_vertically &&
mw.maximized_horizontally &&
mw.get_monitor() == watch.monitorIndex,
)
if (focusedWindow) {
let focusedWindowInfo = this._getFocusedWindowInfo(focusedWindow);
//Mode.ALL_WINDOWS
return metaWindows.some((mw) => this._checkProximity(mw, watch))
}
if (focusedWindowInfo && this._checkIfHandledWindowType(focusedWindowInfo.metaWindow)) {
focusedWindowInfo.allocationId = focusedWindowInfo.window.connect('notify::allocation', () => this._queueUpdate());
focusedWindowInfo.destroyId = focusedWindowInfo.window.connect('destroy', () => this._disconnectFocusedWindow(true));
this._focusedWindowInfo = focusedWindowInfo;
}
}
}
_checkProximity(metaWindow, watch) {
let windowRect = metaWindow.get_frame_rect()
_getFocusedWindowInfo(focusedWindow) {
let window = focusedWindow.get_compositor_private();
let focusedWindowInfo;
if (window) {
focusedWindowInfo = { window: window };
focusedWindowInfo.metaWindow = focusedWindow;
if (focusedWindow.is_attached_dialog()) {
let mainMetaWindow = focusedWindow.get_transient_for();
if (focusedWindowInfo.metaWindow.get_frame_rect().height < mainMetaWindow.get_frame_rect().height) {
focusedWindowInfo.window = mainMetaWindow.get_compositor_private();
focusedWindowInfo.metaWindow = mainMetaWindow;
}
}
}
return focusedWindowInfo;
}
_disconnectFocusedWindow(destroy) {
if (this._focusedWindowInfo && !destroy) {
this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.allocationId);
this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.destroyId);
}
this._focusedWindowInfo = null;
}
_getHandledWindows() {
return Utils.getCurrentWorkspace()
.list_windows()
.filter(mw => this._checkIfHandledWindow(mw));
}
_checkIfHandledWindow(metaWindow) {
return metaWindow &&
!metaWindow.minimized &&
!metaWindow.customJS_ding &&
this._checkIfHandledWindowType(metaWindow);
}
_checkIfHandledWindowType(metaWindow) {
let metaWindowType = metaWindow.get_window_type();
//https://www.roojs.org/seed/gir-1.2-gtk-3.0/seed/Meta.WindowType.html
return metaWindowType <= Meta.WindowType.SPLASHSCREEN &&
metaWindowType != Meta.WindowType.DESKTOP;
}
_queueUpdate(noDelay) {
if (!noDelay && this._timeoutsHandler.getId(T1)) {
//limit the number of updates
this._pendingUpdate = true;
return;
}
this._timeoutsHandler.add([T1, MIN_UPDATE_MS, () => this._endLimitUpdate()]);
let metaWindows = this._getHandledWindows();
Object.keys(this._watches).forEach(id => {
let watch = this._watches[id];
let overlap = !!this._update(watch, metaWindows);
if (overlap !== watch.overlap) {
watch.handler(overlap);
watch.overlap = overlap;
}
});
}
_endLimitUpdate() {
if (this._pendingUpdate) {
this._pendingUpdate = false;
this._queueUpdate();
}
}
_update(watch, metaWindows) {
if (watch.mode === Mode.FOCUSED_WINDOWS)
return (this._focusedWindowInfo &&
this._checkIfHandledWindow(this._focusedWindowInfo.metaWindow) &&
this._checkProximity(this._focusedWindowInfo.metaWindow, watch));
if (watch.mode === Mode.MAXIMIZED_WINDOWS)
return metaWindows.some(mw => mw.maximized_vertically && mw.maximized_horizontally &&
mw.get_monitor() == watch.monitorIndex);
//Mode.ALL_WINDOWS
return metaWindows.some(mw => this._checkProximity(mw, watch));
}
_checkProximity(metaWindow, watch) {
let windowRect = metaWindow.get_frame_rect();
return windowRect.overlap(watch.rect) &&
((!watch.threshold[0] && !watch.threshold[1]) ||
metaWindow.get_monitor() == watch.monitorIndex ||
windowRect.overlap(global.display.get_monitor_geometry(watch.monitorIndex)));
}
};
return (
windowRect.overlap(watch.rect) &&
((!watch.threshold[0] && !watch.threshold[1]) ||
metaWindow.get_monitor() == watch.monitorIndex ||
windowRect.overlap(
global.display.get_monitor_geometry(watch.monitorIndex),
))
)
}
}

3006
taskbar.js

File diff suppressed because it is too large Load Diff

View File

@@ -15,238 +15,254 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import GdkPixbuf from 'gi://GdkPixbuf';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import St from 'gi://St';
import GdkPixbuf from 'gi://GdkPixbuf'
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
import St from 'gi://St'
import * as Proximity from './proximity.js';
import * as Utils from './utils.js';
import {SETTINGS} from './extension.js';
import * as Proximity from './proximity.js'
import * as Utils from './utils.js'
import { SETTINGS } from './extension.js'
export const DynamicTransparency = class {
constructor(dtpPanel) {
this._dtpPanel = dtpPanel
this._proximityManager = dtpPanel.panelManager.proximityManager
this._proximityWatchId = 0
this.currentBackgroundColor = 0
constructor(dtpPanel) {
this._dtpPanel = dtpPanel;
this._proximityManager = dtpPanel.panelManager.proximityManager;
this._proximityWatchId = 0;
this.currentBackgroundColor = 0;
this._initialPanelStyle = dtpPanel.panel.get_style()
this._initialPanelStyle = dtpPanel.panel.get_style();
this._signalsHandler = new Utils.GlobalSignalsHandler()
this._bindSignals()
this._signalsHandler = new Utils.GlobalSignalsHandler();
this._bindSignals();
this._updateAnimationDuration()
this._updateAllAndSet()
this._updateProximityWatch()
}
this._updateAnimationDuration();
this._updateAllAndSet();
this._updateProximityWatch();
destroy() {
this._signalsHandler.destroy()
this._proximityManager.removeWatch(this._proximityWatchId)
this._dtpPanel.panel.set_style(this._initialPanelStyle)
}
updateExternalStyle() {
this._updateComplementaryStyles()
this._setBackground()
}
_bindSignals() {
this._signalsHandler.add(
[Utils.getStageTheme(), 'changed', () => this._updateAllAndSet()],
[Main.overview, ['showing', 'hiding'], () => this._updateAlphaAndSet()],
[
SETTINGS,
['changed::trans-use-custom-bg', 'changed::trans-bg-color'],
() => this._updateColorAndSet(),
],
[
SETTINGS,
[
'changed::trans-use-custom-opacity',
'changed::trans-panel-opacity',
'changed::trans-bg-color',
'changed::trans-dynamic-anim-target',
'changed::trans-use-dynamic-opacity',
],
() => this._updateAlphaAndSet(),
],
[
SETTINGS,
[
'changed::trans-use-custom-gradient',
'changed::trans-gradient-top-color',
'changed::trans-gradient-bottom-color',
'changed::trans-gradient-top-opacity',
'changed::trans-gradient-bottom-opacity',
],
() => this._updateGradientAndSet(),
],
[
SETTINGS,
[
'changed::trans-dynamic-behavior',
'changed::trans-use-dynamic-opacity',
'changed::trans-dynamic-distance',
],
() => this._updateProximityWatch(),
],
[
SETTINGS,
'changed::trans-dynamic-anim-time',
() => this._updateAnimationDuration(),
],
)
}
_updateProximityWatch() {
this._proximityManager.removeWatch(this._proximityWatchId)
if (SETTINGS.get_boolean('trans-use-dynamic-opacity')) {
let isVertical = this._dtpPanel.checkIfVertical()
let threshold = SETTINGS.get_int('trans-dynamic-distance')
this._windowOverlap = false
this._updateAlphaAndSet()
this._proximityWatchId = this._proximityManager.createWatch(
this._dtpPanel.panelBox.get_parent(),
this._dtpPanel.monitor.index,
Proximity.Mode[SETTINGS.get_string('trans-dynamic-behavior')],
isVertical ? threshold : 0,
isVertical ? 0 : threshold,
(overlap) => {
this._windowOverlap = overlap
this._updateAlphaAndSet()
},
)
}
}
_updateAnimationDuration() {
this.animationDuration =
SETTINGS.get_int('trans-dynamic-anim-time') * 0.001 + 's;'
}
_updateAllAndSet() {
let themeBackground = this._getThemeBackground(true)
this._updateColor(themeBackground)
this._updateAlpha(themeBackground)
this._updateComplementaryStyles()
this._updateGradient()
this._setBackground()
this._setGradient()
}
_updateColorAndSet() {
this._updateColor()
this._setBackground()
}
_updateAlphaAndSet() {
this._updateAlpha()
this._setBackground()
}
_updateGradientAndSet() {
this._updateGradient()
this._setGradient()
}
_updateComplementaryStyles() {
let panelThemeNode = this._dtpPanel.panel.get_theme_node()
this._complementaryStyles =
'border-radius: ' + panelThemeNode.get_border_radius(0) + 'px;'
}
_updateColor(themeBackground) {
this.backgroundColorRgb = SETTINGS.get_boolean('trans-use-custom-bg')
? SETTINGS.get_string('trans-bg-color')
: themeBackground || this._getThemeBackground()
}
_updateAlpha(themeBackground) {
if (
this._windowOverlap &&
!Main.overview.visibleTarget &&
SETTINGS.get_boolean('trans-use-dynamic-opacity')
) {
this.alpha = SETTINGS.get_double('trans-dynamic-anim-target')
} else {
this.alpha = SETTINGS.get_boolean('trans-use-custom-opacity')
? SETTINGS.get_double('trans-panel-opacity')
: (themeBackground || this._getThemeBackground()).alpha * 0.003921569 // 1 / 255 = 0.003921569
}
}
_updateGradient() {
this._gradientStyle = ''
if (SETTINGS.get_boolean('trans-use-custom-gradient')) {
this._gradientStyle +=
'background-gradient-direction: ' +
(this._dtpPanel.checkIfVertical() ? 'horizontal;' : 'vertical;') +
'background-gradient-start: ' +
Utils.getrgbaColor(
SETTINGS.get_string('trans-gradient-top-color'),
SETTINGS.get_double('trans-gradient-top-opacity'),
) +
'background-gradient-end: ' +
Utils.getrgbaColor(
SETTINGS.get_string('trans-gradient-bottom-color'),
SETTINGS.get_double('trans-gradient-bottom-opacity'),
)
}
}
_setBackground() {
this.currentBackgroundColor = Utils.getrgbaColor(
this.backgroundColorRgb,
this.alpha,
)
let transition = 'transition-duration:' + this.animationDuration
this._dtpPanel.set_style(
'background-color: ' +
this.currentBackgroundColor +
transition +
this._complementaryStyles,
)
}
_setGradient() {
this._dtpPanel.panel.set_style(
'background: none; ' +
'border-image: none; ' +
'background-image: none; ' +
this._gradientStyle +
'transition-duration:' +
this.animationDuration,
)
}
_getThemeBackground(reload) {
if (reload || !this._themeBackground) {
let fakePanel = new St.Bin({ name: 'panel' })
Main.uiGroup.add_child(fakePanel)
let fakeTheme = fakePanel.get_theme_node()
this._themeBackground =
this._getBackgroundImageColor(fakeTheme) ||
fakeTheme.get_background_color()
Main.uiGroup.remove_child(fakePanel)
}
destroy() {
this._signalsHandler.destroy();
this._proximityManager.removeWatch(this._proximityWatchId);
return this._themeBackground
}
this._dtpPanel.panel.set_style(this._initialPanelStyle);
}
_getBackgroundImageColor(theme) {
let bg = null
updateExternalStyle() {
this._updateComplementaryStyles();
this._setBackground();
}
try {
let imageFile =
theme.get_background_image() || theme.get_border_image().get_file()
_bindSignals() {
this._signalsHandler.add(
[
Utils.getStageTheme(),
'changed',
() => this._updateAllAndSet()
],
[
Main.overview,
[
'showing',
'hiding'
],
() => this._updateAlphaAndSet()
],
[
SETTINGS,
[
'changed::trans-use-custom-bg',
'changed::trans-bg-color'
],
() => this._updateColorAndSet()
],
[
SETTINGS,
[
'changed::trans-use-custom-opacity',
'changed::trans-panel-opacity',
'changed::trans-bg-color',
'changed::trans-dynamic-anim-target',
'changed::trans-use-dynamic-opacity'
],
() => this._updateAlphaAndSet()
],
[
SETTINGS,
[
'changed::trans-use-custom-gradient',
'changed::trans-gradient-top-color',
'changed::trans-gradient-bottom-color',
'changed::trans-gradient-top-opacity',
'changed::trans-gradient-bottom-opacity'
],
() => this._updateGradientAndSet()
],
[
SETTINGS,
[
'changed::trans-dynamic-behavior',
'changed::trans-use-dynamic-opacity',
'changed::trans-dynamic-distance'
],
() => this._updateProximityWatch()
],
[
SETTINGS,
'changed::trans-dynamic-anim-time',
() => this._updateAnimationDuration()
]
);
}
if (imageFile) {
let imageBuf = GdkPixbuf.Pixbuf.new_from_file(imageFile.get_path())
let pixels = imageBuf.get_pixels()
_updateProximityWatch() {
this._proximityManager.removeWatch(this._proximityWatchId);
if (SETTINGS.get_boolean('trans-use-dynamic-opacity')) {
let isVertical = this._dtpPanel.checkIfVertical();
let threshold = SETTINGS.get_int('trans-dynamic-distance');
this._windowOverlap = false;
this._updateAlphaAndSet()
this._proximityWatchId = this._proximityManager.createWatch(
this._dtpPanel.panelBox.get_parent(),
this._dtpPanel.monitor.index,
Proximity.Mode[SETTINGS.get_string('trans-dynamic-behavior')],
isVertical ? threshold : 0,
isVertical ? 0 : threshold,
overlap => {
this._windowOverlap = overlap;
this._updateAlphaAndSet();
}
);
bg = {
red: pixels[0],
green: pixels[1],
blue: pixels[2],
alpha: pixels[3],
}
}
}
} catch (error) {}
_updateAnimationDuration() {
this.animationDuration = (SETTINGS.get_int('trans-dynamic-anim-time') * 0.001) + 's;';
}
_updateAllAndSet() {
let themeBackground = this._getThemeBackground(true);
this._updateColor(themeBackground);
this._updateAlpha(themeBackground);
this._updateComplementaryStyles();
this._updateGradient();
this._setBackground();
this._setGradient();
}
_updateColorAndSet() {
this._updateColor();
this._setBackground();
}
_updateAlphaAndSet() {
this._updateAlpha();
this._setBackground();
}
_updateGradientAndSet() {
this._updateGradient();
this._setGradient();
}
_updateComplementaryStyles() {
let panelThemeNode = this._dtpPanel.panel.get_theme_node();
this._complementaryStyles = 'border-radius: ' + panelThemeNode.get_border_radius(0) + 'px;';
}
_updateColor(themeBackground) {
this.backgroundColorRgb = SETTINGS.get_boolean('trans-use-custom-bg') ?
SETTINGS.get_string('trans-bg-color') :
(themeBackground || this._getThemeBackground());
}
_updateAlpha(themeBackground) {
if (this._windowOverlap && !Main.overview.visibleTarget && SETTINGS.get_boolean('trans-use-dynamic-opacity')) {
this.alpha = SETTINGS.get_double('trans-dynamic-anim-target');
} else {
this.alpha = SETTINGS.get_boolean('trans-use-custom-opacity') ?
SETTINGS.get_double('trans-panel-opacity') :
(themeBackground || this._getThemeBackground()).alpha * 0.003921569; // 1 / 255 = 0.003921569
}
}
_updateGradient() {
this._gradientStyle = '';
if (SETTINGS.get_boolean('trans-use-custom-gradient')) {
this._gradientStyle += 'background-gradient-direction: ' + (this._dtpPanel.checkIfVertical() ? 'horizontal;' : 'vertical;') +
'background-gradient-start: ' + Utils.getrgbaColor(SETTINGS.get_string('trans-gradient-top-color'),
SETTINGS.get_double('trans-gradient-top-opacity')) +
'background-gradient-end: ' + Utils.getrgbaColor(SETTINGS.get_string('trans-gradient-bottom-color'),
SETTINGS.get_double('trans-gradient-bottom-opacity'));
}
}
_setBackground() {
this.currentBackgroundColor = Utils.getrgbaColor(this.backgroundColorRgb, this.alpha);
let transition = 'transition-duration:' + this.animationDuration;
this._dtpPanel.set_style('background-color: ' + this.currentBackgroundColor + transition + this._complementaryStyles);
}
_setGradient() {
this._dtpPanel.panel.set_style(
'background: none; ' +
'border-image: none; ' +
'background-image: none; ' +
this._gradientStyle +
'transition-duration:' + this.animationDuration
);
}
_getThemeBackground(reload) {
if (reload || !this._themeBackground) {
let fakePanel = new St.Bin({ name: 'panel' });
Main.uiGroup.add_child(fakePanel);
let fakeTheme = fakePanel.get_theme_node()
this._themeBackground = this._getBackgroundImageColor(fakeTheme) || fakeTheme.get_background_color();
Main.uiGroup.remove_child(fakePanel);
}
return this._themeBackground;
}
_getBackgroundImageColor(theme) {
let bg = null;
try {
let imageFile = theme.get_background_image() || theme.get_border_image().get_file();
if (imageFile) {
let imageBuf = GdkPixbuf.Pixbuf.new_from_file(imageFile.get_path());
let pixels = imageBuf.get_pixels();
bg = { red: pixels[0], green: pixels[1], blue: pixels[2], alpha: pixels[3] };
}
} catch (error) {}
return bg;
}
return bg
}
}

1497
utils.js

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

583
yarn.lock Normal file
View File

@@ -0,0 +1,583 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.1"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56"
integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==
dependencies:
eslint-visitor-keys "^3.4.3"
"@eslint-community/regexpp@^4.12.1":
version "4.12.1"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
"@eslint/config-array@^0.19.0":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.1.tgz#734aaea2c40be22bbb1f2a9dac687c57a6a4c984"
integrity sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==
dependencies:
"@eslint/object-schema" "^2.1.5"
debug "^4.3.1"
minimatch "^3.1.2"
"@eslint/core@^0.10.0":
version "0.10.0"
resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.10.0.tgz#23727063c21b335f752dbb3a16450f6f9cbc9091"
integrity sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==
dependencies:
"@types/json-schema" "^7.0.15"
"@eslint/eslintrc@^3.2.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c"
integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
espree "^10.0.1"
globals "^14.0.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
js-yaml "^4.1.0"
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@eslint/js@9.19.0", "@eslint/js@^9.19.0":
version "9.19.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.19.0.tgz#51dbb140ed6b49d05adc0b171c41e1a8713b7789"
integrity sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==
"@eslint/object-schema@^2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.5.tgz#8670a8f6258a2be5b2c620ff314a1d984c23eb2e"
integrity sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==
"@eslint/plugin-kit@^0.2.5":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz#ee07372035539e7847ef834e3f5e7b79f09e3a81"
integrity sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==
dependencies:
"@eslint/core" "^0.10.0"
levn "^0.4.1"
"@humanfs/core@^0.19.1":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==
"@humanfs/node@^0.16.6":
version "0.16.6"
resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e"
integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==
dependencies:
"@humanfs/core" "^0.19.1"
"@humanwhocodes/retry" "^0.3.0"
"@humanwhocodes/module-importer@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
"@humanwhocodes/retry@^0.3.0":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
"@humanwhocodes/retry@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b"
integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==
"@types/estree@^1.0.6":
version "1.0.6"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50"
integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==
"@types/json-schema@^7.0.15":
version "7.0.15"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
acorn-jsx@^5.3.2:
version "5.3.2"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn@^8.14.0:
version "8.14.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0"
integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ansi-styles@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
chalk@^4.0.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
dependencies:
color-name "~1.1.4"
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
cross-spawn@^7.0.6:
version "7.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
debug@^4.3.1, debug@^4.3.2:
version "4.4.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
dependencies:
ms "^2.1.3"
deep-is@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
eslint-config-prettier@^10.0.1:
version "10.0.1"
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz#fbb03bfc8db0651df9ce4e8b7150d11c5fe3addf"
integrity sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==
eslint-scope@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442"
integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-visitor-keys@^3.4.3:
version "3.4.3"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
eslint-visitor-keys@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
eslint@^9.19.0:
version "9.19.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.19.0.tgz#ffa1d265fc4205e0f8464330d35f09e1d548b1bf"
integrity sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.12.1"
"@eslint/config-array" "^0.19.0"
"@eslint/core" "^0.10.0"
"@eslint/eslintrc" "^3.2.0"
"@eslint/js" "9.19.0"
"@eslint/plugin-kit" "^0.2.5"
"@humanfs/node" "^0.16.6"
"@humanwhocodes/module-importer" "^1.0.1"
"@humanwhocodes/retry" "^0.4.1"
"@types/estree" "^1.0.6"
"@types/json-schema" "^7.0.15"
ajv "^6.12.4"
chalk "^4.0.0"
cross-spawn "^7.0.6"
debug "^4.3.2"
escape-string-regexp "^4.0.0"
eslint-scope "^8.2.0"
eslint-visitor-keys "^4.2.0"
espree "^10.3.0"
esquery "^1.5.0"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
file-entry-cache "^8.0.0"
find-up "^5.0.0"
glob-parent "^6.0.2"
ignore "^5.2.0"
imurmurhash "^0.1.4"
is-glob "^4.0.0"
json-stable-stringify-without-jsonify "^1.0.1"
lodash.merge "^4.6.2"
minimatch "^3.1.2"
natural-compare "^1.4.0"
optionator "^0.9.3"
espree@^10.0.1, espree@^10.3.0:
version "10.3.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a"
integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==
dependencies:
acorn "^8.14.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^4.2.0"
esquery@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
dependencies:
estraverse "^5.1.0"
esrecurse@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
dependencies:
estraverse "^5.2.0"
estraverse@^5.1.0, estraverse@^5.2.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-levenshtein@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
file-entry-cache@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f"
integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==
dependencies:
flat-cache "^4.0.0"
find-up@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
dependencies:
locate-path "^6.0.0"
path-exists "^4.0.0"
flat-cache@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c"
integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==
dependencies:
flatted "^3.2.9"
keyv "^4.5.4"
flatted@^3.2.9:
version "3.3.2"
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27"
integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==
glob-parent@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
dependencies:
is-glob "^4.0.3"
globals@^14.0.0:
version "14.0.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
globals@^15.14.0:
version "15.14.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-15.14.0.tgz#b8fd3a8941ff3b4d38f3319d433b61bbb482e73f"
integrity sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
ignore@^5.2.0:
version "5.3.2"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
import-fresh@^3.2.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
dependencies:
parent-module "^1.0.0"
resolve-from "^4.0.0"
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-glob@^4.0.0, is-glob@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
json-buffer@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
keyv@^4.5.4:
version "4.5.4"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
dependencies:
json-buffer "3.0.1"
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
dependencies:
prelude-ls "^1.2.1"
type-check "~0.4.0"
locate-path@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
dependencies:
p-locate "^5.0.0"
lodash.merge@^4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
ms@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
optionator@^0.9.3:
version "0.9.4"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734"
integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==
dependencies:
deep-is "^0.1.3"
fast-levenshtein "^2.0.6"
levn "^0.4.1"
prelude-ls "^1.2.1"
type-check "^0.4.0"
word-wrap "^1.2.5"
p-limit@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
dependencies:
yocto-queue "^0.1.0"
p-locate@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
dependencies:
p-limit "^3.0.2"
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
dependencies:
callsites "^3.0.0"
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prettier@^3.4.2:
version "3.4.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f"
integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==
punycode@^2.1.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
strip-json-comments@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
supports-color@^7.1.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
dependencies:
prelude-ls "^1.2.1"
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
word-wrap@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==