mirror of
https://github.com/morgan9e/dash-to-panel
synced 2026-04-14 00:04:17 +09:00
Merge branch 'master' of https://github.com/home-sweet-gnome/dash-to-panel into panel-border
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -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
5
.prettierrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"semi": false,
|
||||
"arrowParens": "always",
|
||||
"singleQuote": true
|
||||
}
|
||||
13
Makefile
13
Makefile
@@ -1,16 +1,19 @@
|
||||
# Basic Makefile
|
||||
|
||||
UUID = dash-to-panel@jderose9.github.com
|
||||
MODULES = ./*.js stylesheet.css metadata.json COPYING README.md
|
||||
MODULES = src/*.js src/stylesheet.css metadata.json COPYING README.md
|
||||
UI_MODULES = ui/*.ui
|
||||
IMAGES = ./* ../media/design/svg/dash-to-panel-logo-light.svg
|
||||
|
||||
TOLOCALIZE = prefs.js appIcons.js taskbar.js
|
||||
TOLOCALIZE = src/extension.js src/prefs.js src/appIcons.js src/taskbar.js
|
||||
MSGSRC = $(wildcard po/*.po)
|
||||
ifeq ($(strip $(DESTDIR)),)
|
||||
INSTALLTYPE = local
|
||||
INSTALLBASE = $(HOME)/.local/share/gnome-shell/extensions
|
||||
else
|
||||
INSTALLTYPE = system
|
||||
INSTALLBASE = $(DESTDIR)/usr/share/gnome-shell/extensions
|
||||
SHARE_PREFIX = $(DESTDIR)/usr/share
|
||||
endif
|
||||
INSTALLNAME = dash-to-panel@jderose9.github.com
|
||||
|
||||
@@ -69,6 +72,12 @@ install-local: _build
|
||||
rm -rf $(INSTALLBASE)/$(INSTALLNAME)
|
||||
mkdir -p $(INSTALLBASE)/$(INSTALLNAME)
|
||||
cp -r ./_build/* $(INSTALLBASE)/$(INSTALLNAME)/
|
||||
ifeq ($(INSTALLTYPE),system)
|
||||
rm -r $(INSTALLBASE)/$(INSTALLNAME)/schemas $(INSTALLBASE)/$(INSTALLNAME)/locale
|
||||
mkdir -p $(SHARE_PREFIX)/glib-2.0/schemas $(SHARE_PREFIX)/locale
|
||||
cp -r ./schemas/*gschema.* $(SHARE_PREFIX)/glib-2.0/schemas
|
||||
cp -r ./_build/locale/* $(SHARE_PREFIX)/locale
|
||||
endif
|
||||
-rm -fR _build
|
||||
echo done
|
||||
|
||||
|
||||
@@ -175,15 +175,18 @@ Ideas for recursing child actors and assigning inline styles are based on code f
|
||||
- @philippun1 for GNOME 40 support :rocket:
|
||||
- @HaselLoyance for toggle for notification counter badge
|
||||
- @rastersoft for Desktop Icons NG integration
|
||||
- @max-dw-i for symbolic icons
|
||||
- @Hirnmoder for Beautify DTP
|
||||
- @JimBroad for grayscale icons
|
||||
|
||||
#### Bug Fixes:
|
||||
@imrvelj, @Teslator, @bil-elmoussaoui, @brandon-schumann, @sw9, @rockon999 , @lexruee, @3v1n0, @freeroot, @moqmar, @ArtyomZorin, @lkc0987, @saibotk, @vanillajonathan, @Zkdc, @leebickmtu, @l3nn4rt, @Melix19, @Aikatsui, @melix99, @kyrillzorin, @oneshadab, @CorvetteCole, @vantu5z, @spectreseven1138
|
||||
@imrvelj, @Teslator, @bil-elmoussaoui, @brandon-schumann, @sw9, @rockon999 , @lexruee, @3v1n0, @freeroot, @moqmar, @ArtyomZorin, @lkc0987, @saibotk, @vanillajonathan, @Zkdc, @leebickmtu, @l3nn4rt, @Melix19, @Aikatsui, @melix99, @kyrillzorin, @oneshadab, @CorvetteCole, @vantu5z, @spectreseven1138, @aperezdc, @smedir, @lucaxvi, @andyholmes, @vowstar, @T99Rots, @City-busz, @guoqiyi, @gcrabbe, @Anduin2017, @xalt7x, @Survolog
|
||||
|
||||
#### Documentation Improvements:
|
||||
@BoQsc, @zakkak, @dandv
|
||||
@BoQsc, @zakkak, @dandv, @elliotwutingfeng
|
||||
|
||||
#### Translations:
|
||||
@frnogueira / @victorwpbastos / @vagkaefer (pt_BR), @zeten30 (cs), @franglais125 / @calotam / @oeramirez (es), @LaurentTreguier / @SolarLiner (fr), @elsieholmes (uk), @hosiet (zh\_CN), @jonnius / @linuxr01 / @daPhipz (de), @urbalazs / @pappfer (hu), @crayxt (kk), @pkomur / @MartinPL / @alex4401 (pl), @AlexGluck / @GoodNike / @rjapolov / @vantu5z (ru), @sicklylife-jp / @ryonakano / @nexryai (ja), @oltulu / @TeknoMobil / @daenney (tr), @sbadux / @kowalski7cc / @l3nn4rt (it), @OriginCode / @pan93412 (zh\_TW), @ojn (sv), @frandieguez (gl), @kuroehanako / @MarongHappy (ko)
|
||||
@frnogueira / @victorwpbastos / @vagkaefer (pt_BR), @zeten30 / @Amereyeu (cs), @franglais125 / @calotam / @oeramirez / @jhonatanseminario / @oscfdezdz (es), @LaurentTreguier / @SolarLiner / @DelphinPETER (fr), @elsieholmes / @xalt7x (uk), @hosiet / @zhmars (zh\_CN), @jonnius / @linuxr01 / @Etamuk / @daPhipz (de), @urbalazs / @pappfer (hu), @crayxt (kk), @pkomur / @MartinPL / @alex4401 / @konradmb / @alewicki95 / @0rzech (pl), @AlexGluck / @GoodNike / @rjapolov / @vantu5z / @Keleth (ru), @sicklylife-jp / @ryonakano / @nexryai / @Umoxfo (ja), @oltulu / @TeknoMobil / @daenney (tr), @sbadux / @kowalski7cc / @l3nn4rt / @albanobattistella (it), @OriginCode / @pan93412 (zh\_TW), @ojn (sv), @frandieguez (gl), @kuroehanako / @MarongHappy (ko), @jose1711 / @dodog (sk), @eshagh79 (fa)
|
||||
|
||||
|
||||
##
|
||||
|
||||
1927
appIcons.js
1927
appIcons.js
File diff suppressed because it is too large
Load Diff
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* The code in this file is distributed under a "1-clause BSD license",
|
||||
* which makes it compatible with GPLv2 and GPLv3 too, and others.
|
||||
*
|
||||
* License text:
|
||||
*
|
||||
* Copyright (C) 2021 Sergio Costas (rastersoft@gmail.com)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* Integration class
|
||||
*
|
||||
* This class must be added to other extensions in order to integrate
|
||||
* them with Desktop Icons NG. It allows an extension to notify how much margin
|
||||
* it uses in each side of each monitor.
|
||||
*
|
||||
* DON'T SEND PATCHES TO THIS FILE TO THE EXTENSION MAINTAINER. SEND THEM TO
|
||||
* DESKTOP ICONS NG MAINTAINER: https://gitlab.com/rastersoft/desktop-icons-ng
|
||||
*
|
||||
* In the *enable()* function, create a *DesktopIconsUsableAreaClass()*
|
||||
* object with
|
||||
*
|
||||
* new DesktopIconsIntegration.DesktopIconsUsableAreaClass(object);
|
||||
*
|
||||
* Now, in the *disable()* function just call to the *destroy()* method before
|
||||
* nullifying the pointer. You must create a new object in enable() the next
|
||||
* time the extension is enabled.
|
||||
*
|
||||
* In your code, every time you change the margins, you should call first to
|
||||
* *resetMargins()* method to clear the current margins, and then call to
|
||||
* *setMargins(...)* method as many times as you need to set the margins in each
|
||||
* monitor. You don't need to call it for all the monitors, only for those where
|
||||
* you are painting something. If you don't set values for a monitor, they will
|
||||
* be considered zero.
|
||||
*
|
||||
* The margins values are relative to the monitor border.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
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";
|
||||
|
||||
export class DesktopIconsUsableAreaClass {
|
||||
_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;
|
||||
|
||||
// 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 (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
9
eslint.config.js
Normal 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,
|
||||
]
|
||||
130
extension.js
130
extension.js
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Dash-To-Panel extension for Gnome 3
|
||||
* Copyright 2016 Jason DeRose (jderose9) and Charles Gagnon (charlesg99)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
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 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;
|
||||
|
||||
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);
|
||||
|
||||
this._realHasOverview = Main.sessionMode.hasOverview;
|
||||
|
||||
//create an object that persists until gnome-shell is restarted, even if the extension is disabled
|
||||
PERSISTENTSTORAGE = {};
|
||||
}
|
||||
|
||||
enable() {
|
||||
DTP_EXTENSION = this;
|
||||
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
|
||||
//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();
|
||||
}
|
||||
|
||||
if (startupCompleteHandler) {
|
||||
Main.layoutManager.disconnect(startupCompleteHandler);
|
||||
startupCompleteHandler = null;
|
||||
}
|
||||
|
||||
Main.sessionMode.hasOverview = this._realHasOverview;
|
||||
}
|
||||
}
|
||||
|
||||
function _enable(extension) {
|
||||
let enabled = global.settings.get_strv('enabled-extensions');
|
||||
|
||||
if (enabled?.indexOf(UBUNTU_DOCK_UUID) >= 0)
|
||||
extensionSystem.disableExtension(UBUNTU_DOCK_UUID);
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
// 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', '')
|
||||
|
||||
panelManager = new PanelManager.PanelManager();
|
||||
|
||||
panelManager.enable();
|
||||
}
|
||||
48
img/zorin-os.svg
Normal file
48
img/zorin-os.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 18 KiB |
427
intellihide.js
427
intellihide.js
@@ -1,427 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* 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 * 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';
|
||||
|
||||
//timeout intervals
|
||||
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 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
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
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.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();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this._setRevealMechanism();
|
||||
this._queueUpdatePanelPosition();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
"uuid": "dash-to-panel@jderose9.github.com",
|
||||
"name": "Dash to Panel",
|
||||
"description": "An icon taskbar for the Gnome Shell. This extension moves the dash into the gnome main panel so that the application launchers and system tray are combined into a single panel, similar to that found in KDE Plasma and Windows 7+. A separate dock is no longer needed for easy access to running and favorited applications.\n\nFor a more traditional experience, you may also want to use Tweak Tool to enable Windows > Titlebar Buttons > Minimize & Maximize.\n\nFor the best support, please report any issues on Github. Dash-to-panel is developed and maintained by @jderose9 and @charlesg99.",
|
||||
"shell-version": [ "46", "47" ],
|
||||
"shell-version": [ "46", "47", "48" ],
|
||||
"url": "https://github.com/home-sweet-gnome/dash-to-panel",
|
||||
"gettext-domain": "dash-to-panel",
|
||||
"version": 9999,
|
||||
|
||||
518
overview.js
518
overview.js
@@ -1,518 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 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-';
|
||||
|
||||
// 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;
|
||||
|
||||
//timeout names
|
||||
const T1 = 'swipeEndTimeout';
|
||||
const T2 = 'numberOverlayTimeout';
|
||||
|
||||
export const Overview = class {
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
let visibilityFunc = visible ? 'show' : 'hide';
|
||||
let height = visible ? -1 : LABEL_MARGIN * Utils.getScaleFactor();
|
||||
let overviewControls = Main.overview._overview._controls;
|
||||
|
||||
overviewControls.dash[visibilityFunc]();
|
||||
overviewControls.dash.set_height(height);
|
||||
}
|
||||
|
||||
_adaptAlloc() {
|
||||
let overviewControls = Main.overview._overview._controls
|
||||
|
||||
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
|
||||
|
||||
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 (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)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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())
|
||||
]);
|
||||
}
|
||||
|
||||
let disable = () => {
|
||||
this._signalsHandler.removeWithLabel(label);
|
||||
this._injectionsHandler.removeWithLabel(label);
|
||||
}
|
||||
|
||||
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 (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);
|
||||
}
|
||||
|
||||
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;
|
||||
if (SETTINGS.get_boolean('overview-click-to-exit'))
|
||||
this._enableClickToExit();
|
||||
|
||||
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;
|
||||
|
||||
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.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()
|
||||
}
|
||||
]);
|
||||
|
||||
this._clickToExitEnabled = true;
|
||||
}
|
||||
|
||||
_disableClickToExit() {
|
||||
if (!this._clickToExitEnabled)
|
||||
return;
|
||||
|
||||
this._signalsHandler.removeWithLabel('click-to-exit')
|
||||
|
||||
this._clickToExitEnabled = false;
|
||||
}
|
||||
|
||||
_onSwipeBegin() {
|
||||
this._swiping = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
_onSwipeEnd() {
|
||||
this._timeoutsHandler.add([
|
||||
T1,
|
||||
0,
|
||||
() => this._swiping = false
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
13
package.json
Normal file
13
package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
781
panelManager.js
781
panelManager.js
@@ -1,781 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Credits:
|
||||
* This file is based on code from the Dash to Dock extension by micheleg
|
||||
* and code from the Taskbar extension by Zorin OS
|
||||
*
|
||||
* Code to re-anchor the panel was taken from Thoma5 BottomPanel:
|
||||
* https://github.com/Thoma5/gnome-shell-extension-bottompanel
|
||||
*
|
||||
* Pattern for moving clock based on Frippery Move Clock by R M Yorston
|
||||
* http://frippery.org/extensions/
|
||||
*
|
||||
* Some code was also adapted from the upstream Gnome Shell source code.
|
||||
*/
|
||||
|
||||
import * as Overview from './overview.js';
|
||||
import * as Panel from './panel.js';
|
||||
import * as PanelSettings from './panelSettings.js';
|
||||
import * as Proximity from './proximity.js';
|
||||
import * as Utils from './utils.js';
|
||||
import * as DesktopIconsIntegration from './desktopIconsIntegration.js';
|
||||
|
||||
import GLib from 'gi://GLib';
|
||||
import GObject from 'gi://GObject';
|
||||
import Clutter from 'gi://Clutter';
|
||||
import Meta from 'gi://Meta';
|
||||
import Shell from 'gi://Shell';
|
||||
import St from 'gi://St';
|
||||
|
||||
import * as BoxPointer from 'resource:///org/gnome/shell/ui/boxpointer.js';
|
||||
import * as LookingGlass from 'resource:///org/gnome/shell/ui/lookingGlass.js';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
|
||||
import * as Layout from 'resource:///org/gnome/shell/ui/layout.js';
|
||||
import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||
import {SETTINGS} from './extension.js';
|
||||
import {SecondaryMonitorDisplay, WorkspacesView} from 'resource:///org/gnome/shell/ui/workspacesView.js';
|
||||
|
||||
|
||||
export const PanelManager = class {
|
||||
|
||||
constructor() {
|
||||
this.overview = new Overview.Overview();
|
||||
this.panelsElementPositions = {};
|
||||
this._injectionManager = new InjectionManager();
|
||||
|
||||
this._saveMonitors();
|
||||
}
|
||||
|
||||
enable(reset) {
|
||||
let dtpPrimaryIndex = SETTINGS.get_int('primary-monitor');
|
||||
|
||||
this.allPanels = [];
|
||||
this.dtpPrimaryMonitor = Main.layoutManager.monitors[dtpPrimaryIndex] || Main.layoutManager.primaryMonitor;
|
||||
this.proximityManager = new Proximity.ProximityManager();
|
||||
|
||||
if (this.dtpPrimaryMonitor) {
|
||||
this.primaryPanel = this._createPanel(this.dtpPrimaryMonitor, SETTINGS.get_boolean('stockgs-keep-top-panel'));
|
||||
this.allPanels.push(this.primaryPanel);
|
||||
this.overview.enable(this.primaryPanel);
|
||||
|
||||
this.setFocusedMonitor(this.dtpPrimaryMonitor);
|
||||
}
|
||||
|
||||
if (SETTINGS.get_boolean('multi-monitors')) {
|
||||
Main.layoutManager.monitors.filter(m => m != this.dtpPrimaryMonitor).forEach(m => {
|
||||
this.allPanels.push(this._createPanel(m, true));
|
||||
});
|
||||
}
|
||||
|
||||
global.dashToPanel.panels = this.allPanels;
|
||||
global.dashToPanel.emit('panels-created');
|
||||
|
||||
this.allPanels.forEach(p => {
|
||||
let panelPosition = p.getPosition();
|
||||
let leftOrRight = (panelPosition == St.Side.LEFT || panelPosition == St.Side.RIGHT);
|
||||
|
||||
p.panelBox.set_size(
|
||||
leftOrRight ? -1 : p.geom.w + p.geom.lrPadding,
|
||||
leftOrRight ? p.geom.h + p.geom.tbPadding : -1
|
||||
);
|
||||
|
||||
this._findPanelMenuButtons(p.panelBox).forEach(pmb => this._adjustPanelMenuButton(pmb, p.monitor, panelPosition));
|
||||
|
||||
p.taskbar.iconAnimator.start();
|
||||
});
|
||||
|
||||
this._setDesktopIconsMargins();
|
||||
//in 3.32, BoxPointer now inherits St.Widget
|
||||
if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) {
|
||||
let panelManager = this;
|
||||
|
||||
this._injectionManager.overrideMethod(BoxPointer.BoxPointer.prototype, 'vfunc_get_preferred_height', () => function(forWidth) {
|
||||
let alloc = { min_size: 0, natural_size: 0 };
|
||||
|
||||
[alloc.min_size, alloc.natural_size] = this.vfunc_get_preferred_height(forWidth);
|
||||
|
||||
return panelManager._getBoxPointerPreferredHeight(this, alloc);
|
||||
});
|
||||
}
|
||||
|
||||
this._updatePanelElementPositions();
|
||||
|
||||
if (reset) return;
|
||||
|
||||
this._desktopIconsUsableArea = new DesktopIconsIntegration.DesktopIconsUsableAreaClass();
|
||||
|
||||
this._oldUpdatePanelBarrier = Main.layoutManager._updatePanelBarrier;
|
||||
Main.layoutManager._updatePanelBarrier = (panel) => {
|
||||
let panelUpdates = panel ? [panel] : this.allPanels;
|
||||
|
||||
panelUpdates.forEach(p => newUpdatePanelBarrier.call(Main.layoutManager, p));
|
||||
};
|
||||
Main.layoutManager._updatePanelBarrier();
|
||||
|
||||
this._oldUpdateHotCorners = Main.layoutManager._updateHotCorners;
|
||||
Main.layoutManager._updateHotCorners = newUpdateHotCorners.bind(Main.layoutManager);
|
||||
Main.layoutManager._updateHotCorners();
|
||||
|
||||
this._forceHotCornerId = SETTINGS.connect('changed::stockgs-force-hotcorner', () => Main.layoutManager._updateHotCorners());
|
||||
|
||||
if (Main.layoutManager._interfaceSettings) {
|
||||
this._enableHotCornersId = Main.layoutManager._interfaceSettings.connect('changed::enable-hot-corners', () => Main.layoutManager._updateHotCorners());
|
||||
}
|
||||
|
||||
this._oldUpdateWorkspacesViews = Main.overview._overview._controls._workspacesDisplay._updateWorkspacesViews;
|
||||
Main.overview._overview._controls._workspacesDisplay._updateWorkspacesViews = this._newUpdateWorkspacesViews.bind(Main.overview._overview._controls._workspacesDisplay);
|
||||
|
||||
this._oldSetPrimaryWorkspaceVisible = Main.overview._overview._controls._workspacesDisplay.setPrimaryWorkspaceVisible
|
||||
Main.overview._overview._controls._workspacesDisplay.setPrimaryWorkspaceVisible = this._newSetPrimaryWorkspaceVisible.bind(Main.overview._overview._controls._workspacesDisplay);
|
||||
|
||||
LookingGlass.LookingGlass.prototype._oldResize = LookingGlass.LookingGlass.prototype._resize;
|
||||
LookingGlass.LookingGlass.prototype._resize = _newLookingGlassResize;
|
||||
|
||||
LookingGlass.LookingGlass.prototype._oldOpen = LookingGlass.LookingGlass.prototype.open;
|
||||
LookingGlass.LookingGlass.prototype.open = _newLookingGlassOpen;
|
||||
|
||||
this._signalsHandler = new Utils.GlobalSignalsHandler();
|
||||
|
||||
//listen settings
|
||||
this._signalsHandler.add(
|
||||
[
|
||||
SETTINGS,
|
||||
[
|
||||
'changed::primary-monitor',
|
||||
'changed::multi-monitors',
|
||||
'changed::isolate-monitors',
|
||||
'changed::panel-positions',
|
||||
'changed::panel-lengths',
|
||||
'changed::panel-anchors',
|
||||
'changed::stockgs-keep-top-panel'
|
||||
],
|
||||
() => this._reset()
|
||||
],
|
||||
[
|
||||
SETTINGS,
|
||||
'changed::panel-element-positions',
|
||||
() => this._updatePanelElementPositions()
|
||||
],
|
||||
[
|
||||
SETTINGS,
|
||||
'changed::intellihide-key-toggle-text',
|
||||
() => this._setKeyBindings(true)
|
||||
],
|
||||
[
|
||||
SETTINGS,
|
||||
'changed::panel-sizes',
|
||||
() => {
|
||||
GLib.idle_add(GLib.PRIORITY_LOW, () => {
|
||||
this._setDesktopIconsMargins();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
Utils.DisplayWrapper.getMonitorManager(),
|
||||
'monitors-changed',
|
||||
() => {
|
||||
if (Main.layoutManager.primaryMonitor) {
|
||||
this._saveMonitors();
|
||||
this._reset();
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
Panel.panelBoxes.forEach(c => this._signalsHandler.add(
|
||||
[
|
||||
Main.panel[c],
|
||||
'child-added',
|
||||
(parent, child) => {
|
||||
this.primaryPanel &&
|
||||
child instanceof St.Bin &&
|
||||
this._adjustPanelMenuButton(this._getPanelMenuButton(child.get_first_child()), this.primaryPanel.monitor, this.primaryPanel.getPosition())
|
||||
}
|
||||
]
|
||||
));
|
||||
|
||||
this._setKeyBindings(true);
|
||||
|
||||
// keep GS overview.js from blowing away custom panel styles
|
||||
if(!SETTINGS.get_boolean('stockgs-keep-top-panel'))
|
||||
Object.defineProperty(Main.panel, "style", {configurable: true, set(v) {}});
|
||||
}
|
||||
|
||||
disable(reset) {
|
||||
this.primaryPanel && this.overview.disable();
|
||||
this.proximityManager.destroy();
|
||||
|
||||
this.allPanels.forEach(p => {
|
||||
p.taskbar.iconAnimator.pause();
|
||||
|
||||
this._findPanelMenuButtons(p.panelBox).forEach(pmb => {
|
||||
if (pmb.menu._boxPointer._dtpGetPreferredHeightId) {
|
||||
pmb.menu._boxPointer._container.disconnect(pmb.menu._boxPointer._dtpGetPreferredHeightId);
|
||||
}
|
||||
|
||||
pmb.menu._boxPointer.sourceActor = pmb.menu._boxPointer._dtpSourceActor;
|
||||
delete pmb.menu._boxPointer._dtpSourceActor;
|
||||
pmb.menu._boxPointer._userArrowSide = St.Side.TOP;
|
||||
})
|
||||
|
||||
this._removePanelBarriers(p);
|
||||
|
||||
p.disable();
|
||||
|
||||
let clipContainer = p.panelBox.get_parent();
|
||||
|
||||
Main.layoutManager._untrackActor(p.panelBox);
|
||||
Main.layoutManager.removeChrome(clipContainer);
|
||||
|
||||
if (p.isStandalone) {
|
||||
p.panelBox.destroy();
|
||||
} else {
|
||||
p.panelBox.remove_child(p);
|
||||
p.remove_child(p.panel);
|
||||
p.panelBox.add_child(p.panel);
|
||||
|
||||
p.panelBox.set_position(clipContainer.x, clipContainer.y);
|
||||
|
||||
clipContainer.remove_child(p.panelBox);
|
||||
Main.layoutManager.addChrome(p.panelBox, { affectsStruts: true, trackFullscreen: true });
|
||||
}
|
||||
});
|
||||
|
||||
this._injectionManager.clear();
|
||||
|
||||
if (Main.layoutManager.primaryMonitor) {
|
||||
Main.layoutManager.panelBox.set_position(Main.layoutManager.primaryMonitor.x, Main.layoutManager.primaryMonitor.y);
|
||||
Main.layoutManager.panelBox.set_size(Main.layoutManager.primaryMonitor.width, -1);
|
||||
}
|
||||
|
||||
if (reset) return;
|
||||
|
||||
this._setKeyBindings(false);
|
||||
|
||||
this._signalsHandler.destroy();
|
||||
|
||||
Main.layoutManager._updateHotCorners = this._oldUpdateHotCorners;
|
||||
Main.layoutManager._updateHotCorners();
|
||||
|
||||
SETTINGS.disconnect(this._forceHotCornerId);
|
||||
|
||||
if (this._enableHotCornersId) {
|
||||
Main.layoutManager._interfaceSettings.disconnect(this._enableHotCornersId);
|
||||
}
|
||||
|
||||
Main.layoutManager._updatePanelBarrier = this._oldUpdatePanelBarrier;
|
||||
Main.layoutManager._updatePanelBarrier();
|
||||
|
||||
Main.overview._overview._controls._workspacesDisplay._updateWorkspacesViews = this._oldUpdateWorkspacesViews;
|
||||
Main.overview._overview._controls._workspacesDisplay.setPrimaryWorkspaceVisible = this._oldSetPrimaryWorkspaceVisible;
|
||||
|
||||
LookingGlass.LookingGlass.prototype._resize = LookingGlass.LookingGlass.prototype._oldResize;
|
||||
delete LookingGlass.LookingGlass.prototype._oldResize;
|
||||
|
||||
LookingGlass.LookingGlass.prototype.open = LookingGlass.LookingGlass.prototype._oldOpen;
|
||||
delete LookingGlass.LookingGlass.prototype._oldOpen
|
||||
|
||||
delete Main.panel.style;
|
||||
this._desktopIconsUsableArea.destroy();
|
||||
this._desktopIconsUsableArea = null;
|
||||
}
|
||||
|
||||
_setDesktopIconsMargins() {
|
||||
this._desktopIconsUsableArea?.resetMargins();
|
||||
this.allPanels.forEach(p => {
|
||||
switch(p.geom.position) {
|
||||
case St.Side.TOP:
|
||||
this._desktopIconsUsableArea?.setMargins(p.monitor.index, p.geom.h, 0, 0, 0);
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
this._desktopIconsUsableArea?.setMargins(p.monitor.index, 0, p.geom.h, 0, 0);
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
this._desktopIconsUsableArea?.setMargins(p.monitor.index, 0, 0, p.geom.w, 0);
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
this._desktopIconsUsableArea?.setMargins(p.monitor.index, 0, 0, 0, p.geom.w);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setFocusedMonitor(monitor) {
|
||||
this.focusedMonitorPanel = this.allPanels.find(p => p.monitor == monitor)
|
||||
|
||||
if (!this.checkIfFocusedMonitor(monitor)) {
|
||||
Main.overview._overview.clear_constraints();
|
||||
Main.overview._overview.add_constraint(new Layout.MonitorConstraint({ index: monitor.index }));
|
||||
|
||||
Main.overview._overview._controls._workspacesDisplay._primaryIndex = monitor.index;
|
||||
|
||||
// https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2395
|
||||
// The overview allocation used to calculate its workarea based on the monitor where the overview
|
||||
// was displayed, but it got changed back to always use the primary monitor. So now, temporarily assign
|
||||
// the primary monitor to dtp focused monitor while recalculating the overview workarea
|
||||
Main.layoutManager.primaryMonitor = monitor
|
||||
Main.overview._overview._controls.layout_manager._updateWorkAreaBox()
|
||||
Main.layoutManager.primaryMonitor = Main.layoutManager.monitors[Main.layoutManager.primaryIndex]
|
||||
}
|
||||
}
|
||||
|
||||
_newSetPrimaryWorkspaceVisible(visible) {
|
||||
if (this._primaryVisible === visible)
|
||||
return;
|
||||
|
||||
this._primaryVisible = visible;
|
||||
|
||||
const primaryIndex = Main.overview._overview._controls._workspacesDisplay._primaryIndex;
|
||||
const primaryWorkspace = this._workspacesViews[primaryIndex];
|
||||
if (primaryWorkspace)
|
||||
primaryWorkspace.visible = visible;
|
||||
}
|
||||
|
||||
_newUpdateWorkspacesViews() {
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
this._workspacesViews[i].destroy();
|
||||
|
||||
this._workspacesViews = [];
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let view;
|
||||
if (i === this._primaryIndex) {
|
||||
view = new WorkspacesView(i,
|
||||
this._controls,
|
||||
this._scrollAdjustment,
|
||||
this._fitModeAdjustment,
|
||||
this._overviewAdjustment);
|
||||
|
||||
view.visible = this._primaryVisible;
|
||||
this.bind_property('opacity', view, 'opacity', GObject.BindingFlags.SYNC_CREATE);
|
||||
this.add_child(view);
|
||||
} else {
|
||||
// No idea why atm, but we need the import at the top of this file and to use the
|
||||
// full imports ns here, otherwise SecondaryMonitorDisplay can't be used ¯\_(ツ)_/¯
|
||||
view = new SecondaryMonitorDisplay(i,
|
||||
this._controls,
|
||||
this._scrollAdjustment,
|
||||
this._fitModeAdjustment,
|
||||
this._overviewAdjustment);
|
||||
Main.layoutManager.overviewGroup.add_child(view);
|
||||
}
|
||||
|
||||
this._workspacesViews.push(view);
|
||||
}
|
||||
}
|
||||
|
||||
_saveMonitors() {
|
||||
//Mutter meta_monitor_manager_get_primary_monitor (global.display.get_primary_monitor()) doesn't return the same
|
||||
//monitor as GDK gdk_screen_get_primary_monitor (imports.gi.Gdk.Screen.get_default().get_primary_monitor()).
|
||||
//Since the Mutter function is what's used in gnome-shell and we can't access it from the settings dialog, store
|
||||
//the monitors information in a setting so we can use the same monitor indexes as the ones in gnome-shell
|
||||
let keyMonitors = 'available-monitors';
|
||||
let keyPrimary = 'primary-monitor';
|
||||
let primaryIndex = Main.layoutManager.primaryIndex;
|
||||
let newMonitors = [primaryIndex];
|
||||
let savedMonitors = SETTINGS.get_value(keyMonitors).deep_unpack();
|
||||
let dtpPrimaryIndex = SETTINGS.get_int(keyPrimary);
|
||||
let newDtpPrimaryIndex = primaryIndex;
|
||||
|
||||
Main.layoutManager.monitors.filter(m => m.index != primaryIndex).forEach(m => newMonitors.push(m.index));
|
||||
|
||||
if (savedMonitors[0] != dtpPrimaryIndex) {
|
||||
// dash to panel primary wasn't the gnome-shell primary (first index of available-monitors)
|
||||
let savedIndex = savedMonitors.indexOf(dtpPrimaryIndex)
|
||||
|
||||
// default to primary if it was set to a monitor that is no longer available
|
||||
newDtpPrimaryIndex = newMonitors[savedIndex];
|
||||
newDtpPrimaryIndex = newDtpPrimaryIndex == null ? primaryIndex : newDtpPrimaryIndex;
|
||||
}
|
||||
|
||||
SETTINGS.set_int(keyPrimary, newDtpPrimaryIndex);
|
||||
SETTINGS.set_value(keyMonitors, new GLib.Variant('ai', newMonitors));
|
||||
}
|
||||
|
||||
checkIfFocusedMonitor(monitor) {
|
||||
return Main.overview._overview._controls._workspacesDisplay._primaryIndex == monitor.index;
|
||||
}
|
||||
|
||||
_createPanel(monitor, isStandalone) {
|
||||
let panelBox;
|
||||
let panel;
|
||||
let clipContainer = new Clutter.Actor();
|
||||
|
||||
if (isStandalone) {
|
||||
panelBox = new St.BoxLayout({ name: 'panelBox' });
|
||||
} else {
|
||||
panelBox = Main.layoutManager.panelBox;
|
||||
Main.layoutManager._untrackActor(panelBox);
|
||||
panelBox.remove_child(Main.panel);
|
||||
Main.layoutManager.removeChrome(panelBox);
|
||||
}
|
||||
|
||||
Main.layoutManager.addChrome(clipContainer, { affectsInputRegion: false });
|
||||
clipContainer.add_child(panelBox);
|
||||
Main.layoutManager.trackChrome(panelBox, { trackFullscreen: true, affectsStruts: true, affectsInputRegion: true });
|
||||
|
||||
panel = new Panel.Panel(this, monitor, panelBox, isStandalone);
|
||||
panelBox.add_child(panel);
|
||||
panel.enable();
|
||||
|
||||
panelBox.visible = true;
|
||||
if (monitor.inFullscreen) {
|
||||
panelBox.hide();
|
||||
}
|
||||
panelBox.set_position(0, 0);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
_reset() {
|
||||
this.disable(true);
|
||||
this.allPanels = [];
|
||||
this.enable(true);
|
||||
}
|
||||
|
||||
_updatePanelElementPositions() {
|
||||
this.panelsElementPositions = PanelSettings.getSettingsJson(SETTINGS, 'panel-element-positions');
|
||||
this.allPanels.forEach(p => p.updateElementPositions());
|
||||
}
|
||||
|
||||
_adjustPanelMenuButton(button, monitor, arrowSide) {
|
||||
if (button) {
|
||||
button.menu._boxPointer._dtpSourceActor = button.menu._boxPointer.sourceActor;
|
||||
button.menu._boxPointer.sourceActor = button;
|
||||
button.menu._boxPointer._userArrowSide = arrowSide;
|
||||
button.menu._boxPointer._dtpInPanel = 1;
|
||||
|
||||
if (!button.menu._boxPointer.vfunc_get_preferred_height) {
|
||||
button.menu._boxPointer._dtpGetPreferredHeightId = button.menu._boxPointer._container.connect('get-preferred-height', (actor, forWidth, alloc) => {
|
||||
this._getBoxPointerPreferredHeight(button.menu._boxPointer, alloc, monitor);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_getBoxPointerPreferredHeight(boxPointer, alloc, monitor) {
|
||||
if (boxPointer._dtpInPanel && boxPointer.sourceActor && SETTINGS.get_boolean('intellihide')) {
|
||||
monitor = monitor || Main.layoutManager.findMonitorForActor(boxPointer.sourceActor);
|
||||
let panel = Utils.find(global.dashToPanel.panels, p => p.monitor == monitor);
|
||||
let excess = alloc.natural_size + panel.dtpSize + 10 - monitor.height; // 10 is arbitrary
|
||||
|
||||
if (excess > 0) {
|
||||
alloc.natural_size -= excess;
|
||||
}
|
||||
}
|
||||
|
||||
return [alloc.min_size, alloc.natural_size];
|
||||
}
|
||||
|
||||
_findPanelMenuButtons(container) {
|
||||
let panelMenuButtons = [];
|
||||
let panelMenuButton;
|
||||
|
||||
let find = parent => parent.get_children().forEach(c => {
|
||||
if ((panelMenuButton = this._getPanelMenuButton(c))) {
|
||||
panelMenuButtons.push(panelMenuButton);
|
||||
}
|
||||
|
||||
find(c);
|
||||
});
|
||||
|
||||
find(container);
|
||||
|
||||
return panelMenuButtons;
|
||||
}
|
||||
|
||||
_removePanelBarriers(panel) {
|
||||
if (panel.isStandalone && panel._rightPanelBarrier) {
|
||||
panel._rightPanelBarrier.destroy();
|
||||
}
|
||||
|
||||
if (panel._leftPanelBarrier) {
|
||||
panel._leftPanelBarrier.destroy();
|
||||
delete panel._leftPanelBarrier;
|
||||
}
|
||||
}
|
||||
|
||||
_getPanelMenuButton(obj) {
|
||||
return obj instanceof PanelMenu.Button && obj.menu?._boxPointer ? obj : 0;
|
||||
}
|
||||
|
||||
_setKeyBindings(enable) {
|
||||
let keys = {
|
||||
'intellihide-key-toggle': () => this.allPanels.forEach(p => p.intellihide.toggle())
|
||||
};
|
||||
|
||||
Object.keys(keys).forEach(k => {
|
||||
Utils.removeKeybinding(k);
|
||||
|
||||
if (enable) {
|
||||
Utils.addKeybinding(k, SETTINGS, keys[k], Shell.ActionMode.NORMAL);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// This class drives long-running icon animations, to keep them running in sync
|
||||
// with each other.
|
||||
export const IconAnimator = class {
|
||||
|
||||
constructor(actor) {
|
||||
this._count = 0;
|
||||
this._started = false;
|
||||
this._animations = {
|
||||
dance: [],
|
||||
};
|
||||
this._timeline = new Clutter.Timeline({
|
||||
duration: 3000,
|
||||
repeat_count: -1,
|
||||
});
|
||||
|
||||
/* Just use the construction property when no need to support 3.36 */
|
||||
if (this._timeline.set_actor)
|
||||
this._timeline.set_actor(actor);
|
||||
|
||||
this._timeline.connect('new-frame', () => {
|
||||
const progress = this._timeline.get_progress();
|
||||
const danceRotation = progress < 1/6 ? 15*Math.sin(progress*24*Math.PI) : 0;
|
||||
const dancers = this._animations.dance;
|
||||
for (let i = 0, iMax = dancers.length; i < iMax; i++) {
|
||||
dancers[i].target.rotation_angle_z = danceRotation;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._timeline.stop();
|
||||
this._timeline = null;
|
||||
for (let name in this._animations) {
|
||||
const pairs = this._animations[name];
|
||||
for (let i = 0, iMax = pairs.length; i < iMax; i++) {
|
||||
const pair = pairs[i];
|
||||
pair.target.disconnect(pair.targetDestroyId);
|
||||
}
|
||||
}
|
||||
this._animations = null;
|
||||
}
|
||||
|
||||
pause() {
|
||||
if (this._started && this._count > 0) {
|
||||
this._timeline.stop();
|
||||
}
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
start() {
|
||||
if (!this._started && this._count > 0) {
|
||||
this._timeline.start();
|
||||
}
|
||||
this._started = true;
|
||||
}
|
||||
|
||||
addAnimation(target, name) {
|
||||
const targetDestroyId = target.connect('destroy', () => this.removeAnimation(target, name));
|
||||
this._animations[name].push({ target: target, targetDestroyId: targetDestroyId });
|
||||
if (this._started && this._count === 0) {
|
||||
this._timeline.start();
|
||||
}
|
||||
this._count++;
|
||||
}
|
||||
|
||||
removeAnimation(target, name) {
|
||||
const pairs = this._animations[name];
|
||||
for (let i = 0, iMax = pairs.length; i < iMax; i++) {
|
||||
const pair = pairs[i];
|
||||
if (pair.target === target) {
|
||||
target.disconnect(pair.targetDestroyId);
|
||||
pairs.splice(i, 1);
|
||||
this._count--;
|
||||
if (this._started && this._count === 0) {
|
||||
this._timeline.stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function newUpdateHotCorners() {
|
||||
// destroy old hot corners
|
||||
this.hotCorners.forEach(function(corner) {
|
||||
if (corner)
|
||||
corner.destroy();
|
||||
});
|
||||
this.hotCorners = [];
|
||||
|
||||
//global.settings is ubuntu specific setting to disable the hot corner (Tweak tool > Top Bar > Activities Overview Hot Corner)
|
||||
//this._interfaceSettings is for the setting to disable the hot corner introduced in gnome-shell 3.34
|
||||
if ((global.settings.list_keys().indexOf('enable-hot-corners') >= 0 && !global.settings.get_boolean('enable-hot-corners')) ||
|
||||
(this._interfaceSettings && !this._interfaceSettings.get_boolean('enable-hot-corners'))) {
|
||||
this.emit('hot-corners-changed');
|
||||
return;
|
||||
}
|
||||
|
||||
// build new hot corners
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
let panel = Utils.find(global.dashToPanel.panels, p => p.monitor.index == i);
|
||||
let panelPosition = panel ? panel.getPosition() : St.Side.BOTTOM;
|
||||
let panelTopLeft = panelPosition == St.Side.TOP || panelPosition == St.Side.LEFT;
|
||||
let monitor = this.monitors[i];
|
||||
let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x;
|
||||
let cornerY = monitor.y;
|
||||
|
||||
let haveTopLeftCorner = true;
|
||||
|
||||
// If the panel is on the bottom, unless this is explicitly forced, don't add a topleft
|
||||
// hot corner unless it is actually a top left panel. Otherwise, it stops the mouse
|
||||
// as you are dragging across. In the future, maybe we will automatically move the
|
||||
// hotcorner to the bottom when the panel is positioned at the bottom
|
||||
if (i != this.primaryIndex || (!panelTopLeft && !SETTINGS.get_boolean('stockgs-force-hotcorner'))) {
|
||||
// Check if we have a top left (right for RTL) corner.
|
||||
// I.e. if there is no monitor directly above or to the left(right)
|
||||
let besideX = this._rtl ? monitor.x + 1 : cornerX - 1;
|
||||
let besideY = cornerY;
|
||||
let aboveX = cornerX;
|
||||
let aboveY = cornerY - 1;
|
||||
|
||||
for (let j = 0; j < this.monitors.length; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
let otherMonitor = this.monitors[j];
|
||||
if (besideX >= otherMonitor.x &&
|
||||
besideX < otherMonitor.x + otherMonitor.width &&
|
||||
besideY >= otherMonitor.y &&
|
||||
besideY < otherMonitor.y + otherMonitor.height) {
|
||||
haveTopLeftCorner = false;
|
||||
break;
|
||||
}
|
||||
if (aboveX >= otherMonitor.x &&
|
||||
aboveX < otherMonitor.x + otherMonitor.width &&
|
||||
aboveY >= otherMonitor.y &&
|
||||
aboveY < otherMonitor.y + otherMonitor.height) {
|
||||
haveTopLeftCorner = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (haveTopLeftCorner) {
|
||||
let corner = new Layout.HotCorner(this, monitor, cornerX, cornerY);
|
||||
|
||||
corner.setBarrierSize = size => Object.getPrototypeOf(corner).setBarrierSize.call(corner, Math.min(size, 32));
|
||||
corner.setBarrierSize(panel ? panel.dtpSize : 32);
|
||||
this.hotCorners.push(corner);
|
||||
} else {
|
||||
this.hotCorners.push(null);
|
||||
}
|
||||
}
|
||||
|
||||
this.emit('hot-corners-changed');
|
||||
}
|
||||
|
||||
function newUpdatePanelBarrier(panel) {
|
||||
let barriers = {
|
||||
_rightPanelBarrier: [(panel.isStandalone ? panel : this)],
|
||||
_leftPanelBarrier: [panel]
|
||||
};
|
||||
|
||||
Object.keys(barriers).forEach(k => {
|
||||
let obj = barriers[k][0];
|
||||
|
||||
if (obj[k]) {
|
||||
obj[k].destroy();
|
||||
obj[k] = null;
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.primaryMonitor || !panel.panelBox.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
let barrierSize = Math.min(10, panel.panelBox.height);
|
||||
let fixed1 = panel.monitor.y;
|
||||
let fixed2 = panel.monitor.y + barrierSize;
|
||||
|
||||
if (panel.checkIfVertical()) {
|
||||
barriers._rightPanelBarrier.push(panel.monitor.y + panel.monitor.height, Meta.BarrierDirection.NEGATIVE_Y);
|
||||
barriers._leftPanelBarrier.push(panel.monitor.y, Meta.BarrierDirection.POSITIVE_Y);
|
||||
} else {
|
||||
barriers._rightPanelBarrier.push(panel.monitor.x + panel.monitor.width, Meta.BarrierDirection.NEGATIVE_X);
|
||||
barriers._leftPanelBarrier.push(panel.monitor.x, Meta.BarrierDirection.POSITIVE_X);
|
||||
}
|
||||
|
||||
switch (panel.getPosition()) {
|
||||
//values are initialized as St.Side.TOP
|
||||
case St.Side.BOTTOM:
|
||||
fixed1 = panel.monitor.y + panel.monitor.height - barrierSize;
|
||||
fixed2 = panel.monitor.y + panel.monitor.height;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
fixed1 = panel.monitor.x + barrierSize;
|
||||
fixed2 = panel.monitor.x;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
fixed1 = panel.monitor.x + panel.monitor.width - barrierSize;
|
||||
fixed2 = panel.monitor.x + panel.monitor.width;
|
||||
break;
|
||||
}
|
||||
|
||||
//remove left barrier if it overlaps one of the hotcorners
|
||||
for (let k in this.hotCorners) {
|
||||
let hc = this.hotCorners[k];
|
||||
|
||||
if (hc && hc._monitor == panel.monitor &&
|
||||
((fixed1 == hc._x || fixed2 == hc._x) || fixed1 == hc._y || fixed2 == hc._y)) {
|
||||
delete barriers._leftPanelBarrier;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(barriers).forEach(k => {
|
||||
let barrierOptions = {
|
||||
backend: global.backend,
|
||||
directions: barriers[k][2]
|
||||
};
|
||||
|
||||
barrierOptions[panel.varCoord.c1] = barrierOptions[panel.varCoord.c2] = barriers[k][1];
|
||||
barrierOptions[panel.fixedCoord.c1] = fixed1;
|
||||
barrierOptions[panel.fixedCoord.c2] = fixed2;
|
||||
|
||||
barriers[k][0][k] = new Meta.Barrier(barrierOptions);
|
||||
});
|
||||
}
|
||||
|
||||
function _newLookingGlassResize() {
|
||||
let primaryMonitorPanel = Utils.find(global.dashToPanel.panels, p => p.monitor == Main.layoutManager.primaryMonitor);
|
||||
let topOffset = primaryMonitorPanel.getPosition() == St.Side.TOP ? primaryMonitorPanel.dtpSize + 8 : 32;
|
||||
|
||||
this._oldResize();
|
||||
|
||||
this._hiddenY = Main.layoutManager.primaryMonitor.y + topOffset - this.height;
|
||||
this._targetY = this._hiddenY + this.height;
|
||||
this.y = this._hiddenY;
|
||||
|
||||
this._objInspector.set_position(this.x + Math.floor(this.width * 0.1), this._targetY + Math.floor(this.height * 0.1));
|
||||
}
|
||||
|
||||
function _newLookingGlassOpen() {
|
||||
if (this._open)
|
||||
return;
|
||||
|
||||
this._resize();
|
||||
this._oldOpen();
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* 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 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 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 },
|
||||
];
|
||||
|
||||
export const optionDialogFunctions = {};
|
||||
|
||||
optionDialogFunctions[SHOW_APPS_BTN] = '_showShowAppsButtonOptions';
|
||||
optionDialogFunctions[DESKTOP_BTN] = '_showDesktopButtonOptions';
|
||||
|
||||
export function checkIfCentered(position) {
|
||||
return position == CENTERED || position == CENTERED_MONITOR;
|
||||
}
|
||||
111
panelSettings.js
111
panelSettings.js
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns length of panel on a specific monitor, as a whole number percent,
|
||||
* from settings. e.g. 100
|
||||
*/
|
||||
export function getPanelLength(settings, monitorIndex) {
|
||||
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);
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
314
panelStyle.js
314
panelStyle.js
@@ -1,314 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Credits:
|
||||
* Ideas for recursing child actors and assigning inline styles
|
||||
* are based on code from the StatusAreaHorizontalSpacing extension
|
||||
* https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension
|
||||
* mathematical.coffee@gmail.com
|
||||
*/
|
||||
|
||||
import * as Utils from './utils.js';
|
||||
import {SETTINGS} from './extension.js';
|
||||
|
||||
|
||||
export const PanelStyle = class {
|
||||
|
||||
enable(panel) {
|
||||
this.panel = panel;
|
||||
|
||||
this._applyStyles();
|
||||
|
||||
this._bindSettingsChanges();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
597
progress.js
597
progress.js
@@ -1,597 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Credits:
|
||||
* This file is based on code from the Dash to Dock extension by micheleg
|
||||
*/
|
||||
|
||||
import Cairo from 'cairo';
|
||||
import Gio from 'gi://Gio';
|
||||
import Clutter from 'gi://Clutter';
|
||||
import Pango from 'gi://Pango';
|
||||
import St from 'gi://St';
|
||||
import * as Utils from './utils.js';
|
||||
import {SETTINGS} from './extension.js';
|
||||
|
||||
import {EventEmitter} from 'resource:///org/gnome/shell/misc/signals.js';
|
||||
|
||||
|
||||
export const ProgressManager = class extends EventEmitter {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._entriesByDBusName = {};
|
||||
|
||||
this._launcher_entry_dbus_signal_id =
|
||||
Gio.DBus.session.signal_subscribe(null, // sender
|
||||
'com.canonical.Unity.LauncherEntry', // iface
|
||||
null, // member
|
||||
null, // path
|
||||
null, // arg0
|
||||
Gio.DBusSignalFlags.NONE,
|
||||
this._onEntrySignalReceived.bind(this));
|
||||
|
||||
this._dbus_name_owner_changed_signal_id =
|
||||
Gio.DBus.session.signal_subscribe('org.freedesktop.DBus', // sender
|
||||
'org.freedesktop.DBus', // interface
|
||||
'NameOwnerChanged', // member
|
||||
'/org/freedesktop/DBus', // path
|
||||
null, // arg0
|
||||
Gio.DBusSignalFlags.NONE,
|
||||
this._onDBusNameOwnerChanged.bind(this));
|
||||
|
||||
this._acquireUnityDBus();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._launcher_entry_dbus_signal_id) {
|
||||
Gio.DBus.session.signal_unsubscribe(this._launcher_entry_dbus_signal_id);
|
||||
}
|
||||
|
||||
if (this._dbus_name_owner_changed_signal_id) {
|
||||
Gio.DBus.session.signal_unsubscribe(this._dbus_name_owner_changed_signal_id);
|
||||
}
|
||||
|
||||
this._releaseUnityDBus();
|
||||
}
|
||||
|
||||
size() {
|
||||
return Object.keys(this._entriesByDBusName).length;
|
||||
}
|
||||
|
||||
lookupByDBusName(dbusName) {
|
||||
return this._entriesByDBusName.hasOwnProperty(dbusName) ? this._entriesByDBusName[dbusName] : null;
|
||||
}
|
||||
|
||||
lookupById(appId) {
|
||||
let ret = [];
|
||||
for (let dbusName in this._entriesByDBusName) {
|
||||
let entry = this._entriesByDBusName[dbusName];
|
||||
if (entry && entry.appId() == appId) {
|
||||
ret.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
addEntry(entry) {
|
||||
let existingEntry = this.lookupByDBusName(entry.dbusName());
|
||||
if (existingEntry) {
|
||||
existingEntry.update(entry);
|
||||
} else {
|
||||
this._entriesByDBusName[entry.dbusName()] = entry;
|
||||
this.emit('progress-entry-added', entry);
|
||||
}
|
||||
}
|
||||
|
||||
removeEntry(entry) {
|
||||
delete this._entriesByDBusName[entry.dbusName()]
|
||||
this.emit('progress-entry-removed', entry);
|
||||
}
|
||||
|
||||
_acquireUnityDBus() {
|
||||
if (!this._unity_bus_id) {
|
||||
Gio.DBus.session.own_name('com.canonical.Unity',
|
||||
Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
_releaseUnityDBus() {
|
||||
if (this._unity_bus_id) {
|
||||
Gio.DBus.session.unown_name(this._unity_bus_id);
|
||||
this._unity_bus_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_onEntrySignalReceived(connection, sender_name, object_path,
|
||||
interface_name, signal_name, parameters, user_data) {
|
||||
if (!parameters || !signal_name)
|
||||
return;
|
||||
|
||||
if (signal_name == 'Update') {
|
||||
if (!sender_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._handleUpdateRequest(sender_name, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
_onDBusNameOwnerChanged(connection, sender_name, object_path,
|
||||
interface_name, signal_name, parameters, user_data) {
|
||||
if (!parameters || !this.size())
|
||||
return;
|
||||
|
||||
let [name, before, after] = parameters.deep_unpack();
|
||||
|
||||
if (!after) {
|
||||
if (this._entriesByDBusName.hasOwnProperty(before)) {
|
||||
this.removeEntry(this._entriesByDBusName[before]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_handleUpdateRequest(senderName, parameters) {
|
||||
if (!senderName || !parameters) {
|
||||
return;
|
||||
}
|
||||
|
||||
let [appUri, properties] = parameters.deep_unpack();
|
||||
let appId = appUri.replace(/(^\w+:|^)\/\//, '');
|
||||
let entry = this.lookupByDBusName(senderName);
|
||||
|
||||
if (entry) {
|
||||
entry.setDBusName(senderName);
|
||||
entry.update(properties);
|
||||
} else {
|
||||
let entry = new AppProgress(senderName, appId, properties);
|
||||
this.addEntry(entry);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export class AppProgress extends EventEmitter {
|
||||
|
||||
constructor(dbusName, appId, properties) {
|
||||
super();
|
||||
|
||||
this._dbusName = dbusName;
|
||||
this._appId = appId;
|
||||
this._count = 0;
|
||||
this._countVisible = false;
|
||||
this._progress = 0.0;
|
||||
this._progressVisible = false;
|
||||
this._urgent = false;
|
||||
this.update(properties);
|
||||
}
|
||||
|
||||
appId() {
|
||||
return this._appId;
|
||||
}
|
||||
|
||||
dbusName() {
|
||||
return this._dbusName;
|
||||
}
|
||||
|
||||
count() {
|
||||
return this._count;
|
||||
}
|
||||
|
||||
setCount(count) {
|
||||
if (this._count != count) {
|
||||
this._count = count;
|
||||
this.emit('count-changed', this._count);
|
||||
}
|
||||
}
|
||||
|
||||
countVisible() {
|
||||
return this._countVisible;
|
||||
}
|
||||
|
||||
setCountVisible(countVisible) {
|
||||
if (this._countVisible != countVisible) {
|
||||
this._countVisible = countVisible;
|
||||
this.emit('count-visible-changed', this._countVisible);
|
||||
}
|
||||
}
|
||||
|
||||
progress() {
|
||||
return this._progress;
|
||||
}
|
||||
|
||||
setProgress(progress) {
|
||||
if (this._progress != progress) {
|
||||
this._progress = progress;
|
||||
this.emit('progress-changed', this._progress);
|
||||
}
|
||||
}
|
||||
|
||||
progressVisible() {
|
||||
return this._progressVisible;
|
||||
}
|
||||
|
||||
setProgressVisible(progressVisible) {
|
||||
if (this._progressVisible != progressVisible) {
|
||||
this._progressVisible = progressVisible;
|
||||
this.emit('progress-visible-changed', this._progressVisible);
|
||||
}
|
||||
}
|
||||
|
||||
urgent() {
|
||||
return this._urgent;
|
||||
}
|
||||
|
||||
setUrgent(urgent) {
|
||||
if (this._urgent != urgent) {
|
||||
this._urgent = urgent;
|
||||
this.emit('urgent-changed', this._urgent);
|
||||
}
|
||||
}
|
||||
|
||||
setDBusName(dbusName) {
|
||||
if (this._dbusName != dbusName) {
|
||||
let oldName = this._dbusName;
|
||||
this._dbusName = dbusName;
|
||||
this.emit('dbus-name-changed', oldName);
|
||||
}
|
||||
}
|
||||
|
||||
update(other) {
|
||||
if (other instanceof AppProgress) {
|
||||
this.setDBusName(other.dbusName())
|
||||
this.setCount(other.count());
|
||||
this.setCountVisible(other.countVisible());
|
||||
this.setProgress(other.progress());
|
||||
this.setProgressVisible(other.progressVisible())
|
||||
this.setUrgent(other.urgent());
|
||||
} else {
|
||||
for (let property in other) {
|
||||
if (other.hasOwnProperty(property)) {
|
||||
if (property == 'count') {
|
||||
this.setCount(other[property].get_int64());
|
||||
} else if (property == 'count-visible') {
|
||||
this.setCountVisible(SETTINGS.get_boolean('progress-show-count') && other[property].get_boolean());
|
||||
} else if (property == 'progress') {
|
||||
this.setProgress(other[property].get_double());
|
||||
} else if (property == 'progress-visible') {
|
||||
this.setProgressVisible(SETTINGS.get_boolean('progress-show-bar') && other[property].get_boolean());
|
||||
} else if (property == 'urgent') {
|
||||
this.setUrgent(other[property].get_boolean());
|
||||
} else {
|
||||
// Not implemented yet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ProgressIndicator = class {
|
||||
|
||||
constructor(source, progressManager) {
|
||||
this._source = source;
|
||||
this._progressManager = progressManager;
|
||||
this._signalsHandler = new Utils.GlobalSignalsHandler();
|
||||
|
||||
this._sourceDestroyId = this._source.connect('destroy', () => {
|
||||
this._signalsHandler.destroy();
|
||||
});
|
||||
|
||||
this._notificationBadgeLabel = new St.Label({ style_class: 'badge' });
|
||||
this._notificationBadgeBin = new St.Bin({
|
||||
child: this._notificationBadgeLabel, y: 2, x: 2
|
||||
});
|
||||
this._notificationBadgeLabel.add_style_class_name('notification-badge');
|
||||
this._notificationBadgeCount = 0;
|
||||
this._notificationBadgeBin.hide();
|
||||
|
||||
this._source._dtpIconContainer.add_child(this._notificationBadgeBin);
|
||||
this._source._dtpIconContainer.connect('notify::allocation', this.updateNotificationBadge.bind(this));
|
||||
|
||||
this._progressManagerEntries = [];
|
||||
this._progressManager.lookupById(this._source.app.id).forEach(
|
||||
(entry) => {
|
||||
this.insertEntry(entry);
|
||||
}
|
||||
);
|
||||
|
||||
this._signalsHandler.add([
|
||||
this._progressManager,
|
||||
'progress-entry-added',
|
||||
this._onEntryAdded.bind(this)
|
||||
], [
|
||||
this._progressManager,
|
||||
'progress-entry-removed',
|
||||
this._onEntryRemoved.bind(this)
|
||||
]);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._source.disconnect(this._sourceDestroyId);
|
||||
this._signalsHandler.destroy();
|
||||
}
|
||||
|
||||
_onEntryAdded(appProgress, entry) {
|
||||
if (!entry || !entry.appId())
|
||||
return;
|
||||
if (this._source && this._source.app && this._source.app.id == entry.appId()) {
|
||||
this.insertEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
_onEntryRemoved(appProgress, entry) {
|
||||
if (!entry || !entry.appId())
|
||||
return;
|
||||
|
||||
if (this._source && this._source.app && this._source.app.id == entry.appId()) {
|
||||
this.removeEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
updateNotificationBadge() {
|
||||
this._source.updateNumberOverlay(this._notificationBadgeBin);
|
||||
this._notificationBadgeLabel.clutter_text.ellipsize = Pango.EllipsizeMode.MIDDLE;
|
||||
}
|
||||
|
||||
_notificationBadgeCountToText(count) {
|
||||
if (count <= 9999) {
|
||||
return count.toString();
|
||||
} else if (count < 1e5) {
|
||||
let thousands = count / 1e3;
|
||||
return thousands.toFixed(1).toString() + "k";
|
||||
} else if (count < 1e6) {
|
||||
let thousands = count / 1e3;
|
||||
return thousands.toFixed(0).toString() + "k";
|
||||
} else if (count < 1e8) {
|
||||
let millions = count / 1e6;
|
||||
return millions.toFixed(1).toString() + "M";
|
||||
} else if (count < 1e9) {
|
||||
let millions = count / 1e6;
|
||||
return millions.toFixed(0).toString() + "M";
|
||||
} else {
|
||||
let billions = count / 1e9;
|
||||
return billions.toFixed(1).toString() + "B";
|
||||
}
|
||||
}
|
||||
|
||||
setNotificationBadge(count) {
|
||||
this._notificationBadgeCount = count;
|
||||
let text = this._notificationBadgeCountToText(count);
|
||||
this._notificationBadgeLabel.set_text(text);
|
||||
}
|
||||
|
||||
toggleNotificationBadge(activate) {
|
||||
if (activate && this._notificationBadgeCount > 0) {
|
||||
this.updateNotificationBadge();
|
||||
this._notificationBadgeBin.show();
|
||||
}
|
||||
else
|
||||
this._notificationBadgeBin.hide();
|
||||
}
|
||||
|
||||
_showProgressOverlay() {
|
||||
if (this._progressOverlayArea) {
|
||||
this._updateProgressOverlay();
|
||||
return;
|
||||
}
|
||||
|
||||
this._progressOverlayArea = new St.DrawingArea({x_expand: true, y_expand: true});
|
||||
this._progressOverlayArea.add_style_class_name('progress-bar');
|
||||
this._progressOverlayArea.connect('repaint', () => {
|
||||
this._drawProgressOverlay(this._progressOverlayArea);
|
||||
});
|
||||
|
||||
this._source._iconContainer.add_child(this._progressOverlayArea);
|
||||
let node = this._progressOverlayArea.get_theme_node();
|
||||
|
||||
let [hasColor, color] = node.lookup_color('-progress-bar-background', false);
|
||||
if (hasColor)
|
||||
this._progressbar_background = color
|
||||
else
|
||||
this._progressbar_background = new Utils.ColorUtils.Color({red: 204, green: 204, blue: 204, alpha: 255});
|
||||
|
||||
[hasColor, color] = node.lookup_color('-progress-bar-border', false);
|
||||
if (hasColor)
|
||||
this._progressbar_border = color;
|
||||
else
|
||||
this._progressbar_border = new Utils.ColorUtils.Color({red: 230, green: 230, blue: 230, alpha: 255});
|
||||
|
||||
this._updateProgressOverlay();
|
||||
}
|
||||
|
||||
_hideProgressOverlay() {
|
||||
if (this._progressOverlayArea)
|
||||
this._progressOverlayArea.destroy();
|
||||
|
||||
this._progressOverlayArea = null;
|
||||
this._progressbar_background = null;
|
||||
this._progressbar_border = null;
|
||||
}
|
||||
|
||||
_updateProgressOverlay() {
|
||||
|
||||
if (this._progressOverlayArea) {
|
||||
this._progressOverlayArea.queue_repaint();
|
||||
}
|
||||
}
|
||||
|
||||
_drawProgressOverlay(area) {
|
||||
let scaleFactor = Utils.getScaleFactor();
|
||||
let [surfaceWidth, surfaceHeight] = area.get_surface_size();
|
||||
let cr = area.get_context();
|
||||
|
||||
let iconSize = this._source.icon.iconSize * scaleFactor;
|
||||
|
||||
let x = Math.floor((surfaceWidth - iconSize) / 2);
|
||||
let y = Math.floor((surfaceHeight - iconSize) / 2);
|
||||
|
||||
let lineWidth = Math.floor(1.0 * scaleFactor);
|
||||
let padding = Math.floor(iconSize * 0.05);
|
||||
let width = iconSize - 2.0*padding;
|
||||
let height = Math.floor(Math.min(18.0*scaleFactor, 0.20*iconSize));
|
||||
x += padding;
|
||||
y += iconSize - height - padding;
|
||||
|
||||
cr.setLineWidth(lineWidth);
|
||||
|
||||
// Draw the outer stroke
|
||||
let stroke = new Cairo.LinearGradient(0, y, 0, y + height);
|
||||
let fill = null;
|
||||
stroke.addColorStopRGBA(0.5, 0.5, 0.5, 0.5, 0.1);
|
||||
stroke.addColorStopRGBA(0.9, 0.8, 0.8, 0.8, 0.4);
|
||||
Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill);
|
||||
|
||||
// Draw the background
|
||||
x += lineWidth;
|
||||
y += lineWidth;
|
||||
width -= 2.0*lineWidth;
|
||||
height -= 2.0*lineWidth;
|
||||
|
||||
stroke = Cairo.SolidPattern.createRGBA(0.20, 0.20, 0.20, 0.9);
|
||||
fill = new Cairo.LinearGradient(0, y, 0, y + height);
|
||||
fill.addColorStopRGBA(0.4, 0.25, 0.25, 0.25, 1.0);
|
||||
fill.addColorStopRGBA(0.9, 0.35, 0.35, 0.35, 1.0);
|
||||
Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill);
|
||||
|
||||
// Draw the finished bar
|
||||
x += lineWidth;
|
||||
y += lineWidth;
|
||||
width -= 2.0*lineWidth;
|
||||
height -= 2.0*lineWidth;
|
||||
|
||||
let finishedWidth = Math.ceil(this._progress * width);
|
||||
|
||||
let bg = this._progressbar_background;
|
||||
let bd = this._progressbar_border;
|
||||
|
||||
stroke = Cairo.SolidPattern.createRGBA(bd.red/255, bd.green/255, bd.blue/255, bd.alpha/255);
|
||||
fill = Cairo.SolidPattern.createRGBA(bg.red/255, bg.green/255, bg.blue/255, bg.alpha/255);
|
||||
|
||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||
Utils.drawRoundedLine(cr, x + lineWidth/2.0 + width - finishedWidth, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill);
|
||||
else
|
||||
Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill);
|
||||
|
||||
cr.$dispose();
|
||||
}
|
||||
|
||||
setProgress(progress) {
|
||||
this._progress = Math.min(Math.max(progress, 0.0), 1.0);
|
||||
this._updateProgressOverlay();
|
||||
}
|
||||
|
||||
toggleProgressOverlay(activate) {
|
||||
if (activate) {
|
||||
this._showProgressOverlay();
|
||||
}
|
||||
else {
|
||||
this._hideProgressOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
insertEntry(appProgress) {
|
||||
if (!appProgress || this._progressManagerEntries.indexOf(appProgress) !== -1)
|
||||
return;
|
||||
|
||||
this._progressManagerEntries.push(appProgress);
|
||||
this._selectEntry(appProgress);
|
||||
}
|
||||
|
||||
removeEntry(appProgress) {
|
||||
if (!appProgress || this._progressManagerEntries.indexOf(appProgress) == -1)
|
||||
return;
|
||||
|
||||
this._progressManagerEntries.splice(this._progressManagerEntries.indexOf(appProgress), 1);
|
||||
|
||||
if (this._progressManagerEntries.length > 0) {
|
||||
this._selectEntry(this._progressManagerEntries[this._progressManagerEntries.length-1]);
|
||||
} else {
|
||||
this.setNotificationBadge(0);
|
||||
this.toggleNotificationBadge(false);
|
||||
this.setProgress(0);
|
||||
this.toggleProgressOverlay(false);
|
||||
this.setUrgent(false);
|
||||
}
|
||||
}
|
||||
|
||||
_selectEntry(appProgress) {
|
||||
if (!appProgress)
|
||||
return;
|
||||
|
||||
this._signalsHandler.removeWithLabel('progress-entry');
|
||||
|
||||
this._signalsHandler.addWithLabel('progress-entry',
|
||||
[
|
||||
appProgress,
|
||||
'count-changed',
|
||||
(appProgress, value) => {
|
||||
this.setNotificationBadge(value);
|
||||
}
|
||||
], [
|
||||
appProgress,
|
||||
'count-visible-changed',
|
||||
(appProgress, value) => {
|
||||
this.toggleNotificationBadge(value);
|
||||
}
|
||||
], [
|
||||
appProgress,
|
||||
'progress-changed',
|
||||
(appProgress, value) => {
|
||||
this.setProgress(value);
|
||||
}
|
||||
], [
|
||||
appProgress,
|
||||
'progress-visible-changed',
|
||||
(appProgress, value) => {
|
||||
this.toggleProgressOverlay(value);
|
||||
}
|
||||
], [
|
||||
appProgress,
|
||||
'urgent-changed',
|
||||
(appProgress, value) => {
|
||||
this.setUrgent(value)
|
||||
}
|
||||
]);
|
||||
|
||||
this.setNotificationBadge(appProgress.count());
|
||||
this.toggleNotificationBadge(appProgress.countVisible());
|
||||
this.setProgress(appProgress.progress());
|
||||
this.toggleProgressOverlay(appProgress.progressVisible());
|
||||
|
||||
this._isUrgent = false;
|
||||
}
|
||||
|
||||
setUrgent(urgent) {
|
||||
const icon = this._source.icon._iconBin;
|
||||
if (urgent) {
|
||||
if (!this._isUrgent) {
|
||||
icon.set_pivot_point(0.5, 0.5);
|
||||
this._source.iconAnimator.addAnimation(icon, 'dance');
|
||||
this._isUrgent = true;
|
||||
}
|
||||
} else {
|
||||
if (this._isUrgent) {
|
||||
this._source.iconAnimator.removeAnimation(icon, 'dance');
|
||||
this._isUrgent = false;
|
||||
}
|
||||
icon.rotation_angle_z = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
256
proximity.js
256
proximity.js
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Meta from 'gi://Meta';
|
||||
import Mtk from 'gi://Mtk';
|
||||
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
import * as Utils from './utils.js';
|
||||
|
||||
//timeout intervals
|
||||
const MIN_UPDATE_MS = 200;
|
||||
|
||||
//timeout names
|
||||
const T1 = 'limitUpdateTimeout';
|
||||
|
||||
export const Mode = {
|
||||
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;
|
||||
|
||||
this._allocationChangedId = actor.connect('notify::allocation', () => this._updateWatchRect());
|
||||
|
||||
this._updateWatchRect();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.actor.disconnect(this._allocationChangedId);
|
||||
}
|
||||
|
||||
_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
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const ProximityManager = class {
|
||||
|
||||
constructor() {
|
||||
this._counter = 1;
|
||||
this._watches = {};
|
||||
this._focusedWindowInfo = null;
|
||||
|
||||
this._signalsHandler = new Utils.GlobalSignalsHandler();
|
||||
this._timeoutsHandler = new Utils.TimeoutsHandler();
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
this._queueUpdate(true);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_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)));
|
||||
}
|
||||
};
|
||||
@@ -23,6 +23,7 @@
|
||||
<value value='5' nick='QUIT'/>
|
||||
<value value='6' nick='TOGGLE-SHOWPREVIEW'/>
|
||||
<value value='7' nick='TOGGLE-CYCLE'/>
|
||||
<value value='8' nick='TOGGLE-SPREAD'/>
|
||||
</enum>
|
||||
<enum id='org.gnome.shell.extensions.dash-to-panel.scrollAction'>
|
||||
<value value='0' nick='NOTHING'/>
|
||||
@@ -91,7 +92,7 @@
|
||||
</key>
|
||||
<key type="s" name="panel-lengths">
|
||||
<default>'{}'</default>
|
||||
<summary>Percentages of screen edge for panel to span</summary>
|
||||
<summary>Percentages of screen edge for panel to span, -1 for dynamic length (dock mode)</summary>
|
||||
<description>Length of the panels, in percent (JSON).</description>
|
||||
</key>
|
||||
<key type="s" name="panel-anchors">
|
||||
@@ -244,6 +245,22 @@
|
||||
<summary>Lock the taskbar</summary>
|
||||
<description>Specifies if the user can modify the taskbar</description>
|
||||
</key>
|
||||
<key type="i" name="panel-top-bottom-margins">
|
||||
<default>0</default>
|
||||
<summary>Panel top and bottom margins</summary>
|
||||
</key>
|
||||
<key type="i" name="panel-side-margins">
|
||||
<default>0</default>
|
||||
<summary>Panel side margins</summary>
|
||||
</key>
|
||||
<key type="i" name="panel-top-bottom-padding">
|
||||
<default>0</default>
|
||||
<summary>Panel top and bottom padding</summary>
|
||||
</key>
|
||||
<key type="i" name="panel-side-padding">
|
||||
<default>0</default>
|
||||
<summary>Panel sides padding</summary>
|
||||
</key>
|
||||
<key type="b" name="trans-use-custom-bg">
|
||||
<default>false</default>
|
||||
<summary>Override theme background color</summary>
|
||||
@@ -341,18 +358,39 @@
|
||||
</key>
|
||||
<key type="b" name="intellihide-hide-from-windows">
|
||||
<default>false</default>
|
||||
<summary>Only hide from windows</summary>
|
||||
<summary>Only hide from overlapping windows</summary>
|
||||
<description>Dictates if the dash should only hide when in conflict with windows</description>
|
||||
</key>
|
||||
<key type="b" name="intellihide-hide-from-monitor-windows">
|
||||
<default>false</default>
|
||||
<summary>Only hide from windows on monitor</summary>
|
||||
</key>
|
||||
<key name="intellihide-behaviour" enum="org.gnome.shell.extensions.dash-to-panel.proximityBehavior">
|
||||
<default>'FOCUSED_WINDOWS'</default>
|
||||
<summary>Intellihide behaviour</summary>
|
||||
<description>Dictates how to intelligently hide the panel</description>
|
||||
</key>
|
||||
<key type="b" name="intellihide-use-pointer">
|
||||
<default>true</default>
|
||||
<summary>Intellihide mouse pointer</summary>
|
||||
<description>The mouse pointer next to the edge of the screen reveals the panel</description>
|
||||
</key>
|
||||
<key type="b" name="intellihide-use-pointer-limit-size">
|
||||
<default>false</default>
|
||||
<summary>Limit to panel length</summary>
|
||||
</key>
|
||||
<key type="b" name="intellihide-revealed-hover">
|
||||
<default>true</default>
|
||||
<summary>Panel stays revealed when hovered</summary>
|
||||
</key>
|
||||
<key type="b" name="intellihide-revealed-hover-limit-size">
|
||||
<default>false</default>
|
||||
<summary>Limit to panel length</summary>
|
||||
</key>
|
||||
<key type="b" name="intellihide-use-pressure">
|
||||
<default>false</default>
|
||||
<summary>Intellihide pressure</summary>
|
||||
<description>To reveal the panel, pressure needs to be applied to the edege of the screen</description>
|
||||
<description>To reveal the panel, pressure needs to be applied to the edge of the screen</description>
|
||||
</key>
|
||||
<key type="i" name="intellihide-pressure-threshold">
|
||||
<default>100</default>
|
||||
@@ -366,9 +404,13 @@
|
||||
</key>
|
||||
<key type="b" name="intellihide-show-in-fullscreen">
|
||||
<default>false</default>
|
||||
<summary>Intellihide pressure</summary>
|
||||
<summary>Allow revealing the panel while in fullscreen</summary>
|
||||
<description>Allow the panel to be revealed while an application is in fullscreen mode</description>
|
||||
</key>
|
||||
<key type="b" name="intellihide-show-on-notification">
|
||||
<default>false</default>
|
||||
<summary>Reveal the panel on notification</summary>
|
||||
</key>
|
||||
<key type="b" name="intellihide-only-secondary">
|
||||
<default>false</default>
|
||||
<summary>Intellihide only secondary</summary>
|
||||
@@ -384,6 +426,11 @@
|
||||
<summary>Intellihide close delay</summary>
|
||||
<description>The delay (ms) before hiding the panel</description>
|
||||
</key>
|
||||
<key type="i" name="intellihide-reveal-delay">
|
||||
<default>0</default>
|
||||
<summary>Intellihide reveal delay</summary>
|
||||
<description>The delay (ms) before revealing the panel</description>
|
||||
</key>
|
||||
<key type="s" name="intellihide-key-toggle-text">
|
||||
<default>"<Super>i"</default>
|
||||
<summary>Keybinding toggle intellihide</summary>
|
||||
@@ -394,6 +441,10 @@
|
||||
<summary>Keybinding toggle intellihide</summary>
|
||||
<description>Keybinding to reveal the panel while in intellihide mode</description>
|
||||
</key>
|
||||
<key type="i" name="intellihide-persisted-state">
|
||||
<default>-1</default>
|
||||
<summary>Persisted intellihide hold status. -1 means the option is disabled</summary>
|
||||
</key>
|
||||
<key type="i" name="intellihide-enable-start-delay">
|
||||
<default>2000</default>
|
||||
<summary>Intellihide enable start delay</summary>
|
||||
@@ -629,21 +680,16 @@
|
||||
<summary>Use favorite icons as application launchers</summary>
|
||||
<description>When the applications are ungrouped, this defines if running applications stay separate from the favorite icons.</description>
|
||||
</key>
|
||||
<key type="i" name="primary-monitor">
|
||||
<default>0</default>
|
||||
<key type="s" name="primary-monitor">
|
||||
<default>''</default>
|
||||
<summary>Primary monitor index</summary>
|
||||
<description>Specifies the index of the primary monitor.</description>
|
||||
<description>Specifies the id of the primary monitor.</description>
|
||||
</key>
|
||||
<key type="b" name="multi-monitors">
|
||||
<default>true</default>
|
||||
<summary>Display panels on all monitors</summary>
|
||||
<description>Specifies if a panel is shown on every monitors</description>
|
||||
</key>
|
||||
<key type="ai" name="available-monitors">
|
||||
<default>[]</default>
|
||||
<summary>Available monitors</summary>
|
||||
<description>Available gnome-shell (Mutter) monitors, internal use</description>
|
||||
</key>
|
||||
<key type="b" name="isolate-monitors">
|
||||
<default>false</default>
|
||||
<summary>Provide monitor isolation</summary>
|
||||
@@ -692,6 +738,29 @@
|
||||
<summary>Action when scrolling over the panel</summary>
|
||||
<description>Set the action that is executed when scrolling over the panel</description>
|
||||
</key>
|
||||
<key type="s" name="context-menu-entries">
|
||||
<default>'
|
||||
[
|
||||
{
|
||||
"title": "Terminal",
|
||||
"cmd": "TERMINALSETTINGS"
|
||||
},
|
||||
{
|
||||
"title": "System monitor",
|
||||
"cmd": "gnome-system-monitor"
|
||||
},
|
||||
{
|
||||
"title": "Files",
|
||||
"cmd": "nautilus"
|
||||
},
|
||||
{
|
||||
"title": "Extensions",
|
||||
"cmd": "gnome-extensions-app"
|
||||
}
|
||||
]'
|
||||
</default>
|
||||
<summary>User defined context menu entries</summary>
|
||||
</key>
|
||||
<key type="i" name="scroll-panel-delay">
|
||||
<default>0</default>
|
||||
<summary>Delay between panel mouse scroll events</summary>
|
||||
@@ -751,6 +820,10 @@
|
||||
<summary>Leftbox font size</summary>
|
||||
<description>Set the size of the leftBox font. (0 for default)</description>
|
||||
</key>
|
||||
<key type="i" name="global-border-radius">
|
||||
<default>0</default>
|
||||
<summary>Border radius of panel elements</summary>
|
||||
</key>
|
||||
<key type="i" name="appicon-margin">
|
||||
<default>8</default>
|
||||
<summary>App icon margin</summary>
|
||||
@@ -816,13 +889,29 @@
|
||||
<default>{'SIMPLE':1,'RIPPLE':1.25,'PLANK':2}</default>
|
||||
<summary>App icon hover animation zoom scale in relation to the app icon size</summary>
|
||||
</key>
|
||||
<key type="b" name="highlight-appicon-hover">
|
||||
<default>true</default>
|
||||
<summary>Highlight app icon on hover</summary>
|
||||
</key>
|
||||
<key type="s" name="highlight-appicon-hover-background-color">
|
||||
<default>"rgba(238, 238, 236, 0.1)"</default>
|
||||
<summary>Highlight color</summary>
|
||||
</key>
|
||||
<key type="s" name="highlight-appicon-pressed-background-color">
|
||||
<default>"rgba(238, 238, 236, 0.18)"</default>
|
||||
<summary>Mouse down highlight color</summary>
|
||||
</key>
|
||||
<key type="i" name="highlight-appicon-hover-border-radius">
|
||||
<default>0</default>
|
||||
<summary>Highlight border radius</summary>
|
||||
</key>
|
||||
<key type="b" name="secondarymenu-contains-appmenu">
|
||||
<default>true</default>
|
||||
<summary>Integrate items from the gnome appmenu into the right click menu</summary>
|
||||
</key>
|
||||
<key type="b" name="secondarymenu-contains-showdetails">
|
||||
<default>false</default>
|
||||
<summary>Display Show Details to open Gnome Software from right click menu</summary>
|
||||
<summary>Display App Details to open Gnome Software from right click menu</summary>
|
||||
</key>
|
||||
<key type="s" name="shortcut-text">
|
||||
<default>"<Super>q"</default>
|
||||
@@ -836,8 +925,7 @@
|
||||
</key>
|
||||
<key type="i" name="shortcut-timeout">
|
||||
<default>2000</default>
|
||||
<summary>Timeout to hide the dock, in seconds</summary>
|
||||
<description>Sets the time duration before the dock is hidden again.</description>
|
||||
<summary>Timeout to hide the panel after showing the overlay using the shortcut, in seconds</summary>
|
||||
</key>
|
||||
<key type="i" name="overlay-timeout">
|
||||
<default>750</default>
|
||||
@@ -859,6 +947,10 @@
|
||||
<summary>Prefix to use for hotkeys</summary>
|
||||
<description>You can choose between Super or SuperAlt as the prefix for hotkeys.</description>
|
||||
</key>
|
||||
<key type="b" name="shortcut-overlay-on-secondary">
|
||||
<default>false</default>
|
||||
<summary>Show overlay on secondary monitors</summary>
|
||||
</key>
|
||||
<key type="b" name="shortcut-previews">
|
||||
<default>false</default>
|
||||
<summary>Show window previews</summary>
|
||||
@@ -1303,9 +1395,13 @@
|
||||
<default>''</default>
|
||||
<summary>The preferences page name to display</summary>
|
||||
</key>
|
||||
<key type="s" name="hide-donate-icon-unixtime">
|
||||
<default>''</default>
|
||||
<summary>Unix time when the donate icon was hidden</summary>
|
||||
<key type="b" name="prefs-opened">
|
||||
<default>false</default>
|
||||
<summary>Track if the preferences window is opened</summary>
|
||||
</key>
|
||||
<key type="i" name="extension-version">
|
||||
<default>65</default>
|
||||
<summary>Installed extension version</summary>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
|
||||
2404
src/appIcons.js
Normal file
2404
src/appIcons.js
Normal file
File diff suppressed because it is too large
Load Diff
171
src/desktopIconsIntegration.js
Normal file
171
src/desktopIconsIntegration.js
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* The code in this file is distributed under a "1-clause BSD license",
|
||||
* which makes it compatible with GPLv2 and GPLv3 too, and others.
|
||||
*
|
||||
* License text:
|
||||
*
|
||||
* Copyright (C) 2021 Sergio Costas (rastersoft@gmail.com)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* Integration class
|
||||
*
|
||||
* This class must be added to other extensions in order to integrate
|
||||
* them with Desktop Icons NG. It allows an extension to notify how much margin
|
||||
* it uses in each side of each monitor.
|
||||
*
|
||||
* DON'T SEND PATCHES TO THIS FILE TO THE EXTENSION MAINTAINER. SEND THEM TO
|
||||
* DESKTOP ICONS NG MAINTAINER: https://gitlab.com/rastersoft/desktop-icons-ng
|
||||
*
|
||||
* In the *enable()* function, create a *DesktopIconsUsableAreaClass()*
|
||||
* object with
|
||||
*
|
||||
* new DesktopIconsIntegration.DesktopIconsUsableAreaClass(object);
|
||||
*
|
||||
* Now, in the *disable()* function just call to the *destroy()* method before
|
||||
* nullifying the pointer. You must create a new object in enable() the next
|
||||
* time the extension is enabled.
|
||||
*
|
||||
* In your code, every time you change the margins, you should call first to
|
||||
* *resetMargins()* method to clear the current margins, and then call to
|
||||
* *setMargins(...)* method as many times as you need to set the margins in each
|
||||
* monitor. You don't need to call it for all the monitors, only for those where
|
||||
* you are painting something. If you don't set values for a monitor, they will
|
||||
* be considered zero.
|
||||
*
|
||||
* The margins values are relative to the monitor border.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
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'
|
||||
|
||||
export class DesktopIconsUsableAreaClass {
|
||||
_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
|
||||
|
||||
// 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 (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)
|
||||
}
|
||||
}
|
||||
214
src/extension.js
Normal file
214
src/extension.js
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Dash-To-Panel extension for Gnome 3
|
||||
* Copyright 2016 Jason DeRose (jderose9) and Charles Gagnon (charlesg99)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
import Gio from 'gi://Gio'
|
||||
import GLib from 'gi://GLib'
|
||||
import Shell from 'gi://Shell'
|
||||
|
||||
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 PanelSettings from './panelSettings.js'
|
||||
|
||||
import * as PanelManager from './panelManager.js'
|
||||
import * as AppIcons from './appIcons.js'
|
||||
import * as Utils from './utils.js'
|
||||
|
||||
const UBUNTU_DOCK_UUID = 'ubuntu-dock@ubuntu.com'
|
||||
|
||||
let panelManager
|
||||
let startupCompleteHandler
|
||||
let ubuntuDockDelayId = 0
|
||||
|
||||
export let DTP_EXTENSION = null
|
||||
export let SETTINGS = null
|
||||
export let DESKTOPSETTINGS = null
|
||||
export let TERMINALSETTINGS = null
|
||||
export let NOTIFICATIONSSETTINGS = null
|
||||
export let PERSISTENTSTORAGE = null
|
||||
export let EXTENSION_PATH = null
|
||||
export let tracker = null
|
||||
|
||||
export default class DashToPanelExtension extends Extension {
|
||||
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 = {}
|
||||
}
|
||||
|
||||
async enable() {
|
||||
DTP_EXTENSION = this
|
||||
SETTINGS = this.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',
|
||||
})
|
||||
NOTIFICATIONSSETTINGS = new Gio.Settings({
|
||||
schema_id: 'org.gnome.desktop.notifications',
|
||||
})
|
||||
EXTENSION_PATH = this.path
|
||||
|
||||
tracker = Shell.WindowTracker.get_default()
|
||||
|
||||
//create a global object that can emit signals and conveniently expose functionalities to other extensions
|
||||
global.dashToPanel = new EventEmitter()
|
||||
|
||||
// reset to be safe
|
||||
SETTINGS.set_boolean('prefs-opened', false)
|
||||
|
||||
await PanelSettings.init(SETTINGS)
|
||||
|
||||
// To remove later, try to map settings using monitor indexes to monitor ids
|
||||
PanelSettings.adjustMonitorSettings(SETTINGS)
|
||||
|
||||
// if new version, display a notification linking to release notes
|
||||
if (this.metadata.version != SETTINGS.get_int('extension-version')) {
|
||||
Utils.notify(
|
||||
_('Dash to Panel has been updated!'),
|
||||
_('You are now running version') + ` ${this.metadata.version}.`,
|
||||
'software-update-available-symbolic',
|
||||
Gio.icon_new_for_string(
|
||||
`${this.path}/img/dash-to-panel-logo-light.svg`,
|
||||
),
|
||||
{
|
||||
text: _(`See what's new`),
|
||||
func: () =>
|
||||
Gio.app_info_launch_default_for_uri(
|
||||
`${this.metadata.url}/releases/tag/v${this.metadata.version}`,
|
||||
global.create_app_launch_context(0, -1),
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
SETTINGS.set_int('extension-version', this.metadata.version)
|
||||
}
|
||||
|
||||
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 = this._realHasOverview),
|
||||
)
|
||||
}
|
||||
|
||||
this.enableGlobalStyles()
|
||||
|
||||
let completeEnable = () => {
|
||||
panelManager = new PanelManager.PanelManager()
|
||||
panelManager.enable()
|
||||
ubuntuDockDelayId = 0
|
||||
|
||||
return GLib.SOURCE_REMOVE
|
||||
}
|
||||
|
||||
// disable ubuntu dock if present
|
||||
if (Main.extensionManager._extensionOrder.indexOf(UBUNTU_DOCK_UUID) >= 0) {
|
||||
let disabled = global.settings.get_strv('disabled-extensions')
|
||||
|
||||
if (disabled.indexOf(UBUNTU_DOCK_UUID) < 0) {
|
||||
disabled.push(UBUNTU_DOCK_UUID)
|
||||
global.settings.set_strv('disabled-extensions', disabled)
|
||||
|
||||
// wait a bit so ubuntu dock can disable itself and restore the showappsbutton
|
||||
ubuntuDockDelayId = GLib.timeout_add(
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
200,
|
||||
completeEnable,
|
||||
)
|
||||
}
|
||||
} else completeEnable()
|
||||
}
|
||||
|
||||
disable() {
|
||||
if (ubuntuDockDelayId) GLib.Source.remove(ubuntuDockDelayId)
|
||||
|
||||
PanelSettings.disable(SETTINGS)
|
||||
panelManager.disable()
|
||||
|
||||
DTP_EXTENSION = null
|
||||
SETTINGS = null
|
||||
DESKTOPSETTINGS = null
|
||||
TERMINALSETTINGS = null
|
||||
panelManager = null
|
||||
|
||||
delete global.dashToPanel
|
||||
|
||||
this.disableGlobalStyles()
|
||||
|
||||
AppIcons.resetRecentlyClickedApp()
|
||||
|
||||
if (startupCompleteHandler) {
|
||||
Main.layoutManager.disconnect(startupCompleteHandler)
|
||||
startupCompleteHandler = null
|
||||
}
|
||||
|
||||
Main.sessionMode.hasOverview = this._realHasOverview
|
||||
}
|
||||
|
||||
openPreferences() {
|
||||
if (SETTINGS.get_boolean('prefs-opened')) {
|
||||
let prefsWindow = Utils.getAllMetaWindows().find(
|
||||
(w) =>
|
||||
w.title == 'Dash to Panel' &&
|
||||
w.wm_class == 'org.gnome.Shell.Extensions',
|
||||
)
|
||||
|
||||
if (prefsWindow) Main.activateWindow(prefsWindow)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
super.openPreferences()
|
||||
}
|
||||
|
||||
resetGlobalStyles() {
|
||||
this.disableGlobalStyles()
|
||||
this.enableGlobalStyles()
|
||||
}
|
||||
|
||||
enableGlobalStyles() {
|
||||
let globalBorderRadius = SETTINGS.get_int('global-border-radius')
|
||||
|
||||
if (globalBorderRadius)
|
||||
Main.layoutManager.uiGroup.add_style_class_name(
|
||||
`br${globalBorderRadius * 4}`,
|
||||
)
|
||||
}
|
||||
|
||||
disableGlobalStyles() {
|
||||
;['br4', 'br8', 'br12', 'br16', 'br20'].forEach((c) =>
|
||||
Main.layoutManager.uiGroup.remove_style_class_name(c),
|
||||
)
|
||||
}
|
||||
}
|
||||
585
src/intellihide.js
Normal file
585
src/intellihide.js
Normal file
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Clutter from 'gi://Clutter'
|
||||
import Meta from 'gi://Meta'
|
||||
import Mtk from 'gi://Mtk'
|
||||
import Shell from 'gi://Shell'
|
||||
import St from 'gi://St'
|
||||
|
||||
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, NOTIFICATIONSSETTINGS } 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
|
||||
|
||||
//timeout names
|
||||
const T1 = 'checkGrabTimeout'
|
||||
const T2 = 'limitUpdateTimeout'
|
||||
const T3 = 'postAnimateTimeout'
|
||||
const T4 = 'enableStartTimeout'
|
||||
|
||||
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,
|
||||
NOTIFY: 4,
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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.enabled = false
|
||||
this._changeEnabledStatus()
|
||||
}
|
||||
|
||||
enable() {
|
||||
this.enabled = true
|
||||
this._monitor = this._dtpPanel.monitor
|
||||
this._animationDestination = -1
|
||||
this._pendingUpdate = false
|
||||
this._hover = false
|
||||
this._hoveredOut = false
|
||||
this._windowOverlap = false
|
||||
this._translationProp =
|
||||
'translation_' + (this._dtpPanel.geom.vertical ? 'x' : 'y')
|
||||
|
||||
this._panelBox.translation_y = 0
|
||||
this._panelBox.translation_x = 0
|
||||
|
||||
this._setTrackPanel(true)
|
||||
this._bindGeneralSignals()
|
||||
|
||||
if (this._hidesFromWindows()) {
|
||||
let watched = SETTINGS.get_boolean('intellihide-hide-from-windows')
|
||||
? this._panelBox.get_parent()
|
||||
: new Mtk.Rectangle({
|
||||
x: this._monitor.x,
|
||||
y: this._monitor.y,
|
||||
width: this._monitor.width,
|
||||
height: this._monitor.height,
|
||||
})
|
||||
|
||||
this._proximityWatchId = this._proximityManager.createWatch(
|
||||
watched,
|
||||
this._dtpPanel.monitor.index,
|
||||
Proximity.Mode[SETTINGS.get_string('intellihide-behaviour')],
|
||||
0,
|
||||
0,
|
||||
(overlap) => {
|
||||
this._windowOverlap = overlap
|
||||
this._queueUpdatePanelPosition()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (SETTINGS.get_boolean('intellihide-use-pointer'))
|
||||
this._setRevealMechanism()
|
||||
|
||||
let lastState = SETTINGS.get_int('intellihide-persisted-state')
|
||||
|
||||
if (lastState > -1) {
|
||||
this._holdStatus = lastState
|
||||
|
||||
if (lastState == Hold.NONE && Main.layoutManager._startingUp)
|
||||
this._signalsHandler.add([
|
||||
this._panelBox,
|
||||
'notify::mapped',
|
||||
() => this._hidePanel(true),
|
||||
])
|
||||
else this._queueUpdatePanelPosition()
|
||||
} else
|
||||
// -1 means that the option to persist hold isn't activated, so normal start
|
||||
this._timeoutsHandler.add([
|
||||
T4,
|
||||
SETTINGS.get_int('intellihide-enable-start-delay'),
|
||||
() => this._queueUpdatePanelPosition(),
|
||||
])
|
||||
}
|
||||
|
||||
disable(reset) {
|
||||
this.enabled = false
|
||||
this._hover = false
|
||||
|
||||
if (this._proximityWatchId) {
|
||||
this._proximityManager.removeWatch(this._proximityWatchId)
|
||||
}
|
||||
|
||||
this._setTrackPanel(false)
|
||||
this._removeRevealMechanism()
|
||||
|
||||
this._revealPanel(!reset)
|
||||
|
||||
this._signalsHandler.destroy()
|
||||
this._timeoutsHandler.destroy()
|
||||
}
|
||||
|
||||
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, immediate) {
|
||||
if (
|
||||
!this.enabled ||
|
||||
(holdStatus == Hold.NOTIFY &&
|
||||
(!SETTINGS.get_boolean('intellihide-show-on-notification') ||
|
||||
!NOTIFICATIONSSETTINGS.get_boolean('show-banners')))
|
||||
)
|
||||
return
|
||||
|
||||
if (!this._holdStatus) this._revealPanel(immediate)
|
||||
|
||||
this._holdStatus |= holdStatus
|
||||
|
||||
this._maybePersistHoldStatus()
|
||||
}
|
||||
|
||||
release(holdStatus) {
|
||||
if (!this.enabled) return
|
||||
|
||||
if (this._holdStatus & holdStatus) this._holdStatus -= holdStatus
|
||||
|
||||
if (!this._holdStatus) {
|
||||
this._maybePersistHoldStatus()
|
||||
this._queueUpdatePanelPosition()
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.disable(true)
|
||||
this.enable()
|
||||
}
|
||||
|
||||
_hidesFromWindows() {
|
||||
return (
|
||||
SETTINGS.get_boolean('intellihide-hide-from-windows') ||
|
||||
SETTINGS.get_boolean('intellihide-hide-from-monitor-windows')
|
||||
)
|
||||
}
|
||||
|
||||
_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']()
|
||||
}
|
||||
}
|
||||
|
||||
_maybePersistHoldStatus() {
|
||||
if (SETTINGS.get_int('intellihide-persisted-state') > -1)
|
||||
SETTINGS.set_int(
|
||||
'intellihide-persisted-state',
|
||||
this._holdStatus & Hold.PERMANENT ? Hold.PERMANENT : Hold.NONE,
|
||||
)
|
||||
}
|
||||
|
||||
_bindGeneralSignals() {
|
||||
this._signalsHandler.add(
|
||||
[
|
||||
this._dtpPanel.taskbar,
|
||||
['menu-closed', 'end-drag'],
|
||||
() => this._queueUpdatePanelPosition(),
|
||||
],
|
||||
[
|
||||
SETTINGS,
|
||||
[
|
||||
'changed::intellihide-use-pointer',
|
||||
'changed::intellihide-use-pressure',
|
||||
'changed::intellihide-hide-from-windows',
|
||||
'changed::intellihide-hide-from-monitor-windows',
|
||||
'changed::intellihide-behaviour',
|
||||
'changed::intellihide-pressure-threshold',
|
||||
'changed::intellihide-pressure-time',
|
||||
],
|
||||
() => this.reset(),
|
||||
],
|
||||
[
|
||||
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),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
_setTrackPanel(enable) {
|
||||
let actorData = Utils.getTrackedActorData(this._panelBox)
|
||||
|
||||
actorData.affectsStruts = !enable
|
||||
actorData.trackFullscreen = !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',
|
||||
() => {
|
||||
let [x, y] = global.get_pointer()
|
||||
|
||||
if (this._pointerIn(x, y, 1, 'intellihide-use-pointer-limit-size'))
|
||||
this._queueUpdatePanelPosition(true)
|
||||
else this._pressureBarrier._isTriggered = false
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(
|
||||
CHECK_POINTER_MS,
|
||||
(x, y) => this._checkMousePointer(x, y),
|
||||
)
|
||||
}
|
||||
|
||||
_removeRevealMechanism() {
|
||||
if (this._pointerWatch) {
|
||||
PointerWatcher.getPointerWatcher()._removeWatch(this._pointerWatch)
|
||||
this._pointerWatch = 0
|
||||
}
|
||||
|
||||
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.geom.vertical) {
|
||||
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) {
|
||||
if (
|
||||
!this._pressureBarrier &&
|
||||
!this._hover &&
|
||||
!Main.overview.visible &&
|
||||
this._pointerIn(x, y, 1, 'intellihide-use-pointer-limit-size')
|
||||
) {
|
||||
this._hover = true
|
||||
this._queueUpdatePanelPosition(true)
|
||||
} else if (this._panelBox.visible) {
|
||||
let keepRevealedOnHover = SETTINGS.get_boolean(
|
||||
'intellihide-revealed-hover',
|
||||
)
|
||||
let fixedOffset = keepRevealedOnHover
|
||||
? this._dtpPanel.geom.outerSize + this._dtpPanel.geom.topOffset
|
||||
: 1
|
||||
let hover = this._pointerIn(
|
||||
x,
|
||||
y,
|
||||
fixedOffset,
|
||||
'intellihide-revealed-hover-limit-size',
|
||||
)
|
||||
|
||||
if (hover == this._hover) return
|
||||
|
||||
this._hoveredOut = !hover
|
||||
this._hover = hover
|
||||
this._queueUpdatePanelPosition()
|
||||
}
|
||||
}
|
||||
|
||||
_pointerIn(x, y, fixedOffset, limitSizeSetting) {
|
||||
let geom = this._dtpPanel.geom
|
||||
let position = geom.position
|
||||
let varCoordX1 = this._monitor.x
|
||||
let varCoordY1 = this._monitor.y + geom.gsTopPanelHeight // if vertical, ignore the original GS panel if present
|
||||
let varOffset = {}
|
||||
|
||||
if (geom.dockMode && SETTINGS.get_boolean(limitSizeSetting)) {
|
||||
let alloc = this._dtpPanel.allocation
|
||||
|
||||
if (!geom.dynamic) {
|
||||
// when fixed, use the panel clipcontainer which is positioned
|
||||
// relative to the stage itself
|
||||
varCoordX1 = geom.x
|
||||
varCoordY1 = geom.y
|
||||
varOffset[this._dtpPanel.varCoord.c2] =
|
||||
alloc[this._dtpPanel.varCoord.c2] - alloc[this._dtpPanel.varCoord.c1]
|
||||
} else {
|
||||
// when dynamic, the panel clipcontainer spans the whole monitor edge
|
||||
// and the panel is positioned relatively to the clipcontainer
|
||||
varOffset[this._dtpPanel.varCoord.c1] =
|
||||
alloc[this._dtpPanel.varCoord.c1]
|
||||
varOffset[this._dtpPanel.varCoord.c2] =
|
||||
alloc[this._dtpPanel.varCoord.c2]
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
((position == St.Side.TOP && y <= this._monitor.y + fixedOffset) ||
|
||||
(position == St.Side.BOTTOM &&
|
||||
y >= this._monitor.y + this._monitor.height - fixedOffset) ||
|
||||
(position == St.Side.LEFT && x <= this._monitor.x + fixedOffset) ||
|
||||
(position == St.Side.RIGHT &&
|
||||
x >= this._monitor.x + this._monitor.width - fixedOffset)) &&
|
||||
x >= varCoordX1 + (varOffset.x1 || 0) &&
|
||||
x < varCoordX1 + (varOffset.x2 || this._monitor.width) &&
|
||||
y >= varCoordY1 + (varOffset.y1 || 0) &&
|
||||
y < varCoordY1 + (varOffset.y2 || this._monitor.height)
|
||||
)
|
||||
}
|
||||
|
||||
_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._hover ||
|
||||
(this._dtpPanel.geom.position == St.Side.TOP &&
|
||||
Main.layoutManager.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 (!this._hidesFromWindows()) {
|
||||
return this._hover
|
||||
}
|
||||
|
||||
return !this._windowOverlap
|
||||
}
|
||||
|
||||
_checkIfGrab() {
|
||||
let grabActor = global.stage.get_grab_actor()
|
||||
let sourceActor = grabActor?._sourceActor || grabActor
|
||||
let 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,
|
||||
() => (this._dtpPanel.taskbar._shownInitially = true),
|
||||
)
|
||||
}
|
||||
|
||||
_hidePanel(immediate) {
|
||||
let position = this._dtpPanel.geom.position
|
||||
let size = this._panelBox[this._dtpPanel.geom.vertical ? 'width' : 'height']
|
||||
let coefficient =
|
||||
position == St.Side.TOP || position == St.Side.LEFT ? -1 : 1
|
||||
|
||||
this._animatePanel(size * coefficient, immediate)
|
||||
}
|
||||
|
||||
_animatePanel(destination, immediate, onComplete) {
|
||||
if (destination === this._animationDestination) return
|
||||
|
||||
Utils.stopAnimations(this._panelBox)
|
||||
this._animationDestination = destination
|
||||
|
||||
let update = () =>
|
||||
this._timeoutsHandler.add([
|
||||
T3,
|
||||
POST_ANIMATE_MS,
|
||||
() => {
|
||||
Main.layoutManager._queueUpdateRegions()
|
||||
this._queueUpdatePanelPosition()
|
||||
},
|
||||
])
|
||||
|
||||
if (immediate) {
|
||||
this._panelBox[this._translationProp] = destination
|
||||
this._panelBox.visible = !destination
|
||||
update()
|
||||
} else if (destination !== this._panelBox[this._translationProp]) {
|
||||
let delay = 0
|
||||
|
||||
if (destination != 0 && this._hoveredOut)
|
||||
delay = SETTINGS.get_int('intellihide-close-delay') * 0.001
|
||||
else if (destination == 0)
|
||||
delay = SETTINGS.get_int('intellihide-reveal-delay') * 0.001
|
||||
|
||||
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,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: () => {
|
||||
this._panelBox.visible = !destination
|
||||
onComplete ? onComplete() : null
|
||||
update()
|
||||
},
|
||||
}
|
||||
|
||||
tweenOpts[this._translationProp] = destination
|
||||
Utils.animate(this._panelBox, tweenOpts)
|
||||
}
|
||||
|
||||
this._hoveredOut = false
|
||||
}
|
||||
}
|
||||
213
src/notificationsMonitor.js
Normal file
213
src/notificationsMonitor.js
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Gio from 'gi://Gio'
|
||||
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
|
||||
import * as MessageTray from 'resource:///org/gnome/shell/ui/messageTray.js'
|
||||
import { EventEmitter } from 'resource:///org/gnome/shell/misc/signals.js'
|
||||
|
||||
import { tracker } from './extension.js'
|
||||
import * as Utils from './utils.js'
|
||||
|
||||
const knownIdMappings = {
|
||||
'org.gnome.Evolution': [/^org\.gnome\.[eE]volution([.-].+)?$/g],
|
||||
}
|
||||
|
||||
export const NotificationsMonitor = class extends EventEmitter {
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this._state = {}
|
||||
this._signalsHandler = new Utils.GlobalSignalsHandler()
|
||||
|
||||
// pretty much useless, but might as well keep it for now
|
||||
this._launcherEntryId = Gio.DBus.session.signal_subscribe(
|
||||
null, // sender
|
||||
'com.canonical.Unity.LauncherEntry', // iface
|
||||
'Update', // member
|
||||
null, // path
|
||||
null, // arg0
|
||||
Gio.DBusSignalFlags.NONE,
|
||||
(
|
||||
connection,
|
||||
senderName,
|
||||
objectPath,
|
||||
interfaceName,
|
||||
signalName,
|
||||
parameters,
|
||||
) => this._handleLauncherUpdate(senderName, parameters),
|
||||
)
|
||||
|
||||
this._signalsHandler.add([
|
||||
tracker,
|
||||
'notify::focus-app',
|
||||
() => {
|
||||
let appId = tracker.focus_app?.id
|
||||
|
||||
// reset notifications from message tray on app focus
|
||||
if (tracker.focus_app && this._state[appId])
|
||||
this._updateState(tracker.focus_app.id, this._getDefaultState(), true)
|
||||
},
|
||||
])
|
||||
this._acquireUnityDBus()
|
||||
|
||||
this._checkNotifications()
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._launcherEntryId)
|
||||
Gio.DBus.session.signal_unsubscribe(this._launcherEntryId)
|
||||
|
||||
this._releaseUnityDBus()
|
||||
this._signalsHandler.destroy()
|
||||
}
|
||||
|
||||
_updateState(appId, state, ignoreMapping) {
|
||||
// depending of the notification source, some app id end
|
||||
// with ".desktop" and some don't ¯\_(ツ)_/¯
|
||||
appId = appId.replace('.desktop', '')
|
||||
|
||||
// some app have different source app id, deamon and such,
|
||||
// but it maps to a desktop app so match those here
|
||||
if (!ignoreMapping && !knownIdMappings[appId])
|
||||
appId =
|
||||
Object.keys(knownIdMappings).find((k) =>
|
||||
knownIdMappings[k].some((regex) => appId.match(regex)),
|
||||
) || appId
|
||||
|
||||
appId = `${appId}.desktop`
|
||||
this._state[appId] = this._state[appId] || this._getDefaultState()
|
||||
|
||||
if (this._mergeState(appId, state)) this.emit(`update-${appId}`)
|
||||
}
|
||||
|
||||
_getDefaultState() {
|
||||
return {
|
||||
count: 0, // Unity
|
||||
trayCount: 0, // MessageTray
|
||||
trayUrgent: false, // MessageTray
|
||||
urgent: false, // Unity add MessageTray combined
|
||||
total: 0, // Unity add MessageTray combined
|
||||
}
|
||||
}
|
||||
|
||||
getState(app) {
|
||||
return this._state[app.id]
|
||||
}
|
||||
|
||||
_mergeState(appId, state) {
|
||||
let currenState = JSON.stringify(this._state[appId])
|
||||
|
||||
this._state[appId] = Object.assign(this._state[appId], state)
|
||||
|
||||
if (tracker.focus_app?.id == appId) {
|
||||
this._state[appId].count = 0
|
||||
this._state[appId].trayCount = 0
|
||||
}
|
||||
|
||||
this._state[appId].urgent =
|
||||
state.urgent ||
|
||||
(this._state[appId].trayUrgent && this._state[appId].trayCount) ||
|
||||
false
|
||||
|
||||
this._state[appId].total =
|
||||
((this._state[appId]['count-visible'] || 0) &&
|
||||
(this._state[appId].count || 0)) + (this._state[appId].trayCount || 0)
|
||||
|
||||
return currenState != JSON.stringify(this._state[appId])
|
||||
}
|
||||
|
||||
_acquireUnityDBus() {
|
||||
if (!this._unityBusId) {
|
||||
this._unityBusId = Gio.DBus.session.own_name(
|
||||
'com.canonical.Unity',
|
||||
Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT,
|
||||
null,
|
||||
null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_releaseUnityDBus() {
|
||||
if (this._unityBusId) {
|
||||
Gio.DBus.session.unown_name(this._unityBusId)
|
||||
this._unityBusId = 0
|
||||
}
|
||||
}
|
||||
|
||||
_handleLauncherUpdate(senderName, parameters) {
|
||||
if (!senderName || !parameters) return
|
||||
|
||||
let [appUri, properties] = parameters.deep_unpack()
|
||||
let appId = appUri.replace(/(^\w+:|^)\/\//, '')
|
||||
let updates = {}
|
||||
|
||||
// https://wiki.ubuntu.com/Unity/LauncherAPI#Low_level_DBus_API:_com.canonical.Unity.LauncherEntry
|
||||
for (let property in properties)
|
||||
updates[property] = properties[property].unpack()
|
||||
|
||||
this._updateState(appId, updates)
|
||||
}
|
||||
|
||||
_checkNotifications() {
|
||||
let getSourceId = (source) =>
|
||||
source?._appId ||
|
||||
source?.app?.id ||
|
||||
(source?.policy instanceof MessageTray.NotificationApplicationPolicy &&
|
||||
source.policy.id)
|
||||
let addSource = (tray, source) => {
|
||||
let appId = getSourceId(source)
|
||||
let updateTray = () => {
|
||||
this._updateState(appId, {
|
||||
trayCount: source.count, // always source.unseenCount might be less annoying
|
||||
trayUrgent: !!source.notifications.find((n) => {
|
||||
return (
|
||||
n.urgency > MessageTray.Urgency.NORMAL ||
|
||||
source.constructor.name == 'WindowAttentionSource' // private type from gnome-shell
|
||||
)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
if (!appId) return
|
||||
|
||||
this._signalsHandler.addWithLabel(appId, [
|
||||
source,
|
||||
'notify::count',
|
||||
updateTray,
|
||||
])
|
||||
|
||||
updateTray()
|
||||
}
|
||||
|
||||
this._signalsHandler.add(
|
||||
[Main.messageTray, 'source-added', addSource],
|
||||
[
|
||||
Main.messageTray,
|
||||
'source-removed',
|
||||
(tray, source) => {
|
||||
let appId = getSourceId(source)
|
||||
|
||||
if (appId) this._signalsHandler.removeWithLabel(appId)
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
Main.messageTray.getSources().forEach((s) => addSource(null, s))
|
||||
}
|
||||
}
|
||||
579
src/overview.js
Normal file
579
src/overview.js
Normal file
@@ -0,0 +1,579 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 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_SWITCH_HOTKEYS_KEY = 'switch-to-application-'
|
||||
const GS_OPEN_HOTKEYS_KEY = 'open-new-window-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
|
||||
|
||||
//timeout names
|
||||
const T1 = 'swipeEndTimeout'
|
||||
const T2 = 'numberOverlayTimeout'
|
||||
|
||||
export const Overview = class {
|
||||
constructor(panelManager) {
|
||||
this._injectionManager = new InjectionManager()
|
||||
this._numHotkeys = 10
|
||||
this._panelManager = panelManager
|
||||
}
|
||||
|
||||
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')
|
||||
}
|
||||
|
||||
let visibilityFunc = visible ? 'show' : 'hide'
|
||||
let height = visible ? -1 : LABEL_MARGIN * Utils.getScaleFactor()
|
||||
let overviewControls = Main.overview._overview._controls
|
||||
|
||||
overviewControls.dash[visibilityFunc]()
|
||||
overviewControls.dash.set_height(height)
|
||||
}
|
||||
|
||||
_adaptAlloc() {
|
||||
let overviewControls = Main.overview._overview._controls
|
||||
|
||||
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
|
||||
|
||||
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.geom.vertical ? 'w' : 'h'] *
|
||||
(transitioning
|
||||
? Math.abs((finalState != 0 ? 0 : 1) - progress)
|
||||
: 1)
|
||||
|
||||
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.outerSize
|
||||
}
|
||||
|
||||
originalAllocate.call(overviewControls, box)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(),
|
||||
),
|
||||
])
|
||||
}
|
||||
|
||||
let disable = () => {
|
||||
this._signalsHandler.removeWithLabel(label)
|
||||
this._injectionsHandler.removeWithLabel(label)
|
||||
}
|
||||
|
||||
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 (
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// Setup keyboard bindings for taskbar elements
|
||||
let shortcutNumKeys = SETTINGS.get_string('shortcut-num-keys')
|
||||
let bothNumKeys = shortcutNumKeys == 'BOTH'
|
||||
let numRowKeys = shortcutNumKeys == 'NUM_ROW'
|
||||
let keys = []
|
||||
let prefixModifiers = Clutter.ModifierType.SUPER_MASK
|
||||
|
||||
//3.32 introduced app hotkeys, disable them to prevent conflicts
|
||||
if (Main.wm._switchToApplication) {
|
||||
for (let i = 1; i < 10; ++i) {
|
||||
Utils.removeKeybinding(GS_SWITCH_HOTKEYS_KEY + i)
|
||||
|
||||
if (bothNumKeys || numRowKeys)
|
||||
Utils.removeKeybinding(GS_OPEN_HOTKEYS_KEY + i)
|
||||
}
|
||||
}
|
||||
|
||||
if (SETTINGS.get_string('hotkey-prefix-text') == 'SuperAlt')
|
||||
prefixModifiers |= Clutter.ModifierType.MOD1_MASK
|
||||
|
||||
if (bothNumKeys || numRowKeys) {
|
||||
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._toggleHotkeysNumberOverlay(true)
|
||||
}
|
||||
|
||||
_disableHotKeys() {
|
||||
if (!this._hotKeysEnabled) return
|
||||
|
||||
let shortcutNumKeys = SETTINGS.get_string('shortcut-num-keys')
|
||||
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_SWITCH_HOTKEYS_KEY + i,
|
||||
gsSettings,
|
||||
Main.wm._switchToApplication.bind(Main.wm),
|
||||
)
|
||||
|
||||
if (shortcutNumKeys == 'BOTH' || shortcutNumKeys == 'NUM_ROW')
|
||||
Utils.addKeybinding(
|
||||
GS_OPEN_HOTKEYS_KEY + i,
|
||||
gsSettings,
|
||||
Main.wm._openNewApplicationWindow.bind(Main.wm),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
this._hotKeysEnabled = false
|
||||
|
||||
this._toggleHotkeysNumberOverlay(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',
|
||||
'changed::shortcut-overlay-on-secondary',
|
||||
],
|
||||
() => {
|
||||
if (
|
||||
SETTINGS.get_boolean('hot-keys') &&
|
||||
SETTINGS.get_string('hotkeys-overlay-combo') === 'ALWAYS'
|
||||
)
|
||||
this._toggleHotkeysNumberOverlay(true)
|
||||
else this._toggleHotkeysNumberOverlay(false, true)
|
||||
},
|
||||
],
|
||||
[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')
|
||||
let temporarily = hotkey_option === 'TEMPORARILY'
|
||||
let timeout = SETTINGS.get_int(
|
||||
overlayFromShortcut ? 'shortcut-timeout' : 'overlay-timeout',
|
||||
)
|
||||
|
||||
if (hotkey_option === 'NEVER' || (!timeout && temporarily)) return
|
||||
|
||||
if (temporarily || overlayFromShortcut)
|
||||
this._toggleHotkeysNumberOverlay(true)
|
||||
|
||||
this._panel.intellihide.revealAndHold(Intellihide.Hold.TEMPORARY)
|
||||
|
||||
// Hide the overlay/dock after the timeout
|
||||
this._timeoutsHandler.add([
|
||||
T2,
|
||||
timeout,
|
||||
() => {
|
||||
if (hotkey_option != 'ALWAYS') {
|
||||
this._toggleHotkeysNumberOverlay(false)
|
||||
}
|
||||
|
||||
this._panel.intellihide.release(Intellihide.Hold.TEMPORARY)
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
_toggleHotkeysNumberOverlay(show, reset) {
|
||||
// this.taskbar is the primary taskbar
|
||||
this.taskbar.toggleHotkeysNumberOverlay(show)
|
||||
|
||||
if (reset || SETTINGS.get_boolean('shortcut-overlay-on-secondary')) {
|
||||
// on secondary panels, show the overlay on icons matching the ones
|
||||
// found on the primary panel (see Taksbar.hotkeyAppNumbers)
|
||||
this._panelManager.allPanels.forEach((p) => {
|
||||
if (p.isPrimary) return
|
||||
|
||||
p.taskbar.toggleHotkeysNumberOverlay(show)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_optionalClickToExit() {
|
||||
this._clickToExitEnabled = false
|
||||
if (SETTINGS.get_boolean('overview-click-to-exit'))
|
||||
this._enableClickToExit()
|
||||
|
||||
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
|
||||
|
||||
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) {
|
||||
if (
|
||||
(pickedActor.has_style_class_name &&
|
||||
pickedActor.has_style_class_name('apps-scroll-view') &&
|
||||
!pickedActor.has_style_pseudo_class('first-child')) ||
|
||||
Main.overview._overview._controls._searchEntryBin.contains(
|
||||
pickedActor,
|
||||
) ||
|
||||
pickedActor instanceof WindowPreview
|
||||
)
|
||||
return Clutter.EVENT_PROPAGATE
|
||||
}
|
||||
|
||||
Main.overview.toggle()
|
||||
},
|
||||
])
|
||||
|
||||
this._clickToExitEnabled = true
|
||||
}
|
||||
|
||||
_disableClickToExit() {
|
||||
if (!this._clickToExitEnabled) return
|
||||
|
||||
this._signalsHandler.removeWithLabel('click-to-exit')
|
||||
|
||||
this._clickToExitEnabled = false
|
||||
}
|
||||
|
||||
_onSwipeBegin() {
|
||||
this._swiping = true
|
||||
return true
|
||||
}
|
||||
|
||||
_onSwipeEnd() {
|
||||
this._timeoutsHandler.add([T1, 0, () => (this._swiping = false)])
|
||||
return true
|
||||
}
|
||||
}
|
||||
1626
src/panel.js
Normal file
1626
src/panel.js
Normal file
File diff suppressed because it is too large
Load Diff
1134
src/panelManager.js
Executable file
1134
src/panelManager.js
Executable file
File diff suppressed because it is too large
Load Diff
67
src/panelPositions.js
Normal file
67
src/panelPositions.js
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* 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 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 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 },
|
||||
]
|
||||
|
||||
export const anchorToPosition = {
|
||||
[START]: STACKED_TL,
|
||||
[MIDDLE]: CENTERED_MONITOR,
|
||||
[END]: STACKED_BR,
|
||||
}
|
||||
|
||||
export const optionDialogFunctions = {}
|
||||
|
||||
optionDialogFunctions[SHOW_APPS_BTN] = '_showShowAppsButtonOptions'
|
||||
optionDialogFunctions[DESKTOP_BTN] = '_showDesktopButtonOptions'
|
||||
|
||||
export function checkIfCentered(position) {
|
||||
return position == CENTERED || position == CENTERED_MONITOR
|
||||
}
|
||||
315
src/panelSettings.js
Normal file
315
src/panelSettings.js
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Gio from 'gi://Gio'
|
||||
|
||||
import * as Pos from './panelPositions.js'
|
||||
|
||||
const displayConfigWrapper = Gio.DBusProxy.makeProxyWrapper(
|
||||
`<node>
|
||||
<interface name="org.gnome.Mutter.DisplayConfig">
|
||||
<signal name="MonitorsChanged" />
|
||||
<method name="GetCurrentState">
|
||||
<arg name="serial" direction="out" type="u" />
|
||||
<arg name="monitors" direction="out" type="a((ssss)a(siiddada{sv})a{sv})" />
|
||||
<arg name="logical_monitors" direction="out" type="a(iiduba(ssss)a{sv})" />
|
||||
<arg name="properties" direction="out" type="a{sv}" />
|
||||
</method>
|
||||
</interface>
|
||||
</node>`,
|
||||
)
|
||||
|
||||
// the module variables here are different in the settings dialog (gjs process)
|
||||
// and in gnome-shell (gnome-shell process)
|
||||
let prefsOpenedId = null
|
||||
let useCache = false
|
||||
let cache = {}
|
||||
let monitorIdToIndex = {}
|
||||
let monitorIndexToId = {}
|
||||
|
||||
export var displayConfigProxy = null
|
||||
export var availableMonitors = []
|
||||
|
||||
export async function init(settings) {
|
||||
useCache = true
|
||||
prefsOpenedId = settings.connect(
|
||||
'changed::prefs-opened',
|
||||
() => (useCache = !settings.get_boolean('prefs-opened')),
|
||||
)
|
||||
|
||||
await setMonitorsInfo(settings)
|
||||
}
|
||||
|
||||
export async function disable(settings) {
|
||||
settings.disconnect(prefsOpenedId)
|
||||
}
|
||||
|
||||
export function clearCache(setting) {
|
||||
if (setting) {
|
||||
cache[setting] = null
|
||||
return
|
||||
}
|
||||
|
||||
cache = {}
|
||||
}
|
||||
|
||||
/** Return object representing a settings value that is stored as JSON. */
|
||||
export function getSettingsJson(settings, setting) {
|
||||
try {
|
||||
if (useCache && cache[setting]) return cache[setting]
|
||||
|
||||
let res = JSON.parse(settings.get_string(setting))
|
||||
|
||||
cache[setting] = res
|
||||
|
||||
return res
|
||||
} catch (e) {
|
||||
console.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)
|
||||
cache[setting] = value
|
||||
} catch (e) {
|
||||
console.log('Error serializing setting: ' + e.message)
|
||||
}
|
||||
}
|
||||
|
||||
// Previously, the monitor index was used as an id to persist per monitor
|
||||
// settings. Since these indexes are unreliable AF, switch to use the monitor
|
||||
// serial as its id while keeping it backward compatible.
|
||||
function getMonitorSetting(settings, settingName, monitorIndex, fallback) {
|
||||
let monitorId = monitorIndexToId[monitorIndex]
|
||||
|
||||
settings = getSettingsJson(settings, settingName)
|
||||
|
||||
return (
|
||||
settings[monitorId] ||
|
||||
settings[monitorIndex] ||
|
||||
settings[availableMonitors[monitorIndex]?.id] ||
|
||||
fallback
|
||||
)
|
||||
}
|
||||
|
||||
function setMonitorSetting(settings, settingName, monitorIndex, value) {
|
||||
let monitorId = monitorIndexToId[monitorIndex]
|
||||
let usedId = monitorId || monitorIndex
|
||||
|
||||
let currentSettings = getSettingsJson(settings, settingName)
|
||||
|
||||
if (monitorId) delete currentSettings[monitorIndex]
|
||||
|
||||
currentSettings[usedId] = value
|
||||
setSettingsJson(settings, settingName, currentSettings)
|
||||
}
|
||||
|
||||
/** Returns size of panel on a specific monitor, in pixels. */
|
||||
export function getPanelSize(settings, monitorIndex) {
|
||||
// Pull in deprecated setting if panel-sizes does not have setting for monitor.
|
||||
return getMonitorSetting(
|
||||
settings,
|
||||
'panel-sizes',
|
||||
monitorIndex,
|
||||
settings.get_int('panel-size') || 48,
|
||||
)
|
||||
}
|
||||
|
||||
export function setPanelSize(settings, monitorIndex, value) {
|
||||
if (!(Number.isInteger(value) && value <= 128 && value >= 16)) {
|
||||
console.log('Not setting invalid panel size: ' + value)
|
||||
return
|
||||
}
|
||||
|
||||
setMonitorSetting(settings, 'panel-sizes', monitorIndex, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns length of panel on a specific monitor, as a whole number percent,
|
||||
* from settings. e.g. 100, or -1 for a dynamic panel length
|
||||
*/
|
||||
export function getPanelLength(settings, monitorIndex) {
|
||||
return getMonitorSetting(settings, 'panel-lengths', monitorIndex, 100)
|
||||
}
|
||||
|
||||
export function setPanelLength(settings, monitorIndex, value) {
|
||||
if (
|
||||
!(Number.isInteger(value) && ((value <= 100 && value >= 20) || value == -1))
|
||||
) {
|
||||
console.log('Not setting invalid panel length: ' + value, new Error().stack)
|
||||
return
|
||||
}
|
||||
|
||||
setMonitorSetting(settings, 'panel-lengths', monitorIndex, value)
|
||||
}
|
||||
|
||||
/** Returns position of panel on a specific monitor. */
|
||||
export function getPanelPosition(settings, monitorIndex) {
|
||||
return getMonitorSetting(
|
||||
settings,
|
||||
'panel-positions',
|
||||
monitorIndex,
|
||||
settings.get_string('panel-position') || Pos.BOTTOM,
|
||||
)
|
||||
}
|
||||
|
||||
export function setPanelPosition(settings, monitorIndex, value) {
|
||||
if (
|
||||
!(
|
||||
value === Pos.TOP ||
|
||||
value === Pos.BOTTOM ||
|
||||
value === Pos.LEFT ||
|
||||
value === Pos.RIGHT
|
||||
)
|
||||
) {
|
||||
console.log('Not setting invalid panel position: ' + value)
|
||||
return
|
||||
}
|
||||
|
||||
setMonitorSetting(settings, 'panel-positions', monitorIndex, value)
|
||||
}
|
||||
|
||||
/** Returns anchor location of panel on a specific monitor. */
|
||||
export function getPanelAnchor(settings, monitorIndex) {
|
||||
return getMonitorSetting(settings, 'panel-anchors', monitorIndex, Pos.MIDDLE)
|
||||
}
|
||||
|
||||
export function setPanelAnchor(settings, monitorIndex, value) {
|
||||
if (!(value === Pos.START || value === Pos.MIDDLE || value === Pos.END)) {
|
||||
console.log('Not setting invalid panel anchor: ' + value)
|
||||
return
|
||||
}
|
||||
|
||||
setMonitorSetting(settings, 'panel-anchors', monitorIndex, value)
|
||||
}
|
||||
|
||||
export function getPanelElementPositions(settings, monitorIndex) {
|
||||
return getMonitorSetting(
|
||||
settings,
|
||||
'panel-element-positions',
|
||||
monitorIndex,
|
||||
Pos.defaults,
|
||||
)
|
||||
}
|
||||
|
||||
export function setPanelElementPositions(settings, monitorIndex, value) {
|
||||
setMonitorSetting(settings, 'panel-element-positions', monitorIndex, value)
|
||||
}
|
||||
|
||||
export function getPrimaryIndex(dtpPrimaryId) {
|
||||
if (dtpPrimaryId in monitorIdToIndex) return monitorIdToIndex[dtpPrimaryId]
|
||||
|
||||
if (dtpPrimaryId.match(/^\d{1,2}$/) && availableMonitors[dtpPrimaryId])
|
||||
return dtpPrimaryId
|
||||
|
||||
return availableMonitors.findIndex((am) => am.primary)
|
||||
}
|
||||
|
||||
export function setMonitorsInfo(settings) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
let monitorInfos = []
|
||||
let saveMonitorState = (proxy) => {
|
||||
proxy.GetCurrentStateRemote((displayInfo, e) => {
|
||||
if (e) return reject(`Error getting display state: ${e}`)
|
||||
|
||||
let ids = {}
|
||||
|
||||
//https://gitlab.gnome.org/GNOME/mutter/-/blob/main/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml#L347
|
||||
displayInfo[2].forEach((logicalMonitor, i) => {
|
||||
let [connector, vendor, product, serial] = logicalMonitor[5][0]
|
||||
let id = i
|
||||
let primary = logicalMonitor[4]
|
||||
|
||||
// if by any chance 2 monitors have the same id, use the connector string
|
||||
// instead, which should be unique but varies between x11 and wayland :(
|
||||
// worst case scenario, resort to using the dumbass index
|
||||
if (vendor && serial) id = `${vendor}-${serial}`
|
||||
|
||||
if (ids[id]) id = connector && !ids[connector] ? connector : i
|
||||
|
||||
monitorInfos.push({
|
||||
id,
|
||||
product,
|
||||
primary,
|
||||
})
|
||||
|
||||
monitorIdToIndex[id] = i
|
||||
monitorIndexToId[i] = id
|
||||
ids[id] = 1
|
||||
})
|
||||
|
||||
_saveMonitors(settings, monitorInfos)
|
||||
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
|
||||
if (!displayConfigProxy)
|
||||
displayConfigProxy = new displayConfigWrapper(
|
||||
Gio.DBus.session,
|
||||
'org.gnome.Mutter.DisplayConfig',
|
||||
'/org/gnome/Mutter/DisplayConfig',
|
||||
(proxy, e) => {
|
||||
if (e) return reject(`Error creating display proxy: ${e}`)
|
||||
|
||||
saveMonitorState(proxy)
|
||||
},
|
||||
)
|
||||
else saveMonitorState(displayConfigProxy)
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function _saveMonitors(settings, monitorInfos) {
|
||||
let keyPrimary = 'primary-monitor'
|
||||
let dtpPrimaryMonitor = settings.get_string(keyPrimary)
|
||||
|
||||
// convert previously saved index to monitor id
|
||||
if (dtpPrimaryMonitor.match(/^\d{1,2}$/) && monitorInfos[dtpPrimaryMonitor])
|
||||
settings.set_string(keyPrimary, monitorInfos[dtpPrimaryMonitor].id)
|
||||
|
||||
availableMonitors = Object.freeze(monitorInfos)
|
||||
}
|
||||
|
||||
// this is for backward compatibility, to remove in a few versions
|
||||
export function adjustMonitorSettings(settings) {
|
||||
let updateSettings = (settingName) => {
|
||||
let monitorSettings = getSettingsJson(settings, settingName)
|
||||
let updatedSettings = {}
|
||||
|
||||
Object.keys(monitorSettings).forEach((key) => {
|
||||
let initialKey = key
|
||||
|
||||
if (key.match(/^\d{1,2}$/)) key = monitorIndexToId[key] || key
|
||||
|
||||
updatedSettings[key] = monitorSettings[initialKey]
|
||||
})
|
||||
|
||||
setSettingsJson(settings, settingName, updatedSettings)
|
||||
}
|
||||
|
||||
updateSettings('panel-sizes')
|
||||
updateSettings('panel-lengths')
|
||||
updateSettings('panel-positions')
|
||||
updateSettings('panel-anchors')
|
||||
updateSettings('panel-element-positions')
|
||||
}
|
||||
343
src/panelStyle.js
Normal file
343
src/panelStyle.js
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Credits:
|
||||
* Ideas for recursing child actors and assigning inline styles
|
||||
* are based on code from the StatusAreaHorizontalSpacing extension
|
||||
* https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension
|
||||
* mathematical.coffee@gmail.com
|
||||
*/
|
||||
|
||||
import * as Utils from './utils.js'
|
||||
import { SETTINGS } from './extension.js'
|
||||
|
||||
export const PanelStyle = class {
|
||||
enable(panel) {
|
||||
this.panel = panel
|
||||
|
||||
this._applyStyles()
|
||||
|
||||
this._bindSettingsChanges()
|
||||
}
|
||||
|
||||
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.geom.vertical
|
||||
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,
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
_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)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
3970
src/prefs.js
Normal file
3970
src/prefs.js
Normal file
File diff suppressed because it is too large
Load Diff
295
src/proximity.js
Normal file
295
src/proximity.js
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Meta from 'gi://Meta'
|
||||
import Mtk from 'gi://Mtk'
|
||||
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
|
||||
|
||||
import * as Utils from './utils.js'
|
||||
|
||||
//timeout intervals
|
||||
const MIN_UPDATE_MS = 200
|
||||
|
||||
//timeout names
|
||||
const T1 = 'limitUpdateTimeout'
|
||||
|
||||
export const Mode = {
|
||||
ALL_WINDOWS: 0,
|
||||
FOCUSED_WINDOWS: 1,
|
||||
MAXIMIZED_WINDOWS: 2,
|
||||
}
|
||||
|
||||
class ProximityRectWatch {
|
||||
constructor(rect, monitorIndex, mode, xThreshold, yThreshold, handler) {
|
||||
this.rect = rect
|
||||
this.monitorIndex = monitorIndex
|
||||
this.overlap = false
|
||||
this.mode = mode
|
||||
this.threshold = [xThreshold, yThreshold]
|
||||
this.handler = handler
|
||||
}
|
||||
|
||||
destroy() {}
|
||||
}
|
||||
|
||||
class ProximityActorWatch extends ProximityRectWatch {
|
||||
constructor(actor, monitorIndex, mode, xThreshold, yThreshold, handler) {
|
||||
super(null, monitorIndex, mode, xThreshold, yThreshold, handler)
|
||||
this.actor = actor
|
||||
|
||||
this._allocationChangedId = actor.connect('notify::allocation', () =>
|
||||
this._updateWatchRect(),
|
||||
)
|
||||
|
||||
this._updateWatchRect()
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.actor.disconnect(this._allocationChangedId)
|
||||
}
|
||||
|
||||
_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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const ProximityManager = class {
|
||||
constructor() {
|
||||
this._counter = 1
|
||||
this._watches = {}
|
||||
this._focusedWindowInfo = null
|
||||
|
||||
this._signalsHandler = new Utils.GlobalSignalsHandler()
|
||||
this._timeoutsHandler = new Utils.TimeoutsHandler()
|
||||
|
||||
this._bindSignals()
|
||||
this._setFocusedWindow()
|
||||
}
|
||||
|
||||
createWatch(watched, monitorIndex, mode, xThreshold, yThreshold, handler) {
|
||||
let constr =
|
||||
watched instanceof Mtk.Rectangle
|
||||
? ProximityRectWatch
|
||||
: ProximityActorWatch
|
||||
|
||||
let watch = new constr(
|
||||
watched,
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
this._queueUpdate(true)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_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),
|
||||
))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -39,19 +39,30 @@
|
||||
}
|
||||
|
||||
#dashtopanelScrollview .overview-tile:hover .dtp-container,
|
||||
#dashtopanelScrollview .overview-tile:focus .dtp-container,
|
||||
#dashtopanelScrollview .overview-tile:focus .dtp-container {
|
||||
background-color: rgba(238, 238, 236, 0.1);
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
#dashtopanelScrollview .overview-tile:hover .dtp-container > .dtp-dots-container,
|
||||
#dashtopanelScrollview .overview-tile:focus .dtp-container > .dtp-dots-container {
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
.dashtopanelMainPanel .dash-item-container .show-apps:hover {
|
||||
background-color: rgba(238, 238, 238, 0.1);
|
||||
}
|
||||
|
||||
.dashtopanelMainPanel .dash-item-container .show-apps .overview-icon {
|
||||
color: #FFF;
|
||||
}
|
||||
.dashtopanelMainPanel .dash-item-container .show-apps:hover .overview-icon {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#dashtopanelTaskbar .dash-item-container .overview-tile:hover,
|
||||
#dashtopanelTaskbar .dash-item-container .overview-tile .dtp-container .overview-icon,
|
||||
#dashtopanelScrollview .overview-tile:hover .dtp-container.animate-appicon-hover,
|
||||
.dashtopanelMainPanel .dash-item-container .show-apps:hover .overview-icon {
|
||||
#dashtopanelScrollview .overview-tile:hover .dtp-container.no-highlight,
|
||||
#dashtopanelScrollview .overview-tile:focus .dtp-container.no-highlight {
|
||||
background: none;
|
||||
}
|
||||
|
||||
@@ -132,8 +143,11 @@
|
||||
|
||||
#dashtopanelScrollview .badge {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
padding: 0.2em 0.5em;
|
||||
border-radius: 1em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin: 0 0 0 2px;
|
||||
}
|
||||
|
||||
#dashtopanelScrollview .number-overlay {
|
||||
@@ -141,7 +155,7 @@
|
||||
}
|
||||
|
||||
#dashtopanelScrollview .notification-badge {
|
||||
background-color: rgba(255,0,0,0.8);
|
||||
background-color: rgba(214, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
#dashtopanelScrollview .progress-bar {
|
||||
@@ -153,3 +167,85 @@
|
||||
.symbolic-icon-style {
|
||||
-st-icon-style: symbolic;
|
||||
}
|
||||
|
||||
|
||||
/* border radius, grrr no css variables in ST */
|
||||
#uiGroup.br4 .dashtopanelPanel.dock,
|
||||
#uiGroup.br4 .dashtopanelPanel.dock .dashtopanelMainPanel,
|
||||
#uiGroup.br4 .show-apps,
|
||||
#uiGroup.br4 .dtp-container,
|
||||
#uiGroup.br4 .dtp-dots-container,
|
||||
#uiGroup.br4 #preview-menu,
|
||||
#uiGroup.br4 #preview-menu .preview-header-box,
|
||||
#uiGroup.br4 #preview-menu .preview-container,
|
||||
#uiGroup.br4 #preview-menu .preview-close-btn-container {
|
||||
border-radius: 4px !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
#uiGroup.br4 .dashtopanelPanel.dock .showdesktop-button {
|
||||
border-radius: 0 4px 4px 0 !important;
|
||||
}
|
||||
|
||||
#uiGroup.br8 .dashtopanelPanel.dock,
|
||||
#uiGroup.br8 .dashtopanelPanel.dock .dashtopanelMainPanel,
|
||||
#uiGroup.br8 .show-apps,
|
||||
#uiGroup.br8 .dtp-container,
|
||||
#uiGroup.br8 .dtp-dots-container,
|
||||
#uiGroup.br8 #preview-menu,
|
||||
#uiGroup.br8 #preview-menu .preview-header-box,
|
||||
#uiGroup.br8 #preview-menu .preview-container,
|
||||
#uiGroup.br8 #preview-menu .preview-close-btn-container {
|
||||
border-radius: 8px !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
#uiGroup.br8 .dashtopanelPanel.dock .showdesktop-button {
|
||||
border-radius: 0 8px 8px 0 !important;
|
||||
}
|
||||
|
||||
#uiGroup.br12 .dashtopanelPanel.dock,
|
||||
#uiGroup.br12 .dashtopanelPanel.dock .dashtopanelMainPanel,
|
||||
#uiGroup.br12 .show-apps,
|
||||
#uiGroup.br12 .dtp-container,
|
||||
#uiGroup.br12 .dtp-dots-container,
|
||||
#uiGroup.br12 #preview-menu,
|
||||
#uiGroup.br12 #preview-menu .preview-header-box,
|
||||
#uiGroup.br12 #preview-menu .preview-container,
|
||||
#uiGroup.br12 #preview-menu .preview-close-btn-container {
|
||||
border-radius: 12px !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
#uiGroup.br12 .dashtopanelPanel.dock .showdesktop-button {
|
||||
border-radius: 0 12px 12px 0 !important;
|
||||
}
|
||||
|
||||
#uiGroup.br16 .dashtopanelPanel.dock,
|
||||
#uiGroup.br16 .dashtopanelPanel.dock .dashtopanelMainPanel,
|
||||
#uiGroup.br16 .show-apps,
|
||||
#uiGroup.br16 .dtp-container,
|
||||
#uiGroup.br16 .dtp-dots-container,
|
||||
#uiGroup.br16 #preview-menu,
|
||||
#uiGroup.br16 #preview-menu .preview-header-box,
|
||||
#uiGroup.br16 #preview-menu .preview-container,
|
||||
#uiGroup.br16 #preview-menu .preview-close-btn-container {
|
||||
border-radius: 16px !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
#uiGroup.br16 .dashtopanelPanel.dock .showdesktop-button {
|
||||
border-radius: 0 16px 16px 0 !important;
|
||||
}
|
||||
|
||||
#uiGroup.br20 .dashtopanelPanel.dock,
|
||||
#uiGroup.br20 .dashtopanelPanel.dock .dashtopanelMainPanel,
|
||||
#uiGroup.br20 .show-apps,
|
||||
#uiGroup.br20 .dtp-container,
|
||||
#uiGroup.br20 .dtp-dots-container,
|
||||
#uiGroup.br20 #preview-menu,
|
||||
#uiGroup.br20 #preview-menu .preview-header-box,
|
||||
#uiGroup.br20 #preview-menu .preview-container,
|
||||
#uiGroup.br20 #preview-menu .preview-close-btn-container {
|
||||
border-radius: 20px !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
#uiGroup.br20 .dashtopanelPanel.dock .showdesktop-button {
|
||||
border-radius: 0 20px 20px 0 !important;
|
||||
}
|
||||
1815
src/taskbar.js
Normal file
1815
src/taskbar.js
Normal file
File diff suppressed because it is too large
Load Diff
293
src/transparency.js
Normal file
293
src/transparency.js
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* 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 * 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
|
||||
|
||||
this._initialPanelStyle = dtpPanel.panel.get_style()
|
||||
|
||||
this._signalsHandler = new Utils.GlobalSignalsHandler()
|
||||
this._bindSignals()
|
||||
|
||||
this._updateAnimationDuration()
|
||||
this._updateAllAndSet()
|
||||
this._updateProximityWatch()
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._signalsHandler.destroy()
|
||||
this._proximityManager.removeWatch(this._proximityWatchId)
|
||||
|
||||
this._dtpPanel.panel.set_style(this._initialPanelStyle)
|
||||
}
|
||||
|
||||
updateExternalStyle() {
|
||||
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-use-border',
|
||||
'changed::trans-border-use-custom-color',
|
||||
'changed::trans-border-custom-color',
|
||||
'changed::trans-border-width',
|
||||
],
|
||||
() => this._updateBorderAndSet()
|
||||
],
|
||||
[
|
||||
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.geom.vertical
|
||||
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._updateBorder()
|
||||
this._updateGradient()
|
||||
this._setBackground()
|
||||
this._setGradient()
|
||||
}
|
||||
|
||||
_updateColorAndSet() {
|
||||
this._updateColor()
|
||||
this._setBackground()
|
||||
}
|
||||
|
||||
_updateAlphaAndSet() {
|
||||
this._updateAlpha()
|
||||
this._setBackground()
|
||||
}
|
||||
|
||||
_updateBorderAndSet() {
|
||||
this._updateBorder()
|
||||
this._setBackground()
|
||||
}
|
||||
|
||||
_updateGradientAndSet() {
|
||||
this._updateGradient()
|
||||
this._setGradient()
|
||||
}
|
||||
|
||||
_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
|
||||
}
|
||||
}
|
||||
|
||||
_updateBorder() {
|
||||
let rgba = this._dtpPanel._getDefaultLineColor(Utils.checkIfColorIsBright(this.backgroundColorRgb)) // supply parameter manually or else an exception (something is undefined) will arise
|
||||
const isLineCustom = SETTINGS.get_boolean('trans-border-use-custom-color')
|
||||
rgba = isLineCustom ? SETTINGS.get_string('trans-border-custom-color') : rgba
|
||||
|
||||
const showBorder = SETTINGS.get_boolean('trans-use-border')
|
||||
const borderWidth = SETTINGS.get_int('trans-border-width')
|
||||
|
||||
const position = this._dtpPanel.getPosition()
|
||||
let borderPosition = ''
|
||||
if (position == St.Side.LEFT) { borderPosition = 'right' }
|
||||
if (position == St.Side.RIGHT) { borderPosition = 'left' }
|
||||
if (position == St.Side.TOP) { borderPosition = 'bottom' }
|
||||
if (position == St.Side.BOTTOM) { borderPosition = 'top' }
|
||||
|
||||
const style = `border: 0 solid ${rgba}; border-${borderPosition}-width:${borderWidth}px;`
|
||||
this._borderStyle = showBorder ? style : ''
|
||||
}
|
||||
|
||||
_updateGradient() {
|
||||
this._gradientStyle = ''
|
||||
|
||||
if (SETTINGS.get_boolean('trans-use-custom-gradient')) {
|
||||
this._gradientStyle +=
|
||||
'background-gradient-direction: ' +
|
||||
(this._dtpPanel.geom.vertical ? '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._borderStyle,
|
||||
)
|
||||
}
|
||||
|
||||
_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) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
return bg
|
||||
}
|
||||
}
|
||||
969
src/utils.js
Normal file
969
src/utils.js
Normal file
@@ -0,0 +1,969 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Credits:
|
||||
* This file is based on code from the Dash to Dock extension by micheleg
|
||||
* and code from the Taskbar extension by Zorin OS
|
||||
* Some code was also adapted from the upstream Gnome Shell source code.
|
||||
*/
|
||||
|
||||
import Clutter from 'gi://Clutter'
|
||||
import Cogl from 'gi://Cogl'
|
||||
import GdkPixbuf from 'gi://GdkPixbuf'
|
||||
import Gio from 'gi://Gio'
|
||||
import GLib from 'gi://GLib'
|
||||
import Graphene from 'gi://Graphene'
|
||||
import Meta from 'gi://Meta'
|
||||
import Shell from 'gi://Shell'
|
||||
import St from 'gi://St'
|
||||
import * as Config from 'resource:///org/gnome/shell/misc/config.js'
|
||||
import * as Util from 'resource:///org/gnome/shell/misc/util.js'
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
|
||||
import * as MessageTray from 'resource:///org/gnome/shell/ui/messageTray.js'
|
||||
|
||||
const SCROLL_TIME = Util.SCROLL_TIME / (Util.SCROLL_TIME > 1 ? 1000 : 1)
|
||||
|
||||
// simplify global signals and function injections handling
|
||||
// abstract class
|
||||
export const BasicHandler = class {
|
||||
constructor() {
|
||||
this._storage = new Object()
|
||||
}
|
||||
|
||||
add(/*unlimited 3-long array arguments*/) {
|
||||
// convert arguments object to array, concatenate with generic
|
||||
let args = [].concat('generic', [].slice.call(arguments))
|
||||
// call addWithLabel with ags as if they were passed arguments
|
||||
this.addWithLabel.apply(this, args)
|
||||
}
|
||||
|
||||
destroy() {
|
||||
for (let label in this._storage) this.removeWithLabel(label)
|
||||
}
|
||||
|
||||
addWithLabel(label /* plus unlimited 3-long array arguments*/) {
|
||||
if (this._storage[label] == undefined) this._storage[label] = new Array()
|
||||
|
||||
// skip first element of the arguments
|
||||
for (let i = 1; i < arguments.length; i++) {
|
||||
let item = this._storage[label]
|
||||
let handlers = this._create(arguments[i])
|
||||
|
||||
for (let j = 0, l = handlers.length; j < l; ++j) {
|
||||
item.push(handlers[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeWithLabel(label) {
|
||||
if (this._storage[label]) {
|
||||
for (let i = 0; i < this._storage[label].length; i++) {
|
||||
this._remove(this._storage[label][i])
|
||||
}
|
||||
|
||||
delete this._storage[label]
|
||||
}
|
||||
}
|
||||
|
||||
hasLabel(label) {
|
||||
return !!this._storage[label]
|
||||
}
|
||||
|
||||
/* Virtual methods to be implemented by subclass */
|
||||
// create single element to be stored in the storage structure
|
||||
_create() {
|
||||
throw new Error('no implementation of _create in ' + this)
|
||||
}
|
||||
|
||||
// correctly delete single element
|
||||
_remove() {
|
||||
throw new Error('no implementation of _remove in ' + this)
|
||||
}
|
||||
}
|
||||
|
||||
// Manage global signals
|
||||
export const GlobalSignalsHandler = class extends BasicHandler {
|
||||
_create(item) {
|
||||
let handlers = []
|
||||
|
||||
item[1] = [].concat(item[1])
|
||||
|
||||
for (let i = 0, l = item[1].length; i < l; ++i) {
|
||||
let object = item[0]
|
||||
let event = item[1][i]
|
||||
let callback = item[2]
|
||||
try {
|
||||
let id = object.connect(event, callback)
|
||||
|
||||
handlers.push([object, id])
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
return handlers
|
||||
}
|
||||
|
||||
_remove(item) {
|
||||
item[0].disconnect(item[1])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage function injection: both instances and prototype can be overridden
|
||||
* and restored
|
||||
*/
|
||||
export const InjectionsHandler = class extends BasicHandler {
|
||||
_create(item) {
|
||||
let object = item[0]
|
||||
let name = item[1]
|
||||
let injectedFunction = item[2]
|
||||
let original = object[name]
|
||||
|
||||
object[name] = injectedFunction
|
||||
return [[object, name, injectedFunction, original]]
|
||||
}
|
||||
|
||||
_remove(item) {
|
||||
let object = item[0]
|
||||
let name = item[1]
|
||||
let original = item[3]
|
||||
object[name] = original
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage timeouts: the added timeouts have their id reset on completion
|
||||
*/
|
||||
export const TimeoutsHandler = class extends BasicHandler {
|
||||
_create(item) {
|
||||
let name = item[0]
|
||||
let delay = item[1]
|
||||
let timeoutHandler = item[2]
|
||||
|
||||
this._remove(item)
|
||||
|
||||
this[name] = GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, () => {
|
||||
this[name] = 0
|
||||
timeoutHandler()
|
||||
|
||||
return GLib.SOURCE_REMOVE
|
||||
})
|
||||
|
||||
return [[name]]
|
||||
}
|
||||
|
||||
remove(name) {
|
||||
this._remove([name])
|
||||
}
|
||||
|
||||
_remove(item) {
|
||||
let name = item[0]
|
||||
|
||||
if (this[name]) {
|
||||
GLib.Source.remove(this[name])
|
||||
this[name] = 0
|
||||
}
|
||||
}
|
||||
|
||||
getId(name) {
|
||||
return this[name] ? this[name] : 0
|
||||
}
|
||||
}
|
||||
|
||||
export function createBoxLayout(options) {
|
||||
if (options && 'vertical' in options) {
|
||||
let vertical = options.vertical
|
||||
|
||||
delete options.vertical
|
||||
setBoxLayoutVertical(options, vertical)
|
||||
}
|
||||
|
||||
return new St.BoxLayout(options)
|
||||
}
|
||||
|
||||
export function setBoxLayoutVertical(box, vertical) {
|
||||
if (Config.PACKAGE_VERSION >= '48')
|
||||
// https://mutter.gnome.org/clutter/enum.Orientation.html
|
||||
box.orientation = vertical ? 1 : 0
|
||||
else box.vertical = vertical
|
||||
}
|
||||
|
||||
export function getBoxLayoutVertical(box) {
|
||||
return Config.PACKAGE_VERSION >= '48' ? box.orientation == 1 : box.vertical
|
||||
}
|
||||
|
||||
// This is wrapper to maintain compatibility with GNOME-Shell 3.30+ as well as
|
||||
// previous versions.
|
||||
export const DisplayWrapper = {
|
||||
getScreen() {
|
||||
return global.screen || global.display
|
||||
},
|
||||
|
||||
getWorkspaceManager() {
|
||||
return global.screen || global.workspace_manager
|
||||
},
|
||||
|
||||
getMonitorManager() {
|
||||
return global.screen || global.backend.get_monitor_manager()
|
||||
},
|
||||
}
|
||||
|
||||
let unredirectEnabled = true
|
||||
export const setDisplayUnredirect = (enable) => {
|
||||
let v48 = Config.PACKAGE_VERSION >= '48'
|
||||
|
||||
if (enable && !unredirectEnabled)
|
||||
v48
|
||||
? global.compositor.enable_unredirect()
|
||||
: Meta.enable_unredirect_for_display(global.display)
|
||||
else if (!enable && unredirectEnabled)
|
||||
v48
|
||||
? global.compositor.disable_unredirect()
|
||||
: Meta.disable_unredirect_for_display(global.display)
|
||||
|
||||
unredirectEnabled = enable
|
||||
}
|
||||
|
||||
export const getSystemMenuInfo = function () {
|
||||
return {
|
||||
name: 'quickSettings',
|
||||
constructor: Main.panel.statusArea.quickSettings.constructor,
|
||||
}
|
||||
}
|
||||
|
||||
export function getOverviewWorkspaces() {
|
||||
let workspaces = []
|
||||
|
||||
Main.overview._overview._controls._workspacesDisplay._workspacesViews.forEach(
|
||||
(wv) =>
|
||||
(workspaces = [
|
||||
...workspaces,
|
||||
...(wv._workspaces || []), // WorkspacesDisplay --> WorkspacesView (primary monitor)
|
||||
...(wv._workspacesView?._workspaces || []), // WorkspacesDisplay --> SecondaryMonitorDisplay --> WorkspacesView
|
||||
...(wv._workspacesView?._workspace // WorkspacesDisplay --> SecondaryMonitorDisplay --> ExtraWorkspaceView
|
||||
? [wv._workspacesView?._workspace]
|
||||
: []),
|
||||
]),
|
||||
)
|
||||
|
||||
return workspaces
|
||||
}
|
||||
|
||||
export const getCurrentWorkspace = function () {
|
||||
return DisplayWrapper.getWorkspaceManager().get_active_workspace()
|
||||
}
|
||||
|
||||
export const getWorkspaceByIndex = function (index) {
|
||||
return DisplayWrapper.getWorkspaceManager().get_workspace_by_index(index)
|
||||
}
|
||||
|
||||
export const getWorkspaceCount = function () {
|
||||
return DisplayWrapper.getWorkspaceManager().n_workspaces
|
||||
}
|
||||
|
||||
export const getStageTheme = function () {
|
||||
return St.ThemeContext.get_for_stage(global.stage)
|
||||
}
|
||||
|
||||
export const getScaleFactor = function () {
|
||||
return getStageTheme().scale_factor || 1
|
||||
}
|
||||
|
||||
export const findIndex = function (array, predicate) {
|
||||
if (array) {
|
||||
if (Array.prototype.findIndex) {
|
||||
return array.findIndex(predicate)
|
||||
}
|
||||
|
||||
for (let i = 0, l = array.length; i < l; ++i) {
|
||||
if (predicate(array[i])) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
export const find = function (array, predicate) {
|
||||
let index = findIndex(array, predicate)
|
||||
|
||||
if (index > -1) {
|
||||
return array[index]
|
||||
}
|
||||
}
|
||||
|
||||
export const mergeObjects = function (main, bck) {
|
||||
for (const prop in bck) {
|
||||
if (!Object.hasOwn(main, prop) && Object.hasOwn(bck, prop)) {
|
||||
main[prop] = bck[prop]
|
||||
}
|
||||
}
|
||||
|
||||
return main
|
||||
}
|
||||
|
||||
export const getTrackedActorData = (actor) => {
|
||||
let trackedIndex = Main.layoutManager._findActor(actor)
|
||||
|
||||
if (trackedIndex >= 0) return Main.layoutManager._trackedActors[trackedIndex]
|
||||
}
|
||||
|
||||
export const getTransformedAllocation = function (actor) {
|
||||
let extents = actor.get_transformed_extents()
|
||||
let topLeft = extents.get_top_left()
|
||||
let bottomRight = extents.get_bottom_right()
|
||||
|
||||
return { x1: topLeft.x, x2: bottomRight.x, y1: topLeft.y, y2: bottomRight.y }
|
||||
}
|
||||
|
||||
export const setClip = function (actor, x, y, width, height, offsetX, offsetY) {
|
||||
actor.set_clip(offsetX || 0, offsetY || 0, width, height)
|
||||
actor.set_position(x, y)
|
||||
actor.set_size(width, height)
|
||||
}
|
||||
|
||||
export const addKeybinding = function (key, settings, handler, modes) {
|
||||
if (!Main.wm._allowedKeybindings[key]) {
|
||||
Main.wm.addKeybinding(
|
||||
key,
|
||||
settings,
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
modes || Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW,
|
||||
handler,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const removeKeybinding = function (key) {
|
||||
if (Main.wm._allowedKeybindings[key]) {
|
||||
Main.wm.removeKeybinding(key)
|
||||
}
|
||||
}
|
||||
|
||||
export const getrgbColor = function (color) {
|
||||
color =
|
||||
typeof color === 'string' ? ColorUtils.color_from_string(color)[1] : color
|
||||
|
||||
return { red: color.red, green: color.green, blue: color.blue }
|
||||
}
|
||||
|
||||
export const getrgbaColor = function (color, alpha, offset) {
|
||||
if (alpha <= 0) {
|
||||
return 'transparent; '
|
||||
}
|
||||
|
||||
let rgb = getrgbColor(color)
|
||||
|
||||
if (offset) {
|
||||
;['red', 'green', 'blue'].forEach((k) => {
|
||||
rgb[k] = Math.min(255, Math.max(0, rgb[k] + offset))
|
||||
|
||||
if (rgb[k] == color[k]) {
|
||||
rgb[k] = Math.min(255, Math.max(0, rgb[k] - offset))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
'rgba(' +
|
||||
rgb.red +
|
||||
',' +
|
||||
rgb.green +
|
||||
',' +
|
||||
rgb.blue +
|
||||
',' +
|
||||
Math.floor(alpha * 100) * 0.01 +
|
||||
'); '
|
||||
)
|
||||
}
|
||||
|
||||
export const checkIfColorIsBright = function (color) {
|
||||
let rgb = getrgbColor(color)
|
||||
let brightness = 0.2126 * rgb.red + 0.7152 * rgb.green + 0.0722 * rgb.blue
|
||||
|
||||
return brightness > 128
|
||||
}
|
||||
|
||||
export const getMouseScrollDirection = function (event) {
|
||||
let direction
|
||||
|
||||
switch (event.get_scroll_direction()) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
case Clutter.ScrollDirection.LEFT:
|
||||
direction = 'up'
|
||||
break
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
case Clutter.ScrollDirection.RIGHT:
|
||||
direction = 'down'
|
||||
break
|
||||
}
|
||||
|
||||
return direction
|
||||
}
|
||||
|
||||
export function getAllMetaWindows() {
|
||||
return global.get_window_actors().map((w) => w.meta_window)
|
||||
}
|
||||
|
||||
export const checkIfWindowHasTransient = function (window) {
|
||||
let hasTransient
|
||||
|
||||
window.foreach_transient(() => (hasTransient = true))
|
||||
|
||||
return hasTransient
|
||||
}
|
||||
|
||||
export const activateSiblingWindow = function (
|
||||
windows,
|
||||
direction,
|
||||
startWindow,
|
||||
) {
|
||||
let windowIndex = windows.indexOf(global.display.focus_window)
|
||||
let nextWindowIndex =
|
||||
windowIndex < 0
|
||||
? startWindow
|
||||
? windows.indexOf(startWindow)
|
||||
: 0
|
||||
: windowIndex + (direction == 'up' ? -1 : 1)
|
||||
|
||||
if (nextWindowIndex == windows.length) {
|
||||
nextWindowIndex = 0
|
||||
} else if (nextWindowIndex < 0) {
|
||||
nextWindowIndex = windows.length - 1
|
||||
}
|
||||
|
||||
if (windowIndex != nextWindowIndex) {
|
||||
Main.activateWindow(windows[nextWindowIndex])
|
||||
}
|
||||
}
|
||||
|
||||
export const animateWindowOpacity = function (window, tweenOpts) {
|
||||
//there currently is a mutter bug with the windowactor opacity, starting with 3.34
|
||||
//https://gitlab.gnome.org/GNOME/mutter/issues/836
|
||||
|
||||
//since 3.36, a workaround is to use the windowactor's child for the fade animation
|
||||
//this leaves a "shadow" on the desktop, so the windowactor needs to be hidden
|
||||
//when the animation is complete
|
||||
let visible = tweenOpts.opacity > 0
|
||||
let windowActor = window
|
||||
let initialOpacity = window.opacity
|
||||
|
||||
window = windowActor.get_first_child() || windowActor
|
||||
|
||||
if (!windowActor.visible && visible) {
|
||||
window.opacity = 0
|
||||
windowActor.visible = visible
|
||||
tweenOpts.opacity = Math.min(initialOpacity, tweenOpts.opacity)
|
||||
}
|
||||
|
||||
if (!visible) {
|
||||
tweenOpts.onComplete = () => {
|
||||
windowActor.visible = visible
|
||||
window.opacity = initialOpacity
|
||||
}
|
||||
}
|
||||
|
||||
animate(window, tweenOpts)
|
||||
}
|
||||
|
||||
export const animate = function (actor, options) {
|
||||
//the original animations used Tweener instead of Clutter animations, so we
|
||||
//use "time" and "delay" properties defined in seconds, as opposed to Clutter
|
||||
//animations "duration" and "delay" which are defined in milliseconds
|
||||
if (options.delay) {
|
||||
options.delay = options.delay * 1000
|
||||
}
|
||||
|
||||
options.duration = options.time * 1000
|
||||
delete options.time
|
||||
|
||||
if (options.transition) {
|
||||
//map Tweener easing equations to Clutter animation modes
|
||||
options.mode =
|
||||
{
|
||||
easeInCubic: Clutter.AnimationMode.EASE_IN_CUBIC,
|
||||
easeInOutCubic: Clutter.AnimationMode.EASE_IN_OUT_CUBIC,
|
||||
easeInOutQuad: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
|
||||
easeOutQuad: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
}[options.transition] || Clutter.AnimationMode.LINEAR
|
||||
|
||||
delete options.transition
|
||||
}
|
||||
|
||||
let params = [options]
|
||||
|
||||
if ('value' in options && actor instanceof St.Adjustment) {
|
||||
params.unshift(options.value)
|
||||
delete options.value
|
||||
}
|
||||
|
||||
actor.ease.apply(actor, params)
|
||||
}
|
||||
|
||||
export const stopAnimations = function (actor) {
|
||||
actor.remove_all_transitions()
|
||||
}
|
||||
|
||||
export const getIndicators = function (delegate) {
|
||||
if (delegate instanceof St.BoxLayout) {
|
||||
return delegate
|
||||
}
|
||||
|
||||
return delegate.indicators
|
||||
}
|
||||
|
||||
export const getPoint = function (coords) {
|
||||
return new Graphene.Point(coords)
|
||||
}
|
||||
|
||||
export const notify = function (
|
||||
title,
|
||||
body,
|
||||
sourceIconName,
|
||||
notificationIcon,
|
||||
action,
|
||||
isTransient,
|
||||
) {
|
||||
let source = MessageTray.getSystemSource()
|
||||
let notification = new MessageTray.Notification({
|
||||
source,
|
||||
title,
|
||||
body,
|
||||
isTransient: isTransient || false,
|
||||
gicon: notificationIcon || null,
|
||||
})
|
||||
|
||||
if (sourceIconName) source.iconName = sourceIconName
|
||||
|
||||
if (action) {
|
||||
if (!(action instanceof Array)) {
|
||||
action = [action]
|
||||
}
|
||||
|
||||
action.forEach((a) => notification.addAction(a.text, a.func))
|
||||
}
|
||||
|
||||
source.addNotification(notification)
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a copy of the same function in utils.js, but also adjust horizontal scrolling
|
||||
* and perform few further cheks on the current value to avoid changing the values when
|
||||
* it would be clamp to the current one in any case.
|
||||
* Return the amount of shift applied
|
||||
*/
|
||||
export const ensureActorVisibleInScrollView = function (
|
||||
scrollView,
|
||||
actor,
|
||||
fadeSize,
|
||||
onComplete,
|
||||
) {
|
||||
const vadjustment = scrollView.vadjustment
|
||||
const hadjustment = scrollView.hadjustment
|
||||
let [vvalue, , vupper, , , vpageSize] = vadjustment.get_values()
|
||||
let [hvalue, , hupper, , , hpageSize] = hadjustment.get_values()
|
||||
|
||||
let [hvalue0, vvalue0] = [hvalue, vvalue]
|
||||
|
||||
let voffset = fadeSize
|
||||
let hoffset = fadeSize
|
||||
|
||||
let box = actor.get_allocation_box()
|
||||
let y1 = box.y1,
|
||||
y2 = box.y2,
|
||||
x1 = box.x1,
|
||||
x2 = box.x2
|
||||
|
||||
let parent = actor.get_parent()
|
||||
while (parent != scrollView) {
|
||||
if (!parent) throw new Error('actor not in scroll view')
|
||||
|
||||
let box = parent.get_allocation_box()
|
||||
y1 += box.y1
|
||||
y2 += box.y1
|
||||
x1 += box.x1
|
||||
x2 += box.x1
|
||||
parent = parent.get_parent()
|
||||
}
|
||||
|
||||
if (y1 < vvalue + voffset) vvalue = Math.max(0, y1 - voffset)
|
||||
else if (vvalue < vupper - vpageSize && y2 > vvalue + vpageSize - voffset)
|
||||
vvalue = Math.min(vupper - vpageSize, y2 + voffset - vpageSize)
|
||||
|
||||
if (x1 < hvalue + hoffset) hvalue = Math.max(0, x1 - hoffset)
|
||||
else if (hvalue < hupper - hpageSize && x2 > hvalue + hpageSize - hoffset)
|
||||
hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize)
|
||||
|
||||
let tweenOpts = {
|
||||
time: SCROLL_TIME,
|
||||
onComplete: onComplete || (() => {}),
|
||||
transition: 'easeOutQuad',
|
||||
}
|
||||
|
||||
if (vvalue !== vvalue0) {
|
||||
animate(vadjustment, mergeObjects(tweenOpts, { value: vvalue }))
|
||||
}
|
||||
|
||||
if (hvalue !== hvalue0) {
|
||||
animate(hadjustment, mergeObjects(tweenOpts, { value: hvalue }))
|
||||
}
|
||||
|
||||
return [hvalue - hvalue0, vvalue - vvalue0]
|
||||
}
|
||||
|
||||
/**
|
||||
* ColorUtils is adapted from https://github.com/micheleg/dash-to-dock
|
||||
*/
|
||||
let colorNs = Clutter.Color ? Clutter : Cogl
|
||||
|
||||
export const ColorUtils = {
|
||||
color_from_string: colorNs.color_from_string,
|
||||
Color: colorNs.Color,
|
||||
|
||||
colorLuminance(r, g, b, dlum) {
|
||||
// Darken or brighten color by a fraction dlum
|
||||
// Each rgb value is modified by the same fraction.
|
||||
// Return "#rrggbb" strin
|
||||
|
||||
let rgbString = '#'
|
||||
|
||||
rgbString += ColorUtils._decimalToHex(
|
||||
Math.round(Math.min(Math.max(r * (1 + dlum), 0), 255)),
|
||||
2,
|
||||
)
|
||||
rgbString += ColorUtils._decimalToHex(
|
||||
Math.round(Math.min(Math.max(g * (1 + dlum), 0), 255)),
|
||||
2,
|
||||
)
|
||||
rgbString += ColorUtils._decimalToHex(
|
||||
Math.round(Math.min(Math.max(b * (1 + dlum), 0), 255)),
|
||||
2,
|
||||
)
|
||||
|
||||
return rgbString
|
||||
},
|
||||
|
||||
_decimalToHex(d, padding) {
|
||||
// Convert decimal to an hexadecimal string adding the desired padding
|
||||
|
||||
let hex = d.toString(16)
|
||||
while (hex.length < padding) hex = '0' + hex
|
||||
return hex
|
||||
},
|
||||
|
||||
HSVtoRGB(h, s, v) {
|
||||
// Convert hsv ([0-1, 0-1, 0-1]) to rgb ([0-255, 0-255, 0-255]).
|
||||
// Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV
|
||||
// here with h = [0,1] instead of [0, 360]
|
||||
// Accept either (h,s,v) independently or {h:h, s:s, v:v} object.
|
||||
// Return {r:r, g:g, b:b} object.
|
||||
|
||||
if (arguments.length === 1) {
|
||||
s = h.s
|
||||
v = h.v
|
||||
h = h.h
|
||||
}
|
||||
|
||||
let r, g, b
|
||||
let c = v * s
|
||||
let h1 = h * 6
|
||||
let x = c * (1 - Math.abs((h1 % 2) - 1))
|
||||
let m = v - c
|
||||
|
||||
if (h1 <= 1) (r = c + m), (g = x + m), (b = m)
|
||||
else if (h1 <= 2) (r = x + m), (g = c + m), (b = m)
|
||||
else if (h1 <= 3) (r = m), (g = c + m), (b = x + m)
|
||||
else if (h1 <= 4) (r = m), (g = x + m), (b = c + m)
|
||||
else if (h1 <= 5) (r = x + m), (g = m), (b = c + m)
|
||||
else (r = c + m), (g = m), (b = x + m)
|
||||
|
||||
return {
|
||||
r: Math.round(r * 255),
|
||||
g: Math.round(g * 255),
|
||||
b: Math.round(b * 255),
|
||||
}
|
||||
},
|
||||
|
||||
RGBtoHSV(r, g, b) {
|
||||
// Convert rgb ([0-255, 0-255, 0-255]) to hsv ([0-1, 0-1, 0-1]).
|
||||
// Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV
|
||||
// here with h = [0,1] instead of [0, 360]
|
||||
// Accept either (r,g,b) independently or {r:r, g:g, b:b} object.
|
||||
// Return {h:h, s:s, v:v} object.
|
||||
|
||||
if (arguments.length === 1) {
|
||||
r = r.r
|
||||
g = r.g
|
||||
b = r.b
|
||||
}
|
||||
|
||||
let h, s, v
|
||||
|
||||
let M = Math.max(r, g, b)
|
||||
let m = Math.min(r, g, b)
|
||||
let c = M - m
|
||||
|
||||
if (c == 0) h = 0
|
||||
else if (M == r) h = ((g - b) / c) % 6
|
||||
else if (M == g) h = (b - r) / c + 2
|
||||
else h = (r - g) / c + 4
|
||||
|
||||
h = h / 6
|
||||
v = M / 255
|
||||
if (M !== 0) s = c / M
|
||||
else s = 0
|
||||
|
||||
return { h: h, s: s, v: v }
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* DominantColorExtractor is adapted from https://github.com/micheleg/dash-to-dock
|
||||
*/
|
||||
let themeLoader = null
|
||||
let iconCacheMap = new Map()
|
||||
const MAX_CACHED_ITEMS = 1000
|
||||
const BATCH_SIZE_TO_DELETE = 50
|
||||
const DOMINANT_COLOR_ICON_SIZE = 64
|
||||
|
||||
export const DominantColorExtractor = class {
|
||||
constructor(app) {
|
||||
this._app = app
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get the pixel buffer for the current icon, if not fail gracefully
|
||||
*/
|
||||
_getIconPixBuf() {
|
||||
let iconTexture = this._app.create_icon_texture(16)
|
||||
|
||||
if (themeLoader === null) {
|
||||
themeLoader = new St.IconTheme()
|
||||
}
|
||||
|
||||
// Unable to load the icon texture, use fallback
|
||||
if (iconTexture instanceof St.Icon === false) {
|
||||
return null
|
||||
}
|
||||
|
||||
iconTexture = iconTexture.get_gicon()
|
||||
|
||||
// Unable to load the icon texture, use fallback
|
||||
if (iconTexture === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (iconTexture instanceof Gio.FileIcon) {
|
||||
// Use GdkPixBuf to load the pixel buffer from the provided file path
|
||||
return GdkPixbuf.Pixbuf.new_from_file(iconTexture.get_file().get_path())
|
||||
}
|
||||
|
||||
// Get the pixel buffer from the icon theme
|
||||
if (iconTexture instanceof Gio.ThemedIcon) {
|
||||
let icon_info = themeLoader.lookup_icon(
|
||||
iconTexture.get_names()[0],
|
||||
DOMINANT_COLOR_ICON_SIZE,
|
||||
0,
|
||||
)
|
||||
|
||||
if (icon_info !== null) {
|
||||
return icon_info.load_icon()
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* The backlight color choosing algorithm was mostly ported to javascript from the
|
||||
* Unity7 C++ source of Canonicals:
|
||||
* https://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/launcher/LauncherIcon.cpp
|
||||
* so it more or less works the same way.
|
||||
*/
|
||||
_getColorPalette() {
|
||||
if (iconCacheMap.get(this._app.get_id())) {
|
||||
// We already know the answer
|
||||
return iconCacheMap.get(this._app.get_id())
|
||||
}
|
||||
|
||||
let pixBuf = this._getIconPixBuf()
|
||||
if (pixBuf == null) return null
|
||||
|
||||
let pixels = pixBuf.get_pixels()
|
||||
|
||||
let total = 0,
|
||||
rTotal = 0,
|
||||
gTotal = 0,
|
||||
bTotal = 0
|
||||
|
||||
let resample_y = 1,
|
||||
resample_x = 1
|
||||
|
||||
// Resampling of large icons
|
||||
// We resample icons larger than twice the desired size, as the resampling
|
||||
// to a size s
|
||||
// DOMINANT_COLOR_ICON_SIZE < s < 2*DOMINANT_COLOR_ICON_SIZE,
|
||||
// most of the case exactly DOMINANT_COLOR_ICON_SIZE as the icon size is tipycally
|
||||
// a multiple of it.
|
||||
let width = pixBuf.get_width()
|
||||
let height = pixBuf.get_height()
|
||||
|
||||
// Resample
|
||||
if (height >= 2 * DOMINANT_COLOR_ICON_SIZE)
|
||||
resample_y = Math.floor(height / DOMINANT_COLOR_ICON_SIZE)
|
||||
|
||||
if (width >= 2 * DOMINANT_COLOR_ICON_SIZE)
|
||||
resample_x = Math.floor(width / DOMINANT_COLOR_ICON_SIZE)
|
||||
|
||||
if (resample_x !== 1 || resample_y !== 1)
|
||||
pixels = this._resamplePixels(pixels, resample_x, resample_y)
|
||||
|
||||
// computing the limit outside the for (where it would be repeated at each iteration)
|
||||
// for performance reasons
|
||||
let limit = pixels.length
|
||||
for (let offset = 0; offset < limit; offset += 4) {
|
||||
let r = pixels[offset],
|
||||
g = pixels[offset + 1],
|
||||
b = pixels[offset + 2],
|
||||
a = pixels[offset + 3]
|
||||
|
||||
let saturation = Math.max(r, g, b) - Math.min(r, g, b)
|
||||
let relevance = 0.1 * 255 * 255 + 0.9 * a * saturation
|
||||
|
||||
rTotal += r * relevance
|
||||
gTotal += g * relevance
|
||||
bTotal += b * relevance
|
||||
|
||||
total += relevance
|
||||
}
|
||||
|
||||
total = total * 255
|
||||
|
||||
let r = rTotal / total,
|
||||
g = gTotal / total,
|
||||
b = bTotal / total
|
||||
|
||||
let hsv = ColorUtils.RGBtoHSV(r * 255, g * 255, b * 255)
|
||||
|
||||
if (hsv.s > 0.15) hsv.s = 0.65
|
||||
hsv.v = 0.9
|
||||
|
||||
let rgb = ColorUtils.HSVtoRGB(hsv.h, hsv.s, hsv.v)
|
||||
|
||||
// Cache the result.
|
||||
let backgroundColor = {
|
||||
lighter: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0.2),
|
||||
original: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0),
|
||||
darker: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, -0.5),
|
||||
}
|
||||
|
||||
if (iconCacheMap.size >= MAX_CACHED_ITEMS) {
|
||||
//delete oldest cached values (which are in order of insertions)
|
||||
let ctr = 0
|
||||
for (let key of iconCacheMap.keys()) {
|
||||
if (++ctr > BATCH_SIZE_TO_DELETE) break
|
||||
iconCacheMap.delete(key)
|
||||
}
|
||||
}
|
||||
|
||||
iconCacheMap.set(this._app.get_id(), backgroundColor)
|
||||
|
||||
return backgroundColor
|
||||
}
|
||||
|
||||
/**
|
||||
* Downsample large icons before scanning for the backlight color to
|
||||
* improve performance.
|
||||
*
|
||||
* @param pixBuf
|
||||
* @param pixels
|
||||
* @param resampleX
|
||||
* @param resampleY
|
||||
*
|
||||
* @return [];
|
||||
*/
|
||||
_resamplePixels(pixels, resampleX, resampleY) {
|
||||
let resampledPixels = []
|
||||
// computing the limit outside the for (where it would be repeated at each iteration)
|
||||
// for performance reasons
|
||||
let limit = pixels.length / (resampleX * resampleY) / 4
|
||||
for (let i = 0; i < limit; i++) {
|
||||
let pixel = i * resampleX * resampleY
|
||||
|
||||
resampledPixels.push(pixels[pixel * 4])
|
||||
resampledPixels.push(pixels[pixel * 4 + 1])
|
||||
resampledPixels.push(pixels[pixel * 4 + 2])
|
||||
resampledPixels.push(pixels[pixel * 4 + 3])
|
||||
}
|
||||
|
||||
return resampledPixels
|
||||
}
|
||||
}
|
||||
|
||||
export const drawRoundedLine = function (
|
||||
cr,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
isRoundLeft,
|
||||
isRoundRight,
|
||||
stroke,
|
||||
fill,
|
||||
) {
|
||||
if (height > width) {
|
||||
y += Math.floor((height - width) / 2.0)
|
||||
height = width
|
||||
}
|
||||
|
||||
height = 2.0 * Math.floor(height / 2.0)
|
||||
|
||||
const leftRadius = isRoundLeft ? height / 2.0 : 0.0
|
||||
const rightRadius = isRoundRight ? height / 2.0 : 0.0
|
||||
|
||||
cr.moveTo(x + width - rightRadius, y)
|
||||
cr.lineTo(x + leftRadius, y)
|
||||
if (isRoundLeft)
|
||||
cr.arcNegative(
|
||||
x + leftRadius,
|
||||
y + leftRadius,
|
||||
leftRadius,
|
||||
-Math.PI / 2,
|
||||
Math.PI / 2,
|
||||
)
|
||||
else cr.lineTo(x, y + height)
|
||||
cr.lineTo(x + width - rightRadius, y + height)
|
||||
if (isRoundRight)
|
||||
cr.arcNegative(
|
||||
x + width - rightRadius,
|
||||
y + rightRadius,
|
||||
rightRadius,
|
||||
Math.PI / 2,
|
||||
-Math.PI / 2,
|
||||
)
|
||||
else cr.lineTo(x + width, y)
|
||||
cr.closePath()
|
||||
|
||||
if (fill != null) {
|
||||
cr.setSource(fill)
|
||||
cr.fillPreserve()
|
||||
}
|
||||
if (stroke != null) cr.setSource(stroke)
|
||||
cr.stroke()
|
||||
}
|
||||
1427
src/windowPreview.js
Normal file
1427
src/windowPreview.js
Normal file
File diff suppressed because it is too large
Load Diff
1628
taskbar.js
1628
taskbar.js
File diff suppressed because it is too large
Load Diff
287
transparency.js
287
transparency.js
@@ -1,287 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* 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 * 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;
|
||||
|
||||
this._initialPanelStyle = dtpPanel.panel.get_style();
|
||||
|
||||
this._signalsHandler = new Utils.GlobalSignalsHandler();
|
||||
this._bindSignals();
|
||||
|
||||
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-use-border',
|
||||
'changed::trans-border-use-custom-color',
|
||||
'changed::trans-border-custom-color',
|
||||
'changed::trans-border-width',
|
||||
],
|
||||
() => this._updateBorderAndSet()
|
||||
],
|
||||
[
|
||||
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._updateBorder();
|
||||
this._updateGradient();
|
||||
this._setBackground();
|
||||
this._setGradient();
|
||||
}
|
||||
|
||||
_updateColorAndSet() {
|
||||
this._updateColor();
|
||||
this._setBackground();
|
||||
}
|
||||
|
||||
_updateAlphaAndSet() {
|
||||
this._updateAlpha();
|
||||
this._setBackground();
|
||||
}
|
||||
|
||||
_updateGradientAndSet() {
|
||||
this._updateGradient();
|
||||
this._setGradient();
|
||||
}
|
||||
|
||||
_updateBorderAndSet() {
|
||||
this._updateBorder();
|
||||
this._setBackground();
|
||||
}
|
||||
|
||||
_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());
|
||||
}
|
||||
|
||||
_updateBorder() {
|
||||
let rgba = this._dtpPanel._getDefaultLineColor(Utils.checkIfColorIsBright(this.backgroundColorRgb)); // supply parameter manually or else an exception (something is undefined) will arise
|
||||
const isLineCustom = SETTINGS.get_boolean('trans-border-use-custom-color');
|
||||
rgba = isLineCustom ? SETTINGS.get_string('trans-border-custom-color') : rgba;
|
||||
|
||||
const showBorder = SETTINGS.get_boolean('trans-use-border');
|
||||
const borderWidth = SETTINGS.get_int('trans-border-width');
|
||||
|
||||
const position = this._dtpPanel.getPosition();
|
||||
let borderPosition = '';
|
||||
if (position == St.Side.LEFT) { borderPosition = 'right'; }
|
||||
if (position == St.Side.RIGHT) { borderPosition = 'left'; }
|
||||
if (position == St.Side.TOP) { borderPosition = 'bottom'; }
|
||||
if (position == St.Side.BOTTOM) { borderPosition = 'top'; }
|
||||
|
||||
const style = `border: 0 solid ${rgba}; border-${borderPosition}-width:${borderWidth}px;`;
|
||||
this._borderStyle = showBorder ? style : '';
|
||||
}
|
||||
|
||||
_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 + this._borderStyle);
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
|
||||
<object class="GtkBox" id="box_advanced_options">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="width-request">600</property>
|
||||
<property name="spacing">24</property>
|
||||
<property name="margin-top">32</property>
|
||||
<property name="margin-bottom">32</property>
|
||||
<property name="margin-start">32</property>
|
||||
<property name="margin-end">32</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Nothing yet!</property>
|
||||
<property name="subtitle" translatable="yes">For real...</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
</interface>
|
||||
@@ -18,14 +18,14 @@
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="animate_appicon_hover_options_travel_adjustment">
|
||||
<property name="lower">0</property>
|
||||
<property name="lower">-100</property>
|
||||
<property name="upper">100</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">5</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="animate_appicon_hover_options_zoom_adjustment">
|
||||
<property name="lower">100</property>
|
||||
<property name="lower">10</property>
|
||||
<property name="upper">250</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">5</property>
|
||||
|
||||
70
ui/BoxHighlightAppIconHoverOptions.ui
Normal file
70
ui/BoxHighlightAppIconHoverOptions.ui
Normal file
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
|
||||
<!-- adjustments -->
|
||||
<object class="GtkAdjustment" id="highlight_appicon_borderradius_adjustment">
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">10</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">2</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkBox" id="highlight_appicon_hover_options">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="width-request">600</property>
|
||||
<property name="spacing">24</property>
|
||||
<property name="margin-top">32</property>
|
||||
<property name="margin-bottom">32</property>
|
||||
<property name="margin-start">32</property>
|
||||
<property name="margin-end">32</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Highlight AppIcon color</property>
|
||||
<child>
|
||||
<object class="GtkColorButton" id="highlight_appicon_color">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="use_alpha">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Pressed AppIcon color</property>
|
||||
<child>
|
||||
<object class="GtkColorButton" id="pressed_appicon_color">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="use_alpha">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Highlight AppIcon border radius</property>
|
||||
<property name="subtitle" translatable="yes">Overrides global border radius (default is 0)</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="highlight_appicon_borderradius">
|
||||
<property name="width-request">300</property>
|
||||
<property name="adjustment">highlight_appicon_borderradius_adjustment</property>
|
||||
<property name="round_digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="value_pos">right</property>
|
||||
<property name="draw_value">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
|
||||
</object>
|
||||
|
||||
</interface>
|
||||
@@ -1,64 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<interface>
|
||||
<!-- interface-name BoxIntellihideOptions.ui -->
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
|
||||
<requires lib="libadwaita" version="1.3"/>
|
||||
<object class="GtkAdjustment" id="intellihide_pressure_threshold_adjustment">
|
||||
<property name="lower">1</property>
|
||||
<property name="page-increment">100</property>
|
||||
<property name="step-increment">10</property>
|
||||
<property name="upper">9990</property>
|
||||
<property name="step_increment">10</property>
|
||||
<property name="page_increment">100</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="intellihide_pressure_time_adjustment">
|
||||
<property name="lower">1</property>
|
||||
<property name="page-increment">100</property>
|
||||
<property name="step-increment">10</property>
|
||||
<property name="upper">5000</property>
|
||||
<property name="step_increment">10</property>
|
||||
<property name="page_increment">100</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="intellihide_animation_time_adjustment">
|
||||
<property name="lower">10</property>
|
||||
<property name="page-increment">100</property>
|
||||
<property name="step-increment">10</property>
|
||||
<property name="upper">2000</property>
|
||||
<property name="step_increment">10</property>
|
||||
<property name="page_increment">100</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="intellihide_close_delay_adjustment">
|
||||
<property name="lower">10</property>
|
||||
<property name="page-increment">100</property>
|
||||
<property name="step-increment">10</property>
|
||||
<property name="upper">4000</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="intellihide_reveal_delay_adjustment">
|
||||
<property name="lower">0</property>
|
||||
<property name="page-increment">100</property>
|
||||
<property name="step-increment">10</property>
|
||||
<property name="upper">4000</property>
|
||||
<property name="step_increment">10</property>
|
||||
<property name="page_increment">100</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="intellihide_enable_hide_delay_adjustment">
|
||||
<property name="page-increment">100</property>
|
||||
<property name="step-increment">10</property>
|
||||
<property name="upper">10000</property>
|
||||
<property name="step_increment">10</property>
|
||||
<property name="page_increment">100</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkBox" id="box_intellihide_options">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="width-request">600</property>
|
||||
<property name="spacing">24</property>
|
||||
<property name="margin-top">32</property>
|
||||
<property name="margin-bottom">32</property>
|
||||
<property name="margin-start">32</property>
|
||||
<property name="margin-end">32</property>
|
||||
|
||||
<property name="margin-start">32</property>
|
||||
<property name="margin-top">32</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">24</property>
|
||||
<property name="width-request">600</property>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Only hide the panel when it is obstructed by windows</property>
|
||||
<property name="title" translatable="yes">Only hide the panel from windows</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="intellihide_window_hide_switch">
|
||||
<property name="valign">center</property>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-end">10</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="intellihide_window_hide_button">
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Overlapping</property>
|
||||
<property name="name">4</property>
|
||||
<property name="use-markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="intellihide_window_monitor_hide_button">
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">On same monitor</property>
|
||||
<property name="name">4</property>
|
||||
<property name="use-markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow" id="intellihide_behaviour_options">
|
||||
<property name="title" translatable="yes">The panel hides from</property>
|
||||
@@ -74,16 +101,67 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Require pressure at the edge of the screen to reveal the panel</property>
|
||||
<property name="title" translatable="yes">Touching the monitor's edge with the pointer reveals the panel</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="intellihide_use_pointer_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="intellihide_use_pointer_limit_button">
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Limit to panel length</property>
|
||||
<property name="name">4</property>
|
||||
<property name="use-markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow" id="intellihide_revealed_hover_options">
|
||||
<property name="title" translatable="yes">Hovering the panel area keeps the panel revealed</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="intellihide_revealed_hover_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="intellihide_revealed_hover_limit_button">
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Limit to panel length</property>
|
||||
<property name="name">4</property>
|
||||
<property name="use-markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow" id="intellihide_use_pressure_options">
|
||||
<property name="title" translatable="yes">Require pressure at the edge of the monitor to reveal the panel</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="intellihide_use_pressure_switch">
|
||||
<property name="valign">center</property>
|
||||
@@ -91,43 +169,38 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow" id="intellihide_use_pressure_options">
|
||||
<object class="AdwActionRow" id="intellihide_use_pressure_options2">
|
||||
<property name="title" translatable="yes">Required pressure threshold (px)</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="intellihide_pressure_threshold_spinbutton">
|
||||
<property name="valign">center</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="text">0</property>
|
||||
<property name="adjustment">intellihide_pressure_threshold_adjustment</property>
|
||||
<property name="numeric">True</property>
|
||||
<property name="text">0</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="width-chars">4</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow" id="intellihide_use_pressure_options2">
|
||||
<object class="AdwActionRow" id="intellihide_use_pressure_options3">
|
||||
<property name="title" translatable="yes">Required pressure timeout (ms)</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="intellihide_pressure_time_spinbutton">
|
||||
<property name="valign">center</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="text">0</property>
|
||||
<property name="adjustment">intellihide_pressure_time_adjustment</property>
|
||||
<property name="numeric">True</property>
|
||||
<property name="text">0</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="width-chars">4</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Allow the panel to be revealed while in fullscreen mode</property>
|
||||
@@ -138,11 +211,10 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow" id="grid_intellihide_only_secondary">
|
||||
<property name="title" translatable="yes">Only hide secondary panels</property>
|
||||
<property name="subtitle" translatable="yes">(requires multi-monitors option)</property>
|
||||
<property name="title" translatable="yes">Only hide secondary panels</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="intellihide_only_secondary_switch">
|
||||
<property name="valign">center</property>
|
||||
@@ -150,77 +222,104 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Keyboard shortcut to reveal and hold the panel</property>
|
||||
<property name="subtitle" translatable="yes">Syntax: &lt;Shift&gt;, &lt;Ctrl&gt;, &lt;Alt&gt;, &lt;Super&gt;</property>
|
||||
<property name="title" translatable="yes">Keyboard shortcut to reveal and hold the panel</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="intellihide_toggle_entry">
|
||||
<property name="placeholder-text" translatable="yes">e.g. <Super>i</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="width-chars">12</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow" id="grid_intellihide_persist_state">
|
||||
<property name="title" translatable="yes">Persist state across restarts</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="intellihide_persist_state_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(respects Gnome "Do Not Disturb" and requires show notification counter badge option)</property>
|
||||
<property name="title" translatable="yes">Reveal and hold the panel on notification</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="intellihide_show_on_notification_switch">
|
||||
<property name="valign">center</property>
|
||||
<property name="width_chars">12</property>
|
||||
<property name="placeholder_text" translatable="yes">e.g. <Super>i</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Hide and reveal animation duration (ms)</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="intellihide_animation_time_spinbutton">
|
||||
<property name="valign">center</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="text">0</property>
|
||||
<property name="adjustment">intellihide_animation_time_adjustment</property>
|
||||
<property name="numeric">True</property>
|
||||
<property name="text">0</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="width-chars">4</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Delay before hiding the panel (ms)</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="intellihide_close_delay_spinbutton">
|
||||
<property name="valign">center</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="text">10</property>
|
||||
<property name="adjustment">intellihide_close_delay_adjustment</property>
|
||||
<property name="numeric">True</property>
|
||||
<property name="text">10</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="value">10</property>
|
||||
<property name="width-chars">4</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Delay before revealing the panel (ms)</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="intellihide_reveal_delay_spinbutton">
|
||||
<property name="adjustment">intellihide_reveal_delay_adjustment</property>
|
||||
<property name="numeric">True</property>
|
||||
<property name="text">10</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="value">10</property>
|
||||
<property name="width-chars">4</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Delay before enabling intellihide on start (ms)</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="intellihide_enable_start_delay_spinbutton">
|
||||
<property name="valign">center</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="text">10</property>
|
||||
<property name="adjustment">intellihide_enable_hide_delay_adjustment</property>
|
||||
<property name="numeric">True</property>
|
||||
<property name="text">10</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="value">10</property>
|
||||
<property name="width-chars">4</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
|
||||
</interface>
|
||||
@@ -29,6 +29,7 @@
|
||||
<item id="CYCLE-MIN" translatable="yes">Cycle windows + minimize</item>
|
||||
<item id="TOGGLE-SHOWPREVIEW" translatable="yes">Toggle single / Preview multiple</item>
|
||||
<item id="TOGGLE-CYCLE" translatable="yes">Toggle single / Cycle multiple</item>
|
||||
<item id="TOGGLE-SPREAD" translatable="yes">Toggle single / Spread multiple</item>
|
||||
<item id="QUIT" translatable="yes">Quit</item>
|
||||
</items>
|
||||
</object>
|
||||
@@ -57,6 +58,7 @@
|
||||
<item id="CYCLE-MIN" translatable="yes">Cycle windows + minimize</item>
|
||||
<item id="TOGGLE-SHOWPREVIEW" translatable="yes">Toggle single / Preview multiple</item>
|
||||
<item id="TOGGLE-CYCLE" translatable="yes">Toggle single / Cycle multiple</item>
|
||||
<item id="TOGGLE-SPREAD" translatable="yes">Toggle single / Spread multiple</item>
|
||||
<item id="QUIT" translatable="yes">Quit</item>
|
||||
</items>
|
||||
</object>
|
||||
@@ -85,6 +87,7 @@
|
||||
<item id="CYCLE-MIN" translatable="yes">Cycle windows + minimize</item>
|
||||
<item id="TOGGLE-SHOWPREVIEW" translatable="yes">Toggle single / Preview multiple</item>
|
||||
<item id="TOGGLE-CYCLE" translatable="yes">Toggle single / Cycle multiple</item>
|
||||
<item id="TOGGLE-SPREAD" translatable="yes">Toggle single / Spread multiple</item>
|
||||
<item id="QUIT" translatable="yes">Quit</item>
|
||||
</items>
|
||||
</object>
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<interface>
|
||||
<!-- interface-name BoxOverlayShortcut.ui -->
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
|
||||
<requires lib="libadwaita" version="1.3"/>
|
||||
<object class="GtkAdjustment" id="shortcut_time_adjustment">
|
||||
<property name="page-increment">1000</property>
|
||||
<property name="step-increment">250</property>
|
||||
<property name="upper">10000</property>
|
||||
<property name="step_increment">250</property>
|
||||
<property name="page_increment">1000</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkBox" id="box_overlay_shortcut">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="width-request">600</property>
|
||||
<property name="spacing">24</property>
|
||||
<property name="margin-top">32</property>
|
||||
<property name="margin-bottom">32</property>
|
||||
<property name="margin-start">32</property>
|
||||
<property name="margin-end">32</property>
|
||||
|
||||
<property name="margin-start">32</property>
|
||||
<property name="margin-top">32</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">24</property>
|
||||
<property name="width-request">600</property>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Hotkeys prefix</property>
|
||||
<property name="subtitle" translatable="yes">Hotkeys will either be Super+Number or Super+Alt+Num</property>
|
||||
<property name="title" translatable="yes">Hotkeys prefix</property>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="hotkey_prefix_combo">
|
||||
<property name="valign">center</property>
|
||||
@@ -35,11 +33,10 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Number overlay</property>
|
||||
<property name="subtitle" translatable="yes">Temporarily show the application numbers over the icons when using the hotkeys.</property>
|
||||
<property name="title" translatable="yes">Number overlay</property>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="overlay_combo">
|
||||
<property name="valign">center</property>
|
||||
@@ -52,49 +49,56 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Hide timeout (ms)</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="timeout_spinbutton">
|
||||
<property name="valign">center</property>
|
||||
<property name="adjustment">shortcut_time_adjustment</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Shortcut to show the overlay for 2 seconds</property>
|
||||
<property name="subtitle" translatable="yes">Syntax: &lt;Shift&gt;, &lt;Ctrl&gt;, &lt;Alt&gt;, &lt;Super&gt;</property>
|
||||
<property name="title" translatable="yes">Shortcut to show the overlay for 2 seconds</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="shortcut_entry">
|
||||
<property name="placeholder-text" translatable="yes">e.g. <Super>q</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="width_chars">12</property>
|
||||
<property name="placeholder_text" translatable="yes">e.g. <Super>q</property>
|
||||
<property name="width-chars">12</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Show window previews on hotkey</property>
|
||||
<property name="subtitle" translatable="yes">Show previews when the application have multiple instances</property>
|
||||
<property name="subtitle" translatable="yes">On secondary monitors, show the overlay on icons matching the primary monitor</property>
|
||||
<property name="title" translatable="yes">Show the overlay on all monitors</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="shortcut_preview_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
<object class="GtkSwitch" id="overlay_on_secondary_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">Show previews when the application have multiple instances</property>
|
||||
<property name="title" translatable="yes">Show window previews on hotkey</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="shortcut_preview_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Hotkeys are activated with</property>
|
||||
<property name="subtitle" translatable="yes">Select which keyboard number keys are used to activate the hotkeys</property>
|
||||
<property name="title" translatable="yes">Hotkeys are activated with</property>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="shortcut_num_keys_combo">
|
||||
<property name="valign">center</property>
|
||||
@@ -107,9 +111,7 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
</interface>
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><i>Show Details</i> menu item</property>
|
||||
<property name="title" translatable="yes"><i>App Details</i> menu item</property>
|
||||
<property name="subtitle" translatable="yes"><i>App Details</i> is only available when Gnome Software is installed</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="secondarymenu_showdetails_switch">
|
||||
<property name="valign">center</property>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Override Show Desktop line color</property>
|
||||
<child>
|
||||
<object class="GtkColorButton" id="override_show_desktop_line_color_colorbutton">>
|
||||
<object class="GtkColorButton" id="override_show_desktop_line_color_colorbutton">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="use_alpha">True</property>
|
||||
|
||||
@@ -105,8 +105,12 @@
|
||||
<property name="title" translatable="yes">Time (ms) before hiding</property>
|
||||
<property name="subtitle" translatable="yes">(100 is default)</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="preview_immediate_click_button">
|
||||
<property name="receives_default">False</property>
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="preview_immediate_click_button">
|
||||
<property name="receives_default">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="preview_immediate_click_label">
|
||||
<property name="name">4</property>
|
||||
|
||||
@@ -1,99 +1,121 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<interface>
|
||||
<!-- interface-name SettingsAbout.ui -->
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
|
||||
<requires lib="libadwaita" version="1.6"/>
|
||||
<object class="AdwPreferencesPage" id="about">
|
||||
<property name="icon-name">help-about-symbolic</property>
|
||||
<property name="title" translatable="yes">About</property>
|
||||
<property name="icon_name">help-about-symbolic</property>
|
||||
|
||||
<!-- group info -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="about_group_info">
|
||||
<property name="title" translatable="yes">Info</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Version</property>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="about_group_info">
|
||||
<property name="title" translatable="yes">Info</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Version</property>
|
||||
<child>
|
||||
<object class="GtkLinkButton" id="extension_version"/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Source</property>
|
||||
<child>
|
||||
<object class="GtkLinkButton" id="homepage_link">
|
||||
<property name="halign">center</property>
|
||||
<property name="label" translatable="yes">GitHub</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="uri">https://github.com/home-sweet-gnome/dash-to-panel</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="about_group_export_and_import">
|
||||
<property name="title" translatable="yes">Export and Import</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">Use the buttons below to create a settings file from your current preferences that can be imported on a different machine.</property>
|
||||
<property name="title" translatable="yes">Export and import settings</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesRow">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="halign">end</property>
|
||||
<property name="margin-bottom">4</property>
|
||||
<property name="margin-end">8</property>
|
||||
<property name="margin-start">8</property>
|
||||
<property name="margin-top">4</property>
|
||||
<property name="spacing">8</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="importexport_export_button">
|
||||
<property name="label" translatable="yes">Export to file</property>
|
||||
<property name="receives-default">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="importexport_import_button">
|
||||
<property name="label" translatable="yes">Import from file</property>
|
||||
<property name="receives-default">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="about_group_disclaimer">
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="justify">center</property>
|
||||
<property name="label" translatable="yes"><span size="small">This program comes with ABSOLUTELY NO WARRANTY.
|
||||
See the <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GNU General Public License, version 2 or later</a> for details.</span></property>
|
||||
<property name="use-markup">True</property>
|
||||
<property name="wrap">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="about_group_sponsor">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin-top">64</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="extension_version">
|
||||
<property name="label">...</property>
|
||||
<object class="GtkLabel">
|
||||
<property name="justify">center</property>
|
||||
<property name="label" translatable="yes">Sponsored and originally developed by</property>
|
||||
<property name="wrap">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Source</property>
|
||||
<child>
|
||||
<object class="GtkLinkButton" id="homepage_link">
|
||||
<property name="label" translatable="yes">GitHub</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="uri">https://github.com/home-sweet-gnome/dash-to-panel</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group export import -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="about_group_export_and_import">
|
||||
<property name="title" translatable="yes">Export and Import</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Export and import settings</property>
|
||||
<property name="subtitle" translatable="yes">Use the buttons below to create a settings file from your current preferences that can be imported on a different machine.</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesRow">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin_start">8</property>
|
||||
<property name="margin_end">8</property>
|
||||
<property name="margin_top">4</property>
|
||||
<property name="margin_bottom">4</property>
|
||||
<property name="spacing">8</property>
|
||||
<property name="halign">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="importexport_export_button">
|
||||
<property name="label" translatable="yes">Export to file</property>
|
||||
<property name="receives_default">True</property>
|
||||
<object class="GtkLinkButton">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkPicture" id="zorin_os_logo">
|
||||
<property name="can-shrink">False</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="importexport_import_button">
|
||||
<property name="label" translatable="yes">Import from file</property>
|
||||
<property name="receives_default">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</property>
|
||||
<property name="uri">https://zorin.com/os/</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group disclaimer -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="about_group_disclaimer">
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="label" translatable="yes"><span size="small">This program comes with ABSOLUTELY NO WARRANTY. See the <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GNU General Public License, version 2 or later</a> for details.</span></property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">center</property>
|
||||
<property name="wrap">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<interface>
|
||||
<!-- interface-name SettingsAction.ui -->
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
|
||||
<requires lib="libadwaita" version="1.6"/>
|
||||
<object class="AdwPreferencesPage" id="action">
|
||||
<property name="icon-name">input-mouse-symbolic</property>
|
||||
<property name="title" translatable="yes">Action</property>
|
||||
<property name="icon_name">input-mouse-symbolic</property>
|
||||
|
||||
<!-- group click action -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="action_group_click_action">
|
||||
<property name="title" translatable="yes">Click action</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Click action</property>
|
||||
<property name="subtitle" translatable="yes">Behaviour when clicking on the icon of a running application.</property>
|
||||
<property name="title" translatable="yes">Click action</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="middle_click_options_button">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="middle_click_image">
|
||||
<property name="icon_name">emblem-system-symbolic</property>
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
@@ -37,6 +35,7 @@
|
||||
<item id="CYCLE" translatable="yes">Cycle through windows</item>
|
||||
<item id="TOGGLE-SHOWPREVIEW" translatable="yes">Toggle single / Preview multiple</item>
|
||||
<item id="TOGGLE-CYCLE" translatable="yes">Toggle single / Cycle multiple</item>
|
||||
<item id="TOGGLE-SPREAD" translatable="yes">Toggle single / Spread multiple</item>
|
||||
<item id="MINIMIZE" translatable="yes">Toggle windows</item>
|
||||
<item id="RAISE" translatable="yes">Raise windows</item>
|
||||
<item id="LAUNCH" translatable="yes">Launch new instance</item>
|
||||
@@ -45,29 +44,25 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group scroll action -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="action_group_scroll_action">
|
||||
<property name="title" translatable="yes">Scroll action</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Scroll panel action</property>
|
||||
<property name="subtitle" translatable="yes">Behavior when mouse scrolling over the panel.</property>
|
||||
<property name="title" translatable="yes">Scroll panel action</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="scroll_panel_options_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="scroll_panel_options_button_image">
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="icon_name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
@@ -77,9 +72,9 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="scroll_panel_combo">
|
||||
<property name="visible">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="visible">True</property>
|
||||
<items>
|
||||
<item id="NOTHING" translatable="yes">Do nothing</item>
|
||||
<item id="SWITCH_WORKSPACE" translatable="yes">Switch workspace</item>
|
||||
@@ -90,19 +85,18 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Scroll icon action</property>
|
||||
<property name="subtitle" translatable="yes">Behavior when mouse scrolling over an application icon.</property>
|
||||
<property name="title" translatable="yes">Scroll icon action</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="scroll_icon_options_button">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="scroll_icon_options_button_image">
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="icon_name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
@@ -112,8 +106,8 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="scroll_icon_combo">
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="valign">center</property>
|
||||
<items>
|
||||
<item id="NOTHING" translatable="yes">Do nothing</item>
|
||||
<item id="CYCLE_WINDOWS" translatable="yes">Cycle windows</item>
|
||||
@@ -123,26 +117,22 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group hotkey -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="action_group_hotkry">
|
||||
<object class="AdwPreferencesGroup" id="action_group_hotkey">
|
||||
<property name="title" translatable="yes">Hotkey overlay</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Use hotkeys to activate apps</property>
|
||||
<property name="subtitle" translatable="yes">Enable Super+(0-9) as shortcuts to activate apps. It can also be used together with Shift and Ctrl.</property>
|
||||
<property name="title" translatable="yes">Use hotkeys to activate apps</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="overlay_button">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image_overlay">
|
||||
<property name="icon_name">emblem-system-symbolic</property>
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
@@ -157,9 +147,55 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="action_appicons_group">
|
||||
<property name="title" translatable="yes">Application icons context menu</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(right-click menu)</property>
|
||||
<property name="title" translatable="yes">Secondary menu</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="secondarymenu_options_button">
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="secondarymenu_options_button_image">
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="context_menu_group">
|
||||
<property name="title" translatable="yes">Panel context menu entries</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="context_menu_add_button">
|
||||
<property name="halign">center</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="width-request">100</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">list-add-symbolic</property>
|
||||
<property name="tooltip-text" translatable="yes">Add entry</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,171 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<interface>
|
||||
<!-- interface-name SettingsDonation.ui -->
|
||||
<requires lib="gtk" version="4.12"/>
|
||||
<requires lib="libadwaita" version="1.6"/>
|
||||
<object class="AdwPreferencesPage" id="donation">
|
||||
<property name="hexpand-set">True</property>
|
||||
<property name="icon-name">emote-love-symbolic</property>
|
||||
<property name="name">donation</property>
|
||||
<property name="title" translatable="yes">Donation</property>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="donation_group">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="halign">center</property>
|
||||
<property name="margin-bottom">50</property>
|
||||
<property name="margin-top">50</property>
|
||||
<property name="spacing">16</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="donation_title_icon">
|
||||
<property name="css-classes">error</property>
|
||||
<property name="icon-name">emote-love-symbolic</property>
|
||||
<property name="pixel-size">48</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="donation_logo">
|
||||
<property name="pixel-size">96</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="donation_label_1">
|
||||
<property name="justify">center</property>
|
||||
<property name="label" translatable="yes"><span size="large">Gnome is the best desktop environment. No question. But if you're like me and would never use it without the enhanced workflow that Dash to Panel provides, please support my work by making a donation.</span></property>
|
||||
<property name="margin-bottom">40</property>
|
||||
<property name="use-markup">True</property>
|
||||
<property name="wrap">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="donation_label_2">
|
||||
<property name="justify">center</property>
|
||||
<property name="label" translatable="yes">I know you're thinking "I don't have time for this", but consider that I've poured countless volunteer hours into making Dash to Panel a quality extension that is useful to YOU! :)</property>
|
||||
<property name="margin-bottom">60</property>
|
||||
<property name="use-markup">True</property>
|
||||
<property name="wrap">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="halign">center</property>
|
||||
<property name="margin-bottom">60</property>
|
||||
<property name="spacing">40</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkLinkButton">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="halign">center</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="paypal_logo">
|
||||
<property name="margin-bottom">2</property>
|
||||
<property name="margin-end">2</property>
|
||||
<property name="margin-top">2</property>
|
||||
<property name="pixel-size">24</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Paypal</property>
|
||||
<property name="margin-end">6</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
<property name="css-classes">button</property>
|
||||
<property name="uri">https://www.paypal.com/donate/?hosted_button_id=5DCVELP7BSAVQ</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLinkButton">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="halign">center</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="stripe_logo">
|
||||
<property name="margin-bottom">2</property>
|
||||
<property name="margin-end">2</property>
|
||||
<property name="margin-top">2</property>
|
||||
<property name="pixel-size">24</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Stripe</property>
|
||||
<property name="margin-end">6</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
<property name="css-classes">button</property>
|
||||
<property name="uri">https://donate.stripe.com/9AQg1g8sA5EY1y07ss</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLinkButton">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="halign">center</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="kofi_logo">
|
||||
<property name="margin-bottom">2</property>
|
||||
<property name="margin-end">2</property>
|
||||
<property name="margin-top">2</property>
|
||||
<property name="pixel-size">24</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Ko-fi</property>
|
||||
<property name="margin-end">6</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
<property name="css-classes">button</property>
|
||||
<property name="uri">https://ko-fi.com/charlesgagnon</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRevealer" id="donation_revealer">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes"><span size="9000">Thanks for your time!
|
||||
If you like, you can now hide the donate icon</span></property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="use-markup">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="donation_icon_switch">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
<property name="margin-bottom">20</property>
|
||||
<property name="transition-type">crossfade</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,279 +1,202 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Created with Cambalache 0.94.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
|
||||
<requires lib="libadwaita" version="1.6"/>
|
||||
<object class="GtkAdjustment" id="tray_size_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
<property name="step_increment">0.01</property>
|
||||
<property name="page_increment">0.1</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="leftbox_size_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
<property name="step_increment">0.01</property>
|
||||
<property name="page_increment">0.1</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="tray_padding_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
<property name="step_increment">0.01</property>
|
||||
<property name="page_increment">0.1</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="statusicon_padding_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
<property name="step_increment">0.01</property>
|
||||
<property name="page_increment">0.1</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="leftbox_padding_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
<property name="step_increment">0.01</property>
|
||||
<property name="page_increment">0.1</property>
|
||||
</object>
|
||||
|
||||
<object class="AdwPreferencesPage" id="finetune">
|
||||
<property name="icon-name">preferences-other-symbolic</property>
|
||||
<property name="title" translatable="yes">Fine-Tune</property>
|
||||
<property name="icon_name">preferences-other-symbolic</property>
|
||||
|
||||
<!-- group font -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="finetune_group_font">
|
||||
<property name="title" translatable="yes">Font size</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Tray Font Size</property>
|
||||
<property name="subtitle" translatable="yes">(0 = theme default)</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="tray_size_scale">
|
||||
<property name="width-request">300</property>
|
||||
<property name="adjustment">tray_size_adjustment</property>
|
||||
<property name="round_digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="value_pos">right</property>
|
||||
<property name="draw_value">True</property>
|
||||
<signal name="value-changed" handler="tray_size_scale_value_changed_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">LeftBox Font Size</property>
|
||||
<property name="subtitle" translatable="yes">(0 = theme default)</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="leftbox_size_scale">
|
||||
<property name="width-request">300</property>
|
||||
<property name="adjustment">leftbox_size_adjustment</property>
|
||||
<property name="round_digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="value_pos">right</property>
|
||||
<property name="draw_value">True</property>
|
||||
<signal name="value-changed" handler="leftbox_size_scale_value_changed_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group panel -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="finetune_group_padding">
|
||||
<property name="title" translatable="yes">Padding</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Tray Item Padding</property>
|
||||
<property name="subtitle" translatable="yes">(-1 = theme default)</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="tray_padding_scale">
|
||||
<property name="width-request">300</property>
|
||||
<property name="adjustment">tray_padding_adjustment</property>
|
||||
<property name="round_digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="value_pos">right</property>
|
||||
<property name="draw_value">True</property>
|
||||
<signal name="value-changed" handler="tray_padding_scale_value_changed_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Status Icon Padding</property>
|
||||
<property name="subtitle" translatable="yes">(-1 = theme default)</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="statusicon_padding_scale">
|
||||
<property name="width-request">300</property>
|
||||
<property name="adjustment">statusicon_padding_adjustment</property>
|
||||
<property name="round_digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="value_pos">right</property>
|
||||
<property name="draw_value">True</property>
|
||||
<signal name="value-changed" handler="statusicon_padding_scale_value_changed_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">LeftBox Padding</property>
|
||||
<property name="subtitle" translatable="yes">(-1 = theme default)</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="leftbox_padding_scale">
|
||||
<property name="width-request">300</property>
|
||||
<property name="adjustment">leftbox_padding_adjustment</property>
|
||||
<property name="round_digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="value_pos">right</property>
|
||||
<property name="draw_value">True</property>
|
||||
<signal name="value-changed" handler="leftbox_padding_scale_value_changed_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group animate -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="finetune_group_animate">
|
||||
<property name="title" translatable="yes">Animate</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Animate switching applications</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="animate_app_switch_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Animate launching new windows</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="animate_window_launch_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group gnome -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="finetune_group_gnome">
|
||||
<property name="title" translatable="yes">Gnome functionality</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Keep original gnome-shell dash</property>
|
||||
<property name="subtitle" translatable="yes">(overview)</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="stockgs_dash_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Keep original gnome-shell top panel</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="stockgs_top_panel_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Activate panel menu buttons on click only</property>
|
||||
<property name="subtitle" translatable="yes">(e.g. date menu)</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="stockgs_panelbtn_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Force Activities hot corner on primary monitor</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="stockgs_hotcorner_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group panel -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="finetune_group_">
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">App icon secondary menu</property>
|
||||
<property name="subtitle" translatable="yes">(right-click menu)</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="secondarymenu_options_button">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="secondarymenu_options_button_image">
|
||||
<property name="icon_name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group advanced-->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="finetune_group_advanced">
|
||||
|
||||
<child>
|
||||
<object class="GtkButton" id="button_advanced_options">
|
||||
<property name="label" translatable="yes">Advanced Options</property>
|
||||
<property name="visible">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="halign">end</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="finetune_group_font">
|
||||
<property name="title" translatable="yes">Font size</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(0 = theme default)</property>
|
||||
<property name="title" translatable="yes">Tray Font Size</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="tray_size_scale">
|
||||
<property name="adjustment">tray_size_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(0 = theme default)</property>
|
||||
<property name="title" translatable="yes">LeftBox Font Size</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="leftbox_size_scale">
|
||||
<property name="adjustment">leftbox_size_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="finetune_group_padding">
|
||||
<property name="title" translatable="yes">Padding</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(-1 = theme default)</property>
|
||||
<property name="title" translatable="yes">Tray Item Padding</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="tray_padding_scale">
|
||||
<property name="adjustment">tray_padding_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(-1 = theme default)</property>
|
||||
<property name="title" translatable="yes">Status Icon Padding</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="statusicon_padding_scale">
|
||||
<property name="adjustment">statusicon_padding_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(-1 = theme default)</property>
|
||||
<property name="title" translatable="yes">LeftBox Padding</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="leftbox_padding_scale">
|
||||
<property name="adjustment">leftbox_padding_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="finetune_group_animate">
|
||||
<property name="title" translatable="yes">Animate</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Animate switching applications</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="animate_app_switch_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Animate launching new windows</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="animate_window_launch_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="finetune_group_gnome">
|
||||
<property name="title" translatable="yes">Gnome functionality</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(overview)</property>
|
||||
<property name="title" translatable="yes">Keep original gnome-shell dash</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="stockgs_dash_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Keep original gnome-shell top panel</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="stockgs_top_panel_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(e.g. date menu)</property>
|
||||
<property name="title" translatable="yes">Activate panel menu buttons on click only</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="stockgs_panelbtn_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Force Activities hot corner on primary monitor</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="stockgs_hotcorner_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,243 +1,225 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<interface>
|
||||
<!-- interface-name SettingsPosition.ui -->
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
|
||||
<requires lib="libadwaita" version="1.6"/>
|
||||
<object class="GtkAdjustment" id="panel_size_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
<property name="step_increment">0.01</property>
|
||||
<property name="page_increment">0.1</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="panel_length_adjustment">
|
||||
<property name="upper">100</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">10</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
</object>
|
||||
|
||||
<object class="AdwPreferencesPage" id="position">
|
||||
<property name="icon-name">find-location-symbolic</property>
|
||||
<property name="title" translatable="yes">Position</property>
|
||||
<property name="icon_name">find-location-symbolic</property>
|
||||
|
||||
<!-- group panel -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="position_group_panel">
|
||||
<property name="title" translatable="yes">Panel</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Display the main panel on</property>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="multimon_primary_combo">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Display panels on all monitors</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="multimon_multi_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="position_group_panel2">
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Panel Intellihide</property>
|
||||
<property name="subtitle" translatable="yes">Hide and reveal the panel according to preferences</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="intellihide_options_button">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image_intellihide_options">
|
||||
<property name="icon_name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="intellihide_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group order and positions -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="position_group_on_monitor">
|
||||
<property name="title" translatable="yes">Order and Position on monitors</property>
|
||||
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesRow">
|
||||
<property name="title" translatable="yes">Monitor</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">6</property>
|
||||
<property name="margin-end">6</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="taskbar_position_sync_button">
|
||||
<property name="label" translatable="yes">Apply changes to all monitors</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="taskbar_position_monitor_combo">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group order and positions 2 -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="position_group_on_monitor2">
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Panel screen position</property>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="position_bottom_button">
|
||||
<property name="label" translatable="yes">Bottom</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="active">True</property>
|
||||
<signal name="clicked" handler="position_bottom_button_clicked_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="position_top_button">
|
||||
<property name="label" translatable="yes">Top</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="group">position_bottom_button</property>
|
||||
<signal name="clicked" handler="position_top_button_clicked_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="position_left_button">
|
||||
<property name="label" translatable="yes">Left</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="group">position_bottom_button</property>
|
||||
<signal name="clicked" handler="position_left_button_clicked_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="position_right_button">
|
||||
<property name="label" translatable="yes">Right</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="group">position_bottom_button</property>
|
||||
<signal name="clicked" handler="position_right_button_clicked_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Panel thickness</property>
|
||||
<property name="subtitle" translatable="yes">(default is 48)</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="panel_size_scale">
|
||||
<property name="width-request">300</property>
|
||||
<property name="adjustment">panel_size_adjustment</property>
|
||||
<property name="round_digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="value_pos">right</property>
|
||||
<property name="draw_value">True</property>
|
||||
<signal name="value-changed" handler="panel_size_scale_value_changed_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Panel length (%)</property>
|
||||
<property name="subtitle" translatable="yes">(default is 100)</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="panel_length_scale">
|
||||
<property name="width-request">300</property>
|
||||
<property name="adjustment">panel_length_adjustment</property>
|
||||
<property name="round_digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="value_pos">right</property>
|
||||
<property name="draw_value">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow" id="panel_anchor_label">
|
||||
<property name="title" translatable="yes">Anchor</property>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="panel_anchor_combo">
|
||||
<property name="valign">center</property>
|
||||
<items>
|
||||
<item id="START" translatable="yes">Start</item>
|
||||
<item id="MIDDLE" translatable="yes">Middle</item>
|
||||
<item id="END" translatable="yes">End</item>
|
||||
</items>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group order and positions 3 -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="position_group_on_monitor3">
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesRow">
|
||||
<property name="title" translatable="yes">Taskbar Display</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="taskbar_display_listbox">
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="selection_mode">none</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="position_group_panel">
|
||||
<property name="title" translatable="yes">Panel</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Display the main panel on</property>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="multimon_primary_combo">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Display panels on all monitors</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="multimon_multi_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="position_group_panel2">
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">Hide and reveal the panel according to preferences</property>
|
||||
<property name="title" translatable="yes">Panel Intellihide</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="intellihide_options_button">
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image_intellihide_options">
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="intellihide_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="position_group_on_monitor">
|
||||
<property name="title" translatable="yes">Order and Position on monitors</property>
|
||||
<child>
|
||||
<object class="AdwPreferencesRow">
|
||||
<property name="title" translatable="yes">Monitor</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-bottom">6</property>
|
||||
<property name="margin-end">6</property>
|
||||
<property name="margin-start">6</property>
|
||||
<property name="margin-top">6</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="taskbar_position_sync_button">
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">Apply changes to all monitors</property>
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="taskbar_position_monitor_combo">
|
||||
<property name="halign">end</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="position_group_on_monitor2">
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Panel monitor position</property>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="position_bottom_button">
|
||||
<property name="active">True</property>
|
||||
<property name="label" translatable="yes">Bottom</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<signal name="clicked" handler="position_bottom_button_clicked_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="position_top_button">
|
||||
<property name="group">position_bottom_button</property>
|
||||
<property name="label" translatable="yes">Top</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<signal name="clicked" handler="position_top_button_clicked_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="position_left_button">
|
||||
<property name="group">position_bottom_button</property>
|
||||
<property name="label" translatable="yes">Left</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<signal name="clicked" handler="position_left_button_clicked_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="position_right_button">
|
||||
<property name="group">position_bottom_button</property>
|
||||
<property name="label" translatable="yes">Right</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<signal name="clicked" handler="position_right_button_clicked_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(default is 48)</property>
|
||||
<property name="title" translatable="yes">Panel thickness</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="panel_size_scale">
|
||||
<property name="adjustment">panel_size_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(default is 100)</property>
|
||||
<property name="title" translatable="yes">Panel length</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="panel_length_dynamic_button">
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">Dynamic</property>
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScale" id="panel_length_scale">
|
||||
<property name="adjustment">panel_length_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow" id="panel_anchor_label">
|
||||
<property name="title" translatable="yes">Anchor</property>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="panel_anchor_combo">
|
||||
<property name="valign">center</property>
|
||||
<items>
|
||||
<item id="START" translatable="yes">Start</item>
|
||||
<item id="MIDDLE" translatable="yes">Middle</item>
|
||||
<item id="END" translatable="yes">End</item>
|
||||
</items>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="position_group_on_monitor3">
|
||||
<child>
|
||||
<object class="AdwPreferencesRow">
|
||||
<property name="title" translatable="yes">Taskbar Display</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="taskbar_display_listbox">
|
||||
<property name="margin-bottom">6</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="selection-mode">none</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -1,37 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<interface>
|
||||
<!-- interface-name SettingsStyle.ui -->
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
|
||||
<requires lib="libadwaita" version="1.6"/>
|
||||
<object class="GtkAdjustment" id="appicon_margin_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
<property name="step_increment">0.01</property>
|
||||
<property name="page_increment">0.1</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="appicon_padding_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="panel_side_margins_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="panel_top_bottom_margins_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="panel_side_padding_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="panel_top_bottom_padding_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
<property name="step_increment">0.01</property>
|
||||
<property name="page_increment">0.1</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="trans_opacity_adjustment">
|
||||
<property name="page-increment">10</property>
|
||||
<property name="step-increment">5</property>
|
||||
<property name="upper">100</property>
|
||||
<property name="step_increment">5</property>
|
||||
<property name="page_increment">10</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="trans_gradient_opacity1_adjustment">
|
||||
<property name="page-increment">10</property>
|
||||
<property name="step-increment">5</property>
|
||||
<property name="upper">100</property>
|
||||
<property name="step_increment">5</property>
|
||||
<property name="page_increment">10</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="trans_gradient_opacity2_adjustment">
|
||||
<property name="page-increment">10</property>
|
||||
<property name="step-increment">5</property>
|
||||
<property name="upper">100</property>
|
||||
<property name="step_increment">5</property>
|
||||
<property name="page_increment">10</property>
|
||||
</object>
|
||||
|
||||
<object class="GtkAdjustment" id="trans_border_opacity_adjustment">
|
||||
@@ -48,60 +69,73 @@
|
||||
</object>
|
||||
|
||||
<object class="AdwPreferencesPage" id="style">
|
||||
<property name="icon-name">applications-graphics-symbolic</property>
|
||||
<property name="title" translatable="yes">Style</property>
|
||||
<property name="icon_name">applications-graphics-symbolic</property>
|
||||
|
||||
<!-- group app icon style -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="style_group_global">
|
||||
<property name="title" translatable="yes">Global style</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Border radius</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="global_border_radius_scale">
|
||||
<property name="adjustment">global_border_radius_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="style_group_app_icon_style">
|
||||
<property name="title" translatable="yes">AppIcon style</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">App Icon Margin</property>
|
||||
<property name="subtitle" translatable="yes">(default is 8)</property>
|
||||
<property name="title" translatable="yes">App Icon Margin</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="appicon_margin_scale">
|
||||
<property name="width-request">300</property>
|
||||
<property name="adjustment">appicon_margin_adjustment</property>
|
||||
<property name="round_digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="value_pos">right</property>
|
||||
<property name="draw_value">True</property>
|
||||
<signal name="value-changed" handler="appicon_margin_scale_value_changed_cb"/>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">App Icon Padding</property>
|
||||
<property name="subtitle" translatable="yes">(default is 4)</property>
|
||||
<property name="title" translatable="yes">App Icon Padding</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="appicon_padding_scale">
|
||||
<property name="width-request">300</property>
|
||||
<property name="adjustment">appicon_padding_adjustment</property>
|
||||
<property name="round_digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="value_pos">right</property>
|
||||
<property name="draw_value">True</property>
|
||||
<signal name="value-changed" handler="appicon_padding_scale_value_changed_cb"/>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Animate hovering app icons</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="animate_appicon_hover_button">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="animate_appicon_hover_options_image">
|
||||
<property name="icon_name">emblem-system-symbolic</property>
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
@@ -116,7 +150,30 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Highlight hovering app icons</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="highlight_appicon_hover_button">
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="highlight_appicon_hover_options_image">
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="highlight_appicon_hover_switch">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Icon style</property>
|
||||
@@ -134,12 +191,9 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group running indicator -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="style_group_running_indicator">
|
||||
<property name="title" translatable="yes">Running indicator</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Running indicator position</property>
|
||||
@@ -152,31 +206,30 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="dots_top_button">
|
||||
<property name="group">dots_bottom_button</property>
|
||||
<property name="label" translatable="yes">Top</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="group">dots_bottom_button</property>
|
||||
<signal name="toggled" handler="dots_top_button_toggled_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="dots_left_button">
|
||||
<property name="group">dots_bottom_button</property>
|
||||
<property name="label" translatable="yes">Left</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="group">dots_bottom_button</property>
|
||||
<signal name="toggled" handler="dots_left_button_toggled_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="dots_right_button">
|
||||
<property name="group">dots_bottom_button</property>
|
||||
<property name="label" translatable="yes">Right</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="group">dots_bottom_button</property>
|
||||
<signal name="toggled" handler="dots_right_button_toggled_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Running indicator style (Focused app)</property>
|
||||
@@ -185,7 +238,7 @@
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="dot_style_image">
|
||||
<property name="icon_name">emblem-system-symbolic</property>
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
@@ -209,7 +262,6 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Running indicator style (Unfocused apps)</property>
|
||||
@@ -229,15 +281,79 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group dynamic trans -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="style_group_dynamic_trans">
|
||||
<property name="title" translatable="yes">Panel style</property>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(default is 0)</property>
|
||||
<property name="title" translatable="yes">Side margins</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="panel_side_margins_scale">
|
||||
<property name="adjustment">panel_side_margins_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(default is 0)</property>
|
||||
<property name="title" translatable="yes">Top and bottom margins</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="panel_top_bottom_margins_scale">
|
||||
<property name="adjustment">panel_top_bottom_margins_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(default is 0)</property>
|
||||
<property name="title" translatable="yes">Side padding</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="panel_side_padding_scale">
|
||||
<property name="adjustment">panel_side_padding_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="subtitle" translatable="yes">(default is 0)</property>
|
||||
<property name="title" translatable="yes">Top and bottom padding</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="panel_top_bottom_padding_scale">
|
||||
<property name="adjustment">panel_top_bottom_padding_adjustment</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">True</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="value-pos">right</property>
|
||||
<property name="width-request">300</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="style_group_dynamic_trans2">
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Override panel theme background color</property>
|
||||
@@ -253,13 +369,6 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group dynamic trans2 -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="style_group_dynamic_trans2">
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Override panel theme background opacity</property>
|
||||
@@ -270,31 +379,29 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow" id="trans_opacity_box">
|
||||
<property name="title" translatable="yes">Panel background opacity (%)</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="trans_opacity_spinbutton">
|
||||
<property name="valign">center</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="adjustment">trans_opacity_adjustment</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow" id="trans_opacity_box2">
|
||||
<property name="title" translatable="yes">Dynamic background opacity</property>
|
||||
<property name="subtitle" translatable="yes">Change opacity when a window gets close to the panel</property>
|
||||
<property name="title" translatable="yes">Dynamic background opacity</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="trans_dyn_options_button">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image_trans_dyn_options">
|
||||
<property name="icon_name">emblem-system-symbolic</property>
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
@@ -309,14 +416,10 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- group dynamic trans3 -->
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="style_group_dynamic_trans3">
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Override panel theme gradient</property>
|
||||
@@ -327,45 +430,42 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow" id="trans_gradient_box">
|
||||
<property name="title" translatable="yes">Gradient top color and opacity (%)</property>
|
||||
<child>
|
||||
<object class="GtkColorButton" id="trans_gradient_color1_colorbutton">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="trans_gradient_color1_spinbutton">
|
||||
<property name="valign">center</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="adjustment">trans_gradient_opacity1_adjustment</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwActionRow" id="trans_gradient_box2">
|
||||
<property name="title" translatable="yes">Gradient bottom color and opacity (%)</property>
|
||||
<child>
|
||||
<object class="GtkColorButton" id="trans_gradient_color2_colorbutton">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="trans_gradient_color2_spinbutton">
|
||||
<property name="valign">center</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="adjustment">trans_gradient_opacity2_adjustment</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
@@ -415,4 +515,10 @@
|
||||
</child>
|
||||
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="global_border_radius_adjustment">
|
||||
<property name="lower">0.33</property>
|
||||
<property name="page-increment">0.1</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="upper">1</property>
|
||||
</object>
|
||||
</interface>
|
||||
889
utils.js
889
utils.js
@@ -1,889 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Dash-To-Panel extension for Gnome 3
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Credits:
|
||||
* This file is based on code from the Dash to Dock extension by micheleg
|
||||
* and code from the Taskbar extension by Zorin OS
|
||||
* Some code was also adapted from the upstream Gnome Shell source code.
|
||||
*/
|
||||
|
||||
import Clutter from 'gi://Clutter';
|
||||
import Cogl from 'gi://Cogl';
|
||||
import GdkPixbuf from 'gi://GdkPixbuf';
|
||||
import Gio from 'gi://Gio';
|
||||
import GLib from 'gi://GLib';
|
||||
import Graphene from 'gi://Graphene';
|
||||
import Meta from 'gi://Meta';
|
||||
import Shell from 'gi://Shell';
|
||||
import St from 'gi://St';
|
||||
import * as Util from 'resource:///org/gnome/shell/misc/util.js';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import * as MessageTray from 'resource:///org/gnome/shell/ui/messageTray.js';
|
||||
|
||||
const SCROLL_TIME = Util.SCROLL_TIME / (Util.SCROLL_TIME > 1 ? 1000 : 1);
|
||||
|
||||
// simplify global signals and function injections handling
|
||||
// abstract class
|
||||
export const BasicHandler = class {
|
||||
|
||||
constructor() {
|
||||
this._storage = new Object();
|
||||
}
|
||||
|
||||
add(/*unlimited 3-long array arguments*/){
|
||||
|
||||
// convert arguments object to array, concatenate with generic
|
||||
let args = [].concat('generic', [].slice.call(arguments));
|
||||
// call addWithLabel with ags as if they were passed arguments
|
||||
this.addWithLabel.apply(this, args);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
for( let label in this._storage )
|
||||
this.removeWithLabel(label);
|
||||
}
|
||||
|
||||
addWithLabel( label /* plus unlimited 3-long array arguments*/) {
|
||||
|
||||
if(this._storage[label] == undefined)
|
||||
this._storage[label] = new Array();
|
||||
|
||||
// skip first element of the arguments
|
||||
for( let i = 1; i < arguments.length; i++ ) {
|
||||
let item = this._storage[label];
|
||||
let handlers = this._create(arguments[i]);
|
||||
|
||||
for (let j = 0, l = handlers.length; j < l; ++j) {
|
||||
item.push(handlers[j]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
removeWithLabel(label){
|
||||
|
||||
if(this._storage[label]) {
|
||||
for( let i = 0; i < this._storage[label].length; i++ ) {
|
||||
this._remove(this._storage[label][i]);
|
||||
}
|
||||
|
||||
delete this._storage[label];
|
||||
}
|
||||
}
|
||||
|
||||
/* Virtual methods to be implemented by subclass */
|
||||
// create single element to be stored in the storage structure
|
||||
_create(item){
|
||||
throw new Error('no implementation of _create in ' + this);
|
||||
}
|
||||
|
||||
// correctly delete single element
|
||||
_remove(item){
|
||||
throw new Error('no implementation of _remove in ' + this);
|
||||
}
|
||||
}
|
||||
|
||||
// Manage global signals
|
||||
export const GlobalSignalsHandler = class extends BasicHandler {
|
||||
|
||||
_create(item) {
|
||||
let handlers = [];
|
||||
|
||||
item[1] = [].concat(item[1]);
|
||||
|
||||
for (let i = 0, l = item[1].length; i < l; ++i) {
|
||||
let object = item[0];
|
||||
let event = item[1][i];
|
||||
let callback = item[2]
|
||||
try {
|
||||
let id = object.connect(event, callback);
|
||||
|
||||
handlers.push([object, id]);
|
||||
} catch (e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
_remove(item){
|
||||
item[0].disconnect(item[1]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Manage function injection: both instances and prototype can be overridden
|
||||
* and restored
|
||||
*/
|
||||
export const InjectionsHandler = class extends BasicHandler {
|
||||
|
||||
_create(item) {
|
||||
let object = item[0];
|
||||
let name = item[1];
|
||||
let injectedFunction = item[2];
|
||||
let original = object[name];
|
||||
|
||||
object[name] = injectedFunction;
|
||||
return [[object, name, injectedFunction, original]];
|
||||
}
|
||||
|
||||
_remove(item) {
|
||||
let object = item[0];
|
||||
let name = item[1];
|
||||
let original = item[3];
|
||||
object[name] = original;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Manage timeouts: the added timeouts have their id reset on completion
|
||||
*/
|
||||
export const TimeoutsHandler = class extends BasicHandler {
|
||||
|
||||
_create(item) {
|
||||
let name = item[0];
|
||||
let delay = item[1];
|
||||
let timeoutHandler = item[2];
|
||||
|
||||
this._remove(item);
|
||||
|
||||
this[name] = GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, () => {
|
||||
this[name] = 0;
|
||||
timeoutHandler();
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
|
||||
return [[name]];
|
||||
}
|
||||
|
||||
remove(name) {
|
||||
this._remove([name])
|
||||
}
|
||||
|
||||
_remove(item) {
|
||||
let name = item[0];
|
||||
|
||||
if (this[name]) {
|
||||
GLib.Source.remove(this[name]);
|
||||
this[name] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
getId(name) {
|
||||
return this[name] ? this[name] : 0;
|
||||
}
|
||||
};
|
||||
|
||||
// This is wrapper to maintain compatibility with GNOME-Shell 3.30+ as well as
|
||||
// previous versions.
|
||||
export const DisplayWrapper = {
|
||||
getScreen() {
|
||||
return global.screen || global.display;
|
||||
},
|
||||
|
||||
getWorkspaceManager() {
|
||||
return global.screen || global.workspace_manager;
|
||||
},
|
||||
|
||||
getMonitorManager() {
|
||||
return global.screen || global.backend.get_monitor_manager();
|
||||
}
|
||||
};
|
||||
|
||||
let unredirectEnabled = true
|
||||
export const setDisplayUnredirect = (enable) => {
|
||||
if (enable && !unredirectEnabled)
|
||||
Meta.enable_unredirect_for_display(global.display);
|
||||
else if (!enable && unredirectEnabled)
|
||||
Meta.disable_unredirect_for_display(global.display);
|
||||
|
||||
unredirectEnabled = enable;
|
||||
};
|
||||
|
||||
export const getSystemMenuInfo = function() {
|
||||
return {
|
||||
name: 'quickSettings',
|
||||
constructor: Main.panel.statusArea.quickSettings.constructor
|
||||
};
|
||||
}
|
||||
|
||||
export const getCurrentWorkspace = function() {
|
||||
return DisplayWrapper.getWorkspaceManager().get_active_workspace();
|
||||
};
|
||||
|
||||
export const getWorkspaceByIndex = function(index) {
|
||||
return DisplayWrapper.getWorkspaceManager().get_workspace_by_index(index);
|
||||
};
|
||||
|
||||
export const getWorkspaceCount = function() {
|
||||
return DisplayWrapper.getWorkspaceManager().n_workspaces;
|
||||
};
|
||||
|
||||
export const getStageTheme = function() {
|
||||
return St.ThemeContext.get_for_stage(global.stage);
|
||||
};
|
||||
|
||||
export const getScaleFactor = function() {
|
||||
return getStageTheme().scale_factor || 1;
|
||||
};
|
||||
|
||||
export const findIndex = function(array, predicate) {
|
||||
if (array) {
|
||||
if (Array.prototype.findIndex) {
|
||||
return array.findIndex(predicate);
|
||||
}
|
||||
|
||||
for (let i = 0, l = array.length; i < l; ++i) {
|
||||
if (predicate(array[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
|
||||
export const find = function(array, predicate) {
|
||||
let index = findIndex(array, predicate);
|
||||
|
||||
if (index > -1) {
|
||||
return array[index];
|
||||
}
|
||||
};
|
||||
|
||||
export const mergeObjects = function(main, bck) {
|
||||
for (const prop in bck) {
|
||||
if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) {
|
||||
main[prop] = bck[prop];
|
||||
}
|
||||
}
|
||||
|
||||
return main;
|
||||
};
|
||||
|
||||
export const getTrackedActorData = (actor) => {
|
||||
let trackedIndex = Main.layoutManager._findActor(actor);
|
||||
|
||||
if (trackedIndex >= 0)
|
||||
return Main.layoutManager._trackedActors[trackedIndex]
|
||||
}
|
||||
|
||||
export const getTransformedAllocation = function(actor) {
|
||||
let extents = actor.get_transformed_extents();
|
||||
let topLeft = extents.get_top_left();
|
||||
let bottomRight = extents.get_bottom_right();
|
||||
|
||||
return { x1: topLeft.x, x2: bottomRight.x, y1: topLeft.y, y2: bottomRight.y };
|
||||
};
|
||||
|
||||
export const setClip = function(actor, x, y, width, height) {
|
||||
actor.set_clip(0, 0, width, height);
|
||||
actor.set_position(x, y);
|
||||
actor.set_size(width, height);
|
||||
};
|
||||
|
||||
export const addKeybinding = function(key, settings, handler, modes) {
|
||||
if (!Main.wm._allowedKeybindings[key]) {
|
||||
Main.wm.addKeybinding(
|
||||
key,
|
||||
settings,
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
modes || (Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW),
|
||||
handler
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const removeKeybinding = function(key) {
|
||||
if (Main.wm._allowedKeybindings[key]) {
|
||||
Main.wm.removeKeybinding(key);
|
||||
}
|
||||
};
|
||||
|
||||
export const getrgbColor = function(color) {
|
||||
color = typeof color === 'string' ? ColorUtils.color_from_string(color)[1] : color;
|
||||
|
||||
return { red: color.red, green: color.green, blue: color.blue };
|
||||
};
|
||||
|
||||
export const getrgbaColor = function(color, alpha, offset) {
|
||||
if (alpha <= 0) {
|
||||
return 'transparent; ';
|
||||
}
|
||||
|
||||
let rgb = getrgbColor(color);
|
||||
|
||||
if (offset) {
|
||||
['red', 'green', 'blue'].forEach(k => {
|
||||
rgb[k] = Math.min(255, Math.max(0, rgb[k] + offset));
|
||||
|
||||
if (rgb[k] == color[k]) {
|
||||
rgb[k] = Math.min(255, Math.max(0, rgb[k] - offset));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ',' + (Math.floor(alpha * 100) * 0.01) + '); ' ;
|
||||
};
|
||||
|
||||
export const checkIfColorIsBright = function(color) {
|
||||
let rgb = getrgbColor(color);
|
||||
let brightness = 0.2126 * rgb.red + 0.7152 * rgb.green + 0.0722 * rgb.blue;
|
||||
|
||||
return brightness > 128;
|
||||
};
|
||||
|
||||
export const getMouseScrollDirection = function(event) {
|
||||
let direction;
|
||||
|
||||
switch (event.get_scroll_direction()) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
case Clutter.ScrollDirection.LEFT:
|
||||
direction = 'up';
|
||||
break;
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
case Clutter.ScrollDirection.RIGHT:
|
||||
direction = 'down';
|
||||
break;
|
||||
}
|
||||
|
||||
return direction;
|
||||
};
|
||||
|
||||
export const checkIfWindowHasTransient = function(window) {
|
||||
let hasTransient;
|
||||
|
||||
window.foreach_transient(t => !(hasTransient = true));
|
||||
|
||||
return hasTransient;
|
||||
};
|
||||
|
||||
export const activateSiblingWindow = function(windows, direction, startWindow) {
|
||||
let windowIndex = windows.indexOf(global.display.focus_window);
|
||||
let nextWindowIndex = windowIndex < 0 ?
|
||||
startWindow ? windows.indexOf(startWindow) : 0 :
|
||||
windowIndex + (direction == 'up' ? -1 : 1);
|
||||
|
||||
if (nextWindowIndex == windows.length) {
|
||||
nextWindowIndex = 0;
|
||||
} else if (nextWindowIndex < 0) {
|
||||
nextWindowIndex = windows.length - 1;
|
||||
}
|
||||
|
||||
if (windowIndex != nextWindowIndex) {
|
||||
Main.activateWindow(windows[nextWindowIndex]);
|
||||
}
|
||||
};
|
||||
|
||||
export const animateWindowOpacity = function(window, tweenOpts) {
|
||||
//there currently is a mutter bug with the windowactor opacity, starting with 3.34
|
||||
//https://gitlab.gnome.org/GNOME/mutter/issues/836
|
||||
|
||||
//since 3.36, a workaround is to use the windowactor's child for the fade animation
|
||||
//this leaves a "shadow" on the desktop, so the windowactor needs to be hidden
|
||||
//when the animation is complete
|
||||
let visible = tweenOpts.opacity > 0;
|
||||
let windowActor = window;
|
||||
let initialOpacity = window.opacity;
|
||||
|
||||
window = windowActor.get_first_child() || windowActor;
|
||||
|
||||
if (!windowActor.visible && visible) {
|
||||
window.opacity = 0;
|
||||
windowActor.visible = visible;
|
||||
tweenOpts.opacity = Math.min(initialOpacity, tweenOpts.opacity);
|
||||
}
|
||||
|
||||
if (!visible) {
|
||||
tweenOpts.onComplete = () => {
|
||||
windowActor.visible = visible;
|
||||
window.opacity = initialOpacity;
|
||||
};
|
||||
}
|
||||
|
||||
animate(window, tweenOpts);
|
||||
};
|
||||
|
||||
export const animate = function(actor, options) {
|
||||
//the original animations used Tweener instead of Clutter animations, so we
|
||||
//use "time" and "delay" properties defined in seconds, as opposed to Clutter
|
||||
//animations "duration" and "delay" which are defined in milliseconds
|
||||
if (options.delay) {
|
||||
options.delay = options.delay * 1000;
|
||||
}
|
||||
|
||||
options.duration = options.time * 1000;
|
||||
delete options.time;
|
||||
|
||||
if (options.transition) {
|
||||
//map Tweener easing equations to Clutter animation modes
|
||||
options.mode = {
|
||||
'easeInCubic': Clutter.AnimationMode.EASE_IN_CUBIC,
|
||||
'easeInOutCubic': Clutter.AnimationMode.EASE_IN_OUT_CUBIC,
|
||||
'easeInOutQuad': Clutter.AnimationMode.EASE_IN_OUT_QUAD,
|
||||
'easeOutQuad': Clutter.AnimationMode.EASE_OUT_QUAD
|
||||
}[options.transition] || Clutter.AnimationMode.LINEAR;
|
||||
|
||||
delete options.transition;
|
||||
}
|
||||
|
||||
let params = [options];
|
||||
|
||||
if ('value' in options && actor instanceof St.Adjustment) {
|
||||
params.unshift(options.value);
|
||||
delete options.value;
|
||||
}
|
||||
|
||||
actor.ease.apply(actor, params);
|
||||
}
|
||||
|
||||
export const isAnimating = function(actor, prop) {
|
||||
return !!actor.get_transition(prop);
|
||||
}
|
||||
|
||||
export const stopAnimations = function(actor) {
|
||||
actor.remove_all_transitions();
|
||||
}
|
||||
|
||||
export const getIndicators = function(delegate) {
|
||||
if (delegate instanceof St.BoxLayout) {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
return delegate.indicators;
|
||||
}
|
||||
|
||||
export const getPoint = function(coords) {
|
||||
return new Graphene.Point(coords);
|
||||
}
|
||||
|
||||
export const notify = function(text, iconName, action, isTransient) {
|
||||
let source = new MessageTray.SystemNotificationSource();
|
||||
let notification = new MessageTray.Notification(source, 'Dash to Panel', text);
|
||||
let notifyFunc = source.showNotification || source.notify;
|
||||
|
||||
if (iconName) {
|
||||
source.createIcon = function() {
|
||||
return new St.Icon({ icon_name: iconName });
|
||||
};
|
||||
}
|
||||
|
||||
if (action) {
|
||||
if (!(action instanceof Array)) {
|
||||
action = [action];
|
||||
}
|
||||
|
||||
action.forEach(a => notification.addAction(a.text, a.func));
|
||||
}
|
||||
|
||||
Main.messageTray.add(source);
|
||||
|
||||
notification.setTransient(isTransient);
|
||||
notifyFunc.call(source, notification);
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a copy of the same function in utils.js, but also adjust horizontal scrolling
|
||||
* and perform few further cheks on the current value to avoid changing the values when
|
||||
* it would be clamp to the current one in any case.
|
||||
* Return the amount of shift applied
|
||||
*/
|
||||
export const ensureActorVisibleInScrollView = function(scrollView, actor, fadeSize, onComplete) {
|
||||
const vadjustment = scrollView.vadjustment;
|
||||
const hadjustment = scrollView.hadjustment;
|
||||
let [vvalue, vlower, vupper, vstepIncrement, vpageIncrement, vpageSize] = vadjustment.get_values();
|
||||
let [hvalue, hlower, hupper, hstepIncrement, hpageIncrement, hpageSize] = hadjustment.get_values();
|
||||
|
||||
let [hvalue0, vvalue0] = [hvalue, vvalue];
|
||||
|
||||
let voffset = fadeSize;
|
||||
let hoffset = fadeSize;
|
||||
|
||||
let box = actor.get_allocation_box();
|
||||
let y1 = box.y1, y2 = box.y2, x1 = box.x1, x2 = box.x2;
|
||||
|
||||
let parent = actor.get_parent();
|
||||
while (parent != scrollView) {
|
||||
if (!parent)
|
||||
throw new Error("actor not in scroll view");
|
||||
|
||||
let box = parent.get_allocation_box();
|
||||
y1 += box.y1;
|
||||
y2 += box.y1;
|
||||
x1 += box.x1;
|
||||
x2 += box.x1;
|
||||
parent = parent.get_parent();
|
||||
}
|
||||
|
||||
if (y1 < vvalue + voffset)
|
||||
vvalue = Math.max(0, y1 - voffset);
|
||||
else if (vvalue < vupper - vpageSize && y2 > vvalue + vpageSize - voffset)
|
||||
vvalue = Math.min(vupper -vpageSize, y2 + voffset - vpageSize);
|
||||
|
||||
if (x1 < hvalue + hoffset)
|
||||
hvalue = Math.max(0, x1 - hoffset);
|
||||
else if (hvalue < hupper - hpageSize && x2 > hvalue + hpageSize - hoffset)
|
||||
hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize);
|
||||
|
||||
let tweenOpts = {
|
||||
time: SCROLL_TIME,
|
||||
onComplete: onComplete || (() => {}),
|
||||
transition: 'easeOutQuad'
|
||||
};
|
||||
|
||||
if (vvalue !== vvalue0) {
|
||||
animate(vadjustment, mergeObjects(tweenOpts, { value: vvalue }));
|
||||
}
|
||||
|
||||
if (hvalue !== hvalue0) {
|
||||
animate(hadjustment, mergeObjects(tweenOpts, { value: hvalue }));
|
||||
}
|
||||
|
||||
return [hvalue- hvalue0, vvalue - vvalue0];
|
||||
}
|
||||
|
||||
/**
|
||||
* ColorUtils is adapted from https://github.com/micheleg/dash-to-dock
|
||||
*/
|
||||
let colorNs = Clutter.Color ? Clutter : Cogl
|
||||
|
||||
export const ColorUtils = {
|
||||
color_from_string: colorNs.color_from_string,
|
||||
Color: colorNs.Color,
|
||||
|
||||
colorLuminance(r, g, b, dlum) {
|
||||
// Darken or brighten color by a fraction dlum
|
||||
// Each rgb value is modified by the same fraction.
|
||||
// Return "#rrggbb" strin
|
||||
|
||||
let rgbString = '#';
|
||||
|
||||
rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(r*(1+dlum), 0), 255)), 2);
|
||||
rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(g*(1+dlum), 0), 255)), 2);
|
||||
rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(b*(1+dlum), 0), 255)), 2);
|
||||
|
||||
return rgbString;
|
||||
},
|
||||
|
||||
_decimalToHex(d, padding) {
|
||||
// Convert decimal to an hexadecimal string adding the desired padding
|
||||
|
||||
let hex = d.toString(16);
|
||||
while (hex.length < padding)
|
||||
hex = '0'+ hex;
|
||||
return hex;
|
||||
},
|
||||
|
||||
HSVtoRGB(h, s, v) {
|
||||
// Convert hsv ([0-1, 0-1, 0-1]) to rgb ([0-255, 0-255, 0-255]).
|
||||
// Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV
|
||||
// here with h = [0,1] instead of [0, 360]
|
||||
// Accept either (h,s,v) independently or {h:h, s:s, v:v} object.
|
||||
// Return {r:r, g:g, b:b} object.
|
||||
|
||||
if (arguments.length === 1) {
|
||||
s = h.s;
|
||||
v = h.v;
|
||||
h = h.h;
|
||||
}
|
||||
|
||||
let r,g,b;
|
||||
let c = v*s;
|
||||
let h1 = h*6;
|
||||
let x = c*(1 - Math.abs(h1 % 2 - 1));
|
||||
let m = v - c;
|
||||
|
||||
if (h1 <=1)
|
||||
r = c + m, g = x + m, b = m;
|
||||
else if (h1 <=2)
|
||||
r = x + m, g = c + m, b = m;
|
||||
else if (h1 <=3)
|
||||
r = m, g = c + m, b = x + m;
|
||||
else if (h1 <=4)
|
||||
r = m, g = x + m, b = c + m;
|
||||
else if (h1 <=5)
|
||||
r = x + m, g = m, b = c + m;
|
||||
else
|
||||
r = c + m, g = m, b = x + m;
|
||||
|
||||
return {
|
||||
r: Math.round(r * 255),
|
||||
g: Math.round(g * 255),
|
||||
b: Math.round(b * 255)
|
||||
};
|
||||
},
|
||||
|
||||
RGBtoHSV(r, g, b) {
|
||||
// Convert rgb ([0-255, 0-255, 0-255]) to hsv ([0-1, 0-1, 0-1]).
|
||||
// Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV
|
||||
// here with h = [0,1] instead of [0, 360]
|
||||
// Accept either (r,g,b) independently or {r:r, g:g, b:b} object.
|
||||
// Return {h:h, s:s, v:v} object.
|
||||
|
||||
if (arguments.length === 1) {
|
||||
r = r.r;
|
||||
g = r.g;
|
||||
b = r.b;
|
||||
}
|
||||
|
||||
let h,s,v;
|
||||
|
||||
let M = Math.max(r, g, b);
|
||||
let m = Math.min(r, g, b);
|
||||
let c = M - m;
|
||||
|
||||
if (c == 0)
|
||||
h = 0;
|
||||
else if (M == r)
|
||||
h = ((g-b)/c) % 6;
|
||||
else if (M == g)
|
||||
h = (b-r)/c + 2;
|
||||
else
|
||||
h = (r-g)/c + 4;
|
||||
|
||||
h = h/6;
|
||||
v = M/255;
|
||||
if (M !== 0)
|
||||
s = c/M;
|
||||
else
|
||||
s = 0;
|
||||
|
||||
return {h: h, s: s, v: v};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* DominantColorExtractor is adapted from https://github.com/micheleg/dash-to-dock
|
||||
*/
|
||||
let themeLoader = null;
|
||||
let iconCacheMap = new Map();
|
||||
const MAX_CACHED_ITEMS = 1000;
|
||||
const BATCH_SIZE_TO_DELETE = 50;
|
||||
const DOMINANT_COLOR_ICON_SIZE = 64;
|
||||
|
||||
export const DominantColorExtractor = class {
|
||||
|
||||
constructor(app){
|
||||
this._app = app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get the pixel buffer for the current icon, if not fail gracefully
|
||||
*/
|
||||
_getIconPixBuf() {
|
||||
let iconTexture = this._app.create_icon_texture(16);
|
||||
|
||||
if (themeLoader === null) {
|
||||
themeLoader = new St.IconTheme();
|
||||
}
|
||||
|
||||
// Unable to load the icon texture, use fallback
|
||||
if (iconTexture instanceof St.Icon === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
iconTexture = iconTexture.get_gicon();
|
||||
|
||||
// Unable to load the icon texture, use fallback
|
||||
if (iconTexture === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (iconTexture instanceof Gio.FileIcon) {
|
||||
// Use GdkPixBuf to load the pixel buffer from the provided file path
|
||||
return GdkPixbuf.Pixbuf.new_from_file(iconTexture.get_file().get_path());
|
||||
}
|
||||
|
||||
// Get the pixel buffer from the icon theme
|
||||
if (iconTexture instanceof Gio.ThemedIcon) {
|
||||
let icon_info = themeLoader.lookup_icon(iconTexture.get_names()[0],
|
||||
DOMINANT_COLOR_ICON_SIZE, 0);
|
||||
|
||||
if (icon_info !== null) {
|
||||
return icon_info.load_icon();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The backlight color choosing algorithm was mostly ported to javascript from the
|
||||
* Unity7 C++ source of Canonicals:
|
||||
* https://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/launcher/LauncherIcon.cpp
|
||||
* so it more or less works the same way.
|
||||
*/
|
||||
_getColorPalette() {
|
||||
if (iconCacheMap.get(this._app.get_id())) {
|
||||
// We already know the answer
|
||||
return iconCacheMap.get(this._app.get_id());
|
||||
}
|
||||
|
||||
let pixBuf = this._getIconPixBuf();
|
||||
if (pixBuf == null)
|
||||
return null;
|
||||
|
||||
let pixels = pixBuf.get_pixels(),
|
||||
offset = 0;
|
||||
|
||||
let total = 0,
|
||||
rTotal = 0,
|
||||
gTotal = 0,
|
||||
bTotal = 0;
|
||||
|
||||
let resample_y = 1,
|
||||
resample_x = 1;
|
||||
|
||||
// Resampling of large icons
|
||||
// We resample icons larger than twice the desired size, as the resampling
|
||||
// to a size s
|
||||
// DOMINANT_COLOR_ICON_SIZE < s < 2*DOMINANT_COLOR_ICON_SIZE,
|
||||
// most of the case exactly DOMINANT_COLOR_ICON_SIZE as the icon size is tipycally
|
||||
// a multiple of it.
|
||||
let width = pixBuf.get_width();
|
||||
let height = pixBuf.get_height();
|
||||
|
||||
// Resample
|
||||
if (height >= 2* DOMINANT_COLOR_ICON_SIZE)
|
||||
resample_y = Math.floor(height/DOMINANT_COLOR_ICON_SIZE);
|
||||
|
||||
if (width >= 2* DOMINANT_COLOR_ICON_SIZE)
|
||||
resample_x = Math.floor(width/DOMINANT_COLOR_ICON_SIZE);
|
||||
|
||||
if (resample_x !==1 || resample_y !== 1)
|
||||
pixels = this._resamplePixels(pixels, resample_x, resample_y);
|
||||
|
||||
// computing the limit outside the for (where it would be repeated at each iteration)
|
||||
// for performance reasons
|
||||
let limit = pixels.length;
|
||||
for (let offset = 0; offset < limit; offset+=4) {
|
||||
let r = pixels[offset],
|
||||
g = pixels[offset + 1],
|
||||
b = pixels[offset + 2],
|
||||
a = pixels[offset + 3];
|
||||
|
||||
let saturation = (Math.max(r,g, b) - Math.min(r,g, b));
|
||||
let relevance = 0.1 * 255 * 255 + 0.9 * a * saturation;
|
||||
|
||||
rTotal += r * relevance;
|
||||
gTotal += g * relevance;
|
||||
bTotal += b * relevance;
|
||||
|
||||
total += relevance;
|
||||
}
|
||||
|
||||
total = total * 255;
|
||||
|
||||
let r = rTotal / total,
|
||||
g = gTotal / total,
|
||||
b = bTotal / total;
|
||||
|
||||
let hsv = ColorUtils.RGBtoHSV(r * 255, g * 255, b * 255);
|
||||
|
||||
if (hsv.s > 0.15)
|
||||
hsv.s = 0.65;
|
||||
hsv.v = 0.90;
|
||||
|
||||
let rgb = ColorUtils.HSVtoRGB(hsv.h, hsv.s, hsv.v);
|
||||
|
||||
// Cache the result.
|
||||
let backgroundColor = {
|
||||
lighter: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0.2),
|
||||
original: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0),
|
||||
darker: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, -0.5)
|
||||
};
|
||||
|
||||
if (iconCacheMap.size >= MAX_CACHED_ITEMS) {
|
||||
//delete oldest cached values (which are in order of insertions)
|
||||
let ctr=0;
|
||||
for (let key of iconCacheMap.keys()) {
|
||||
if (++ctr > BATCH_SIZE_TO_DELETE)
|
||||
break;
|
||||
iconCacheMap.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
iconCacheMap.set(this._app.get_id(), backgroundColor);
|
||||
|
||||
return backgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downsample large icons before scanning for the backlight color to
|
||||
* improve performance.
|
||||
*
|
||||
* @param pixBuf
|
||||
* @param pixels
|
||||
* @param resampleX
|
||||
* @param resampleY
|
||||
*
|
||||
* @return [];
|
||||
*/
|
||||
_resamplePixels(pixels, resampleX, resampleY) {
|
||||
let resampledPixels = [];
|
||||
// computing the limit outside the for (where it would be repeated at each iteration)
|
||||
// for performance reasons
|
||||
let limit = pixels.length / (resampleX * resampleY) / 4;
|
||||
for (let i = 0; i < limit; i++) {
|
||||
let pixel = i * resampleX * resampleY;
|
||||
|
||||
resampledPixels.push(pixels[pixel * 4]);
|
||||
resampledPixels.push(pixels[pixel * 4 + 1]);
|
||||
resampledPixels.push(pixels[pixel * 4 + 2]);
|
||||
resampledPixels.push(pixels[pixel * 4 + 3]);
|
||||
}
|
||||
|
||||
return resampledPixels;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export const drawRoundedLine = function(cr, x, y, width, height, isRoundLeft, isRoundRight, stroke, fill) {
|
||||
if (height > width) {
|
||||
y += Math.floor((height - width) / 2.0);
|
||||
height = width;
|
||||
}
|
||||
|
||||
height = 2.0 * Math.floor(height / 2.0);
|
||||
|
||||
const leftRadius = isRoundLeft ? height / 2.0 : 0.0;
|
||||
const rightRadius = isRoundRight ? height / 2.0 : 0.0;
|
||||
|
||||
cr.moveTo(x + width - rightRadius, y);
|
||||
cr.lineTo(x + leftRadius, y);
|
||||
if (isRoundLeft)
|
||||
cr.arcNegative(x + leftRadius, y + leftRadius, leftRadius, -Math.PI/2, Math.PI/2);
|
||||
else
|
||||
cr.lineTo(x, y + height);
|
||||
cr.lineTo(x + width - rightRadius, y + height);
|
||||
if (isRoundRight)
|
||||
cr.arcNegative(x + width - rightRadius, y + rightRadius, rightRadius, Math.PI/2, -Math.PI/2);
|
||||
else
|
||||
cr.lineTo(x + width, y);
|
||||
cr.closePath();
|
||||
|
||||
if (fill != null) {
|
||||
cr.setSource(fill);
|
||||
cr.fillPreserve();
|
||||
}
|
||||
if (stroke != null)
|
||||
cr.setSource(stroke);
|
||||
cr.stroke();
|
||||
}
|
||||
1152
windowPreview.js
1152
windowPreview.js
File diff suppressed because it is too large
Load Diff
583
yarn.lock
Normal file
583
yarn.lock
Normal 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==
|
||||
Reference in New Issue
Block a user