10 Commits

Author SHA1 Message Date
Artyom Zorin
a4f86d41f8 Bump to version 68.5.3 2025-08-07 00:11:11 +01:00
Artyom Zorin
582b8b280b Bump to version 68.5.1 2025-08-05 22:50:54 +01:00
Artyom Zorin
ded853bdc2 Bump to version 68.5 2025-08-04 18:37:22 +01:00
Artyom Zorin
216d932ccc Bump to version 68.4 2025-07-31 20:01:46 +01:00
Artyom Zorin
f6c8dd38ce Bump to version 68.3 2025-07-07 13:00:30 +01:00
Artyom Zorin
34717961b6 Bump to version 68.2.3 2025-07-04 20:38:38 +01:00
Artyom Zorin
770649ff0a Updated metadata 2025-06-06 23:05:40 +01:00
Artyom Zorin
35e98e2061 Bump to version 68.2 2025-05-10 23:55:10 +01:00
Artyom Zorin
557250216a Bump to version 68.1 2025-05-02 14:22:16 +01:00
Artyom Zorin
bb69c75c70 Bump to version 65.2 2025-02-27 15:46:57 +00:00
103 changed files with 23281 additions and 17079 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ zorin-taskbar@zorinos.com*.zip
*.mo
po/zorin-taskbar.pot
ui/*.ui.h
node_modules/

View File

@@ -1,18 +1,19 @@
# Basic Makefile
UUID = zorin-taskbar@zorinos.com
BASE_MODULES = extension.js stylesheet.css metadata.json COPYING README.md
EXTRA_MODULES = appIcons.js panel.js panelManager.js proximity.js intellihide.js progress.js panelPositions.js panelSettings.js panelStyle.js overview.js taskbar.js transparency.js windowPreview.js prefs.js utils.js desktopIconsIntegration.js
UI_MODULES = ui/BoxDynamicOpacityOptions.ui ui/BoxGroupAppsOptions.ui ui/BoxIntellihideOptions.ui ui/BoxMiddleClickOptions.ui ui/BoxOverlayShortcut.ui ui/BoxShowDateMenuOptions.ui ui/BoxShowDesktopOptions.ui ui/BoxWindowPreviewOptions.ui ui/SettingsAction.ui ui/SettingsBehavior.ui ui/SettingsPosition.ui ui/SettingsStyle.ui
MODULES = src/*.js src/stylesheet.css metadata.json COPYING README.md
UI_MODULES = ui/*.ui
IMAGES = ./*
EXTRA_IMAGES = show-desktop-symbolic.svg
TOLOCALIZE = prefs.js appIcons.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 = zorin-taskbar@zorinos.com
@@ -20,7 +21,7 @@ INSTALLNAME = zorin-taskbar@zorinos.com
# in the metadata and in the generated zip-file.
ifdef VERSION
else
VERSION = 56
VERSION = 65
endif
ifdef TARGET
@@ -49,7 +50,7 @@ mergepo: potfile
./po/zorin-taskbar.pot: $(TOLOCALIZE)
mkdir -p po
xgettext -k_ -kN_ -o po/zorin-taskbar.pot --package-name "Zorin Taskbar" $(TOLOCALIZE) --from-code=UTF-8
for l in $(UI_MODULES) ; do \
intltool-extract --type=gettext/glade $$l; \
xgettext -k_ -kN_ -o po/zorin-taskbar.pot $$l.h --join-existing --from-code=UTF-8; \
@@ -67,6 +68,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
@@ -79,12 +86,12 @@ zip-file: _build
_build: all
-rm -fR ./_build
mkdir -p _build
cp $(BASE_MODULES) $(EXTRA_MODULES) _build
cp $(MODULES) _build
mkdir -p _build/ui
cp $(UI_MODULES) _build/ui
mkdir -p _build/img
cd img ; cp $(EXTRA_IMAGES) ../_build/img/
cd img ; cp $(IMAGES) ../_build/img/
mkdir -p _build/schemas
cp schemas/*.xml _build/schemas/
cp schemas/gschemas.compiled _build/schemas/

File diff suppressed because it is too large Load Diff

97
debian/changelog vendored
View File

@@ -1,3 +1,100 @@
gnome-shell-extension-zorin-taskbar (68.5.3) noble; urgency=medium
* Added workaround for race condition
-- Artyom Zorin <azorin@zoringroup.com> Thu, 07 Aug 2025 00:09:07 +0100
gnome-shell-extension-zorin-taskbar (68.5.2) noble; urgency=medium
* Fixed settings cache issues
-- Artyom Zorin <azorin@zoringroup.com> Wed, 06 Aug 2025 23:45:25 +0100
gnome-shell-extension-zorin-taskbar (68.5.1) noble; urgency=medium
* Minor code cleanups
-- Artyom Zorin <azorin@zoringroup.com> Tue, 05 Aug 2025 22:47:20 +0100
gnome-shell-extension-zorin-taskbar (68.5) noble; urgency=medium
* Rebased on upstream commit 16e16c11ce08abc3c9f0bf922bbc08e17b2c1f08
-- Artyom Zorin <azorin@zoringroup.com> Mon, 04 Aug 2025 13:46:11 +0100
gnome-shell-extension-zorin-taskbar (68.4) noble; urgency=medium
* Applied monitor selection and reset geometry fixes
-- Artyom Zorin <azorin@zoringroup.com> Thu, 31 Jul 2025 19:40:58 +0100
gnome-shell-extension-zorin-taskbar (68.3) noble; urgency=medium
* Removed code to handle overview startup animation
-- Artyom Zorin <azorin@zoringroup.com> Mon, 07 Jul 2025 12:56:41 +0100
gnome-shell-extension-zorin-taskbar (68.2.3) noble; urgency=medium
* Fixed logic error when adjusting panel menu buttons
-- Artyom Zorin <azorin@zoringroup.com> Fri, 04 Jul 2025 20:36:32 +0100
gnome-shell-extension-zorin-taskbar (68.2.2) noble; urgency=medium
* Added settings schema to metadata file
-- Artyom Zorin <azorin@zoringroup.com> Fri, 06 Jun 2025 23:03:34 +0100
gnome-shell-extension-zorin-taskbar (68.2.1) noble; urgency=medium
* Updated debian control file
-- Artyom Zorin <azorin@zoringroup.com> Fri, 23 May 2025 20:05:49 +0100
gnome-shell-extension-zorin-taskbar (68.2) noble; urgency=medium
* Corrected code to detect Tiling Shell gap offset
-- Artyom Zorin <azorin@zoringroup.com> Sat, 10 May 2025 23:52:12 +0100
gnome-shell-extension-zorin-taskbar (68.1) noble; urgency=medium
* Adjusted app icon margins and padding
-- Artyom Zorin <azorin@zoringroup.com> Fri, 02 May 2025 14:19:18 +0100
gnome-shell-extension-zorin-taskbar (68) noble; urgency=medium
* Re-based on upstream version 68
-- Artyom Zorin <azorin@zoringroup.com> Tue, 29 Apr 2025 20:36:02 +0100
gnome-shell-extension-zorin-taskbar (65.3) noble; urgency=medium
* Changed activities button default position
-- Artyom Zorin <azorin@zoringroup.com> Sun, 02 Mar 2025 19:39:09 +0000
gnome-shell-extension-zorin-taskbar (65.2) noble; urgency=medium
* Separated floating rounded theme from intellihide as an independent
styling option
-- Artyom Zorin <azorin@zoringroup.com> Thu, 27 Feb 2025 13:57:03 +0000
gnome-shell-extension-zorin-taskbar (65.1) noble; urgency=medium
* Fixed various bugs
-- Artyom Zorin <azorin@zoringroup.com> Wed, 26 Feb 2025 12:20:34 +0000
gnome-shell-extension-zorin-taskbar (65) noble; urgency=medium
* Re-based on upstream version 65
-- Artyom Zorin <azorin@zoringroup.com> Tue, 25 Feb 2025 22:29:43 +0000
gnome-shell-extension-zorin-taskbar (56.11) jammy; urgency=medium
* Updated French translations

4
debian/control vendored
View File

@@ -8,6 +8,6 @@ Rules-Requires-Root: no
Package: gnome-shell-extension-zorin-taskbar
Architecture: all
Depends: ${misc:Depends}, gnome-shell (>= 42), gnome-shell (<< 45~)
Depends: ${misc:Depends}, gnome-shell (>= 46), gnome-shell (<< 49~)
Description: Zorin Taskbar extension
A taskbar extension for the Zorin Desktop environment.
A taskbar extension for the Zorin OS desktop.

4
debian/copyright vendored
View File

@@ -2,8 +2,8 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: gnome-shell-extension-zorin-taskbar
Files: *
Copyright: 2016-2021, Jason DeRose (https://github.com/jderose9)
2016-2023, Zorin OS Technologies Ltd.
Copyright: 2016-2025, Jason DeRose (https://github.com/jderose9)
2016-2025, Zorin OS Technologies Ltd.
License: GPL-2+
Files: po/cs.po

View File

@@ -1,159 +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.
*
*******************************************************************************/
const GLib = imports.gi.GLib;
const Main = imports.ui.main;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const IDENTIFIER_UUID = "130cbc66-235c-4bd6-8571-98d2d8bba5e2";
var DesktopIconsUsableAreaClass = class {
constructor() {
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 (extension.state === ExtensionUtils.ExtensionState.ENABLED) {
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 (extension?.state !== ExtensionUtils.ExtensionState.ENABLED)
return;
const usableArea = extension?.stateObj?.DesktopIconsUsableArea;
if (usableArea?.uuid === IDENTIFIER_UUID)
usableArea.setMarginsForExtension(Me.uuid, this._margins);
}
}

View File

@@ -1,146 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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/>.
*
*/
const Main = imports.ui.main;
const Meta = imports.gi.Meta;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const WindowManager = imports.ui.windowManager;
const ExtensionUtils = imports.misc.extensionUtils;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Me = ExtensionUtils.getCurrentExtension();
const { PanelManager } = Me.imports.panelManager;
const Utils = Me.imports.utils;
const AppIcons = Me.imports.appIcons;
const ZORIN_DASH_UUID = 'zorin-dash@zorinos.com';
let panelManager;
let extensionChangedHandler;
let disabledZorinDash;
let extensionSystem = (Main.extensionManager || imports.ui.extensionSystem);
function init() {
this._realHasOverview = Main.sessionMode.hasOverview;
ExtensionUtils.initTranslations(Utils.TRANSLATION_DOMAIN);
//create an object that persists until gnome-shell is restarted, even if the extension is disabled
Me.persistentStorage = {};
}
function enable() {
// The Zorin Dash extension might get enabled after this extension
extensionChangedHandler = extensionSystem.connect('extension-state-changed', (data, extension) => {
if (extension.uuid === ZORIN_DASH_UUID && extension.state === 1) {
_enable();
}
});
//create a global object that can emit signals and conveniently expose functionalities to other extensions
global.zorinTaskbar = {};
Signals.addSignalMethods(global.zorinTaskbar);
_enable();
}
function _enable() {
let zorinDash = Main.extensionManager ?
Main.extensionManager.lookup(ZORIN_DASH_UUID) : //gnome-shell >= 3.33.4
ExtensionUtils.extensions[ZORIN_DASH_UUID];
if (zorinDash && zorinDash.stateObj && zorinDash.stateObj.dockManager) {
// Disable Zorin Dash
let extensionOrder = (extensionSystem.extensionOrder || extensionSystem._extensionOrder);
Utils.getStageTheme().get_theme().unload_stylesheet(zorinDash.stylesheet);
zorinDash.stateObj.disable();
disabledZorinDash = true;
zorinDash.state = 2; //ExtensionState.DISABLED
extensionOrder.splice(extensionOrder.indexOf(ZORIN_DASH_UUID), 1);
//reset to prevent conflicts with the Zorin Dash
if (panelManager) {
disable(true);
}
}
if (panelManager) return; //already initialized
Me.settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.zorin-taskbar');
Me.desktopSettings = ExtensionUtils.getSettings('org.gnome.desktop.interface');
Main.layoutManager.startInOverview = false;
if (Main.layoutManager._startingUp) {
Main.sessionMode.hasOverview = false;
Main.layoutManager.connect('startup-complete', () => {
Main.sessionMode.hasOverview = this._realHasOverview
});
}
panelManager = new PanelManager();
panelManager.enable();
Utils.removeKeybinding('open-application-menu');
Utils.addKeybinding(
'open-application-menu',
new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA }),
() => {
panelManager.primaryPanel.taskbar.popupFocusedAppSecondaryMenu();
},
Shell.ActionMode.NORMAL | Shell.ActionMode.POPUP
);
}
function disable(reset) {
panelManager.disable();
Me.settings.run_dispose();
Me.desktopSettings.run_dispose();
delete Me.settings;
panelManager = null;
Utils.removeKeybinding('open-application-menu');
Utils.addKeybinding(
'open-application-menu',
new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA }),
Main.wm._toggleAppMenu.bind(Main.wm),
Shell.ActionMode.NORMAL | Shell.ActionMode.POPUP
);
if (!reset) {
extensionSystem.disconnect(extensionChangedHandler);
delete global.zorinTaskbar;
// Re-enable Zorin Dash if it was disabled by dash to panel
if (disabledZorinDash && Main.sessionMode.allowExtensions) {
(extensionSystem._callExtensionEnable || extensionSystem.enableExtension).call(extensionSystem, ZORIN_DASH_UUID);
}
AppIcons.resetRecentlyClickedApp();
}
Main.sessionMode.hasOverview = this._realHasOverview;
}

View File

@@ -1,468 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
*/
const Clutter = imports.gi.Clutter;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
var GrabHelper = imports.ui.grabHelper;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const OverviewControls = imports.ui.overviewControls;
const PointerWatcher = imports.ui.pointerWatcher;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Panel = Me.imports.panel;
const Proximity = Me.imports.proximity;
const Utils = Me.imports.utils;
var INTELLIHIDE_PRESSURE_THRESHOLD = 100;
var INTELLIHIDE_PRESSURE_TIME = 1000;
var INTELLIHIDE_ANIMATION_TIME = 200;
var INTELLIHIDE_CLOSE_DELAY = 400;
var INTELLIHIDE_ENABLE_START_DELAY = 2000;
//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 = 'panelBoxClipTimeout';
var SIDE_CONTROLS_ANIMATION_TIME = OverviewControls.SIDE_CONTROLS_ANIMATION_TIME / (OverviewControls.SIDE_CONTROLS_ANIMATION_TIME > 1 ? 1000 : 1);
var Hold = {
NONE: 0,
TEMPORARY: 1,
PERMANENT: 2
};
var 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 = Me.settings.connect('changed::intellihide', () => this._changeEnabledStatus());
this._intellihideOnlySecondaryChangedId = Me.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 (Me.settings.get_boolean('intellihide-hide-from-windows')) {
this._proximityWatchId = this._proximityManager.createWatch(
this._panelBox.get_parent(),
this._dtpPanel.monitor.index,
Proximity.Mode[Me.settings.get_string('intellihide-behaviour')],
0, 0,
overlap => {
this._windowOverlap = overlap;
this._queueUpdatePanelPosition();
}
);
}
this._setRevealMechanism();
this._queueUpdatePanelPosition();
this._toggleFloatingRoundedTheme();
}
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;
if (this._panelBox.has_style_class_name('floating')) {
this._panelBox.remove_style_class_name('floating');
this._resetPanelGeometry();
}
}
destroy() {
Me.settings.disconnect(this._intellihideChangedId);
Me.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();
}
_toggleFloatingRoundedTheme() {
if (Me.settings.get_boolean('intellihide-floating-rounded-theme')) {
if (!this._panelBox.has_style_class_name('floating'))
this._panelBox.add_style_class_name('floating');
} else {
if (this._panelBox.has_style_class_name('floating'))
this._panelBox.remove_style_class_name('floating');
}
this._resetPanelGeometry();
}
_resetPanelGeometry() {
this._dtpPanel.geom = this._dtpPanel.getGeometry();
this._dtpPanel._setPanelPosition();
this._dtpPanel.dynamicTransparency.updateExternalStyle();
}
_changeEnabledStatus() {
let intellihide = Me.settings.get_boolean('intellihide');
let onlySecondary = Me.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();
}
],
[
Me.settings,
[
'changed::intellihide-use-pressure',
'changed::intellihide-hide-from-windows',
'changed::intellihide-behaviour'
],
() => this.reset()
],
[
Me.settings,
[
'changed::intellihide-floating-rounded-theme'
],
() => this._toggleFloatingRoundedTheme()
],
[
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 && Me.settings.get_boolean('intellihide-use-pressure')) {
this._edgeBarrier = this._createBarrier();
this._pressureBarrier = new Layout.PressureBarrier(
INTELLIHIDE_PRESSURE_THRESHOLD,
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 Me.settings.get_boolean('intellihide-show-in-fullscreen');
}
return !mouseBtnIsPressed;
}
if (!Me.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 :
INTELLIHIDE_ANIMATION_TIME * 0.001,
//only delay the animation when hiding the panel after the user hovered out
delay: destination != 0 && this._hoveredOut ? 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;
}
}

View File

@@ -1,9 +1,10 @@
{
"extension-id": "zorin-taskbar",
"uuid": "zorin-taskbar@zorinos.com",
"name": "Zorin Taskbar",
"description": "A taskbar extension for the Zorin Desktop environment.",
"shell-version": [ "42", "43", "44" ],
"gettext-domain": "zorin-taskbar",
"version": 56
"extension-id": "zorin-taskbar",
"uuid": "zorin-taskbar@zorinos.com",
"name": "Zorin Taskbar",
"description": "A taskbar extension for the Zorin OS desktop.",
"shell-version": [ "46", "47", "48" ],
"gettext-domain": "zorin-taskbar",
"settings-schema": "org.gnome.shell.extensions.zorin-taskbar",
"version": 68
}

View File

@@ -1,462 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Dash to Panel extension
* Some code was also adapted from the upstream Gnome Shell source code.
*/
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Intellihide = Me.imports.intellihide;
const Utils = Me.imports.utils;
const Clutter = imports.gi.Clutter;
const Main = imports.ui.main;
const Shell = imports.gi.Shell;
const Gtk = imports.gi.Gtk;
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
const Mainloop = imports.mainloop;
const IconGrid = imports.ui.iconGrid;
const { OverviewActor } = imports.ui.overview;
const Workspace = imports.ui.workspace;
const St = imports.gi.St;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
const Meta = imports.gi.Meta;
const GS_HOTKEYS_KEY = 'switch-to-application-';
const OVERLAY_TIMEOUT = 750;
const SHORTCUT_TIMEOUT = 2000;
// 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';
var Overview = class {
constructor() {
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._toggleDash();
this._adaptAlloc(true);
this._signalsHandler.add([
Me.settings,
[
'changed::panel-sizes'
],
() => this._toggleDash()
]);
}
disable() {
this._signalsHandler.destroy();
this._injectionsHandler.destroy();
this._timeoutsHandler.destroy();
this._toggleDash(true);
this._adaptAlloc();
// Remove key bindings
this._disableHotKeys();
this._disableExtraShortcut();
}
_toggleDash(visible) {
if (visible === undefined) {
visible = false;
}
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(enable) {
let overviewControls = Main.overview._overview._controls
let proto = Object.getPrototypeOf(overviewControls)
let allocFunc = null
if (enable)
allocFunc = (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 is very good and 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
}
proto.vfunc_allocate.call(overviewControls, box)
}
Utils.hookVfunc(proto, 'allocate', allocFunc)
}
/**
* 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([
Me.settings,
'changed::isolate-workspaces',
() => {
this._panel.panelManager.allPanels.forEach(p => p.taskbar.resetAppIcons());
if (Me.settings.get_boolean('isolate-workspaces'))
enable();
else
disable();
}
]);
if (Me.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 (Me.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 (Me.settings.get_boolean('hot-keys'))
this._enableHotKeys();
this._signalsHandler.add([
Me.settings,
'changed::hot-keys',
() => {
if (Me.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 = Me.settings.get_string('shortcut-num-keys');
let bothNumKeys = shortcutNumKeys == 'BOTH';
let keys = [];
let prefixModifiers = Clutter.ModifierType.SUPER_MASK
if (Me.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), Me.settings, () => this._activateApp(appNum, modifiers));
}
}, this);
this._hotKeysEnabled = true;
if (Me.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: imports.ui.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 (Me.settings.get_boolean('hot-keys'))
this._enableExtraShortcut();
this._signalsHandler.add([
Me.settings,
'changed::hot-keys',
this._checkHotkeysOptions.bind(this)
], [
Me.settings,
'changed::hotkeys-overlay-combo',
() => {
if (Me.settings.get_boolean('hot-keys') && Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS')
this.taskbar.toggleNumberOverlay(true);
else
this.taskbar.toggleNumberOverlay(false);
}
], [
Me.settings,
'changed::shortcut-num-keys',
() => this._resetHotkeys()
]);
}
_checkHotkeysOptions() {
if (Me.settings.get_boolean('hot-keys'))
this._enableExtraShortcut();
else
this._disableExtraShortcut();
}
_enableExtraShortcut() {
Utils.addKeybinding('shortcut', Me.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 = Me.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 = OVERLAY_TIMEOUT;
if (overlayFromShortcut) {
timeout = 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);
}]);
}
_onSwipeBegin() {
this._swiping = true;
return true;
}
_onSwipeEnd() {
this._timeoutsHandler.add([
T1,
0,
() => this._swiping = false
]);
return true;
}
}

1237
panel.js

File diff suppressed because it is too large Load Diff

View File

@@ -1,755 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Dash to Panel extension
*
* 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.
*/
const Me = imports.misc.extensionUtils.getCurrentExtension();
const { Overview } = Me.imports.overview;
const { Panel, panelBoxes } = Me.imports.panel;
const PanelSettings = Me.imports.panelSettings;
const Proximity = Me.imports.proximity;
const Taskbar = Me.imports.taskbar;
const Utils = Me.imports.utils;
const DesktopIconsIntegration = Me.imports.desktopIconsIntegration;
const Gi = imports._gi;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Clutter = imports.gi.Clutter;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const AppDisplay = imports.ui.appDisplay;
const BoxPointer = imports.ui.boxpointer;
const Dash = imports.ui.dash;
const IconGrid = imports.ui.iconGrid;
const LookingGlass = imports.ui.lookingGlass;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const Layout = imports.ui.layout;
const WM = imports.ui.windowManager;
const { SecondaryMonitorDisplay, WorkspacesView } = imports.ui.workspacesView;
var PanelManager = class {
constructor() {
this.overview = new Overview();
this.panelsElementPositions = {};
this._saveMonitors();
}
enable(reset) {
this.allPanels = [];
this.dtpPrimaryMonitor = Main.layoutManager.primaryMonitor; // The real primary monitor should always have the main panel
this.proximityManager = new Proximity.ProximityManager();
if (this.dtpPrimaryMonitor) {
this.primaryPanel = this._createPanel(this.dtpPrimaryMonitor, Me.settings.get_boolean('stockgs-keep-top-panel'));
this.allPanels.push(this.primaryPanel);
this.overview.enable(this.primaryPanel);
this.setFocusedMonitor(this.dtpPrimaryMonitor);
}
if (Me.settings.get_boolean('multi-monitors')) {
Main.layoutManager.monitors.filter(m => m != this.dtpPrimaryMonitor).forEach(m => {
this.allPanels.push(this._createPanel(m, true));
});
}
global.zorinTaskbar.panels = this.allPanels;
global.zorinTaskbar.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;
Utils.hookVfunc(BoxPointer.BoxPointer.prototype, '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();
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(
[
Me.settings,
[
'changed::multi-monitors',
'changed::isolate-monitors',
'changed::panel-positions',
'changed::panel-lengths',
'changed::panel-anchors',
'changed::stockgs-keep-top-panel'
],
() => this._reset()
],
[
Me.settings,
'changed::panel-element-positions',
() => this._updatePanelElementPositions()
],
[
Me.settings,
'changed::intellihide-key-toggle-text',
() => this._setKeyBindings(true)
],
[
Me.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();
}
}
]
);
panelBoxes.forEach(c => this._signalsHandler.add(
[
Main.panel[c],
'actor-added',
(parent, child) =>
this.primaryPanel &&
this._adjustPanelMenuButton(this._getPanelMenuButton(child), this.primaryPanel.monitor, this.primaryPanel.getPosition())
]
));
this._setKeyBindings(true);
// keep GS overview.js from blowing away custom panel styles
if(!Me.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(p.panel);
p.panelBox.set_position(clipContainer.x, clipContainer.y);
clipContainer.remove_child(p.panelBox);
Main.layoutManager.addChrome(p.panelBox, { affectsStruts: true, trackFullscreen: true });
}
});
if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) {
Utils.hookVfunc(BoxPointer.BoxPointer.prototype, 'get_preferred_height', BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height);
}
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();
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;
}
}
_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 imports.ui.workspacesView.SecondaryMonitorDisplay(i,
this._controls,
this._scrollAdjustment,
this._fitModeAdjustment,
this._overviewAdjustment);
Main.layoutManager.overviewGroup.add_actor(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 primaryIndex = Main.layoutManager.primaryIndex;
let newMonitors = [primaryIndex];
Main.layoutManager.monitors.filter(m => m.index != primaryIndex).forEach(m => newMonitors.push(m.index));
Me.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(this, monitor, panelBox, isStandalone);
panelBox.add(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(Me.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 && Me.settings.get_boolean('intellihide')) {
monitor = monitor || Main.layoutManager.findMonitorForActor(boxPointer.sourceActor);
let panel = Utils.find(global.zorinTaskbar.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, Me.settings, keys[k], Shell.ActionMode.NORMAL);
}
});
}
};
// This class drives long-running icon animations, to keep them running in sync
// with each other.
var 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.zorinTaskbar.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) {
// 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.zorinTaskbar.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();
}

View File

@@ -1,64 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
*/
var SHOW_APPS_BTN = 'showAppsButton';
var ACTIVITIES_BTN = 'activitiesButton';
var TASKBAR = 'taskbar';
var DATE_MENU = 'dateMenu';
var SYSTEM_MENU = 'systemMenu';
var LEFT_BOX = 'leftBox';
var CENTER_BOX = 'centerBox';
var RIGHT_BOX = 'rightBox';
var DESKTOP_BTN = 'desktopButton';
var STACKED_TL = 'stackedTL';
var STACKED_BR = 'stackedBR';
var CENTERED = 'centered';
var CENTERED_MONITOR = 'centerMonitor';
var TOP = 'TOP';
var BOTTOM = 'BOTTOM';
var LEFT = 'LEFT';
var RIGHT = 'RIGHT';
var START = 'START';
var MIDDLE = 'MIDDLE';
var END = 'END';
var defaults = [
{ element: LEFT_BOX, visible: true, position: STACKED_TL },
{ element: SHOW_APPS_BTN, visible: false, position: STACKED_TL },
{ element: ACTIVITIES_BTN, 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: SYSTEM_MENU, visible: true, position: STACKED_BR },
{ element: DATE_MENU, visible: true, position: STACKED_BR },
{ element: DESKTOP_BTN, visible: false, position: STACKED_BR },
];
var optionDialogFunctions = {};
optionDialogFunctions[DATE_MENU] = '_showDateMenuOptions';
optionDialogFunctions[DESKTOP_BTN] = '_showDesktopButtonOptions';
function checkIfCentered(position) {
return position == CENTERED || position == CENTERED_MONITOR;
}

View File

@@ -1,112 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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/>.
*/
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Pos = Me.imports.panelPositions;
/** Return object representing a settings value that is stored as JSON. */
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. */
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. */
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;
}
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
*/
function getPanelLength(settings, monitorIndex) {
const lengths = getSettingsJson(settings, 'panel-lengths');
const theDefault = 100;
return lengths[monitorIndex] || theDefault;
}
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. */
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;
}
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. */
function getPanelAnchor(settings, monitorIndex) {
const anchors = getSettingsJson(settings, 'panel-anchors');
const theDefault = Pos.MIDDLE;
return anchors[monitorIndex] || theDefault;
}
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);
}

View File

@@ -1,170 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
* 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
*/
const Me = imports.misc.extensionUtils.getCurrentExtension();
const ExtensionUtils = imports.misc.extensionUtils;
const Main = imports.ui.main;
const Mainloop = imports.mainloop;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Panel = Me.imports.panel;
const Taskbar = Me.imports.taskbar;
const Utils = Me.imports.utils;
var PanelStyle = class {
enable(panel) {
this.panel = panel;
this._applyStyles();
}
disable() {
this._removeStyles();
}
_applyStyles() {
this._rightBoxOperations = [];
// center box has been moved next to the right box and will be treated the same
this._centerBoxOperations = this._rightBoxOperations;
this._leftBoxOperations = [];
this._applyStylesRecursively();
/* connect signal */
this._rightBoxActorAddedID = this.panel._rightBox.connect('actor-added',
(container, actor) => {
if(this._rightBoxOperations.length && !this._ignoreAddedChild)
this._recursiveApply(actor, this._rightBoxOperations);
this._ignoreAddedChild = 0;
}
);
this._centerBoxActorAddedID = this.panel._centerBox.connect('actor-added',
(container, actor) => {
if(this._centerBoxOperations.length && !this._ignoreAddedChild)
this._recursiveApply(actor, this._centerBoxOperations);
this._ignoreAddedChild = 0;
}
);
this._leftBoxActorAddedID = this.panel._leftBox.connect('actor-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);
}
}
}
_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);
}
}
}

View File

@@ -18,6 +18,3 @@ msgstr "Wys Rekenaar-Ikoon"
msgid "Show Desktop button padding (px)"
msgstr "Wys Rekenaar-Ikoon vulling (px)"
msgid "Floating rounded theme"
msgstr "Swewende afgeronde tema"

View File

@@ -22,8 +22,5 @@ msgstr "أظهر أيقونات سطح المكتب"
msgid "Show Desktop button padding (px)"
msgstr "أظهر زر سطح المكتب المساحة المتروكة (بيكسل)"
msgid "Floating rounded theme"
msgstr "مظهر دائري عائم"
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "عزل مساحات العمل والشاشات في إعدادات تبديل التطبيقات"

View File

@@ -21,6 +21,3 @@ msgstr "Паказаць значок працоўнага стала"
msgid "Show Desktop button padding (px)"
msgstr "Пракладка Паказаць кнопку працоўнага стала (px)"
msgid "Floating rounded theme"
msgstr "Плаваючая круглявая тэма"

View File

@@ -21,6 +21,3 @@ msgstr "Показване на икона на работния плот"
msgid "Show Desktop button padding (px)"
msgstr "Бутон Покажи работния плот - подложка (px)"
msgid "Floating rounded theme"
msgstr "Плаваща заоблена тема"

View File

@@ -18,6 +18,3 @@ msgstr "ডেস্কটপ আইকন দেখান"
msgid "Show Desktop button padding (px)"
msgstr "Show Desktop button প্যাডিং (px আকারে)"
msgid "Floating rounded theme"
msgstr "ভাসমান বৃত্তাকার থিম"

View File

@@ -21,6 +21,3 @@ msgstr "Mostrar l'icona de l'Escriptori"
msgid "Show Desktop button padding (px)"
msgstr "Farciment Mostra el botó de l'escriptori (px)"
msgid "Floating rounded theme"
msgstr "Tema flotant arrodonit"

418
po/cs.po

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,3 @@ msgstr "Vis skrivebords ikon"
msgid "Show Desktop button padding (px)"
msgstr "Vis skrivebords knap afstand (px)"
msgid "Floating rounded theme"
msgstr "Flydende afrundet tema"

629
po/de.po

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,3 @@ msgstr "Εμφάνιση επιφάνειας εργασίας"
msgid "Show Desktop button padding (px)"
msgstr "Εμφάνισε διαχωριστικό"
msgid "Floating rounded theme"
msgstr "Κυμαινόμενο στρογγυλεμένο θέμα"

View File

@@ -255,6 +255,12 @@ msgstr "Importar configuraciones"
msgid "Quit"
msgstr "Salir"
#: appIcons.js:1497
msgid "Quit %d Window"
msgid_plural "Quit %d Windows"
msgstr[0] "Cerrar %d ventana"
msgstr[1] "Cerrar %d ventanas"
#: appIcons.js:1515
msgid "Windows"
msgstr "Ventanas"
@@ -1501,9 +1507,6 @@ msgstr "Mostrar Escritorio - ícono"
msgid "Show Desktop button padding (px)"
msgstr "Mostrar Escritorio - espaciado del botón (px)"
msgid "Floating rounded theme"
msgstr "Tema flotante redondeado"
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Aislar espacios de trabajo y monitores en la configuración de Cambio de aplicaciones"

View File

@@ -21,6 +21,3 @@ msgstr "Kuva töölauaikoon"
msgid "Show Desktop button padding (px)"
msgstr "Täitmine Kuva töölaua nupp (px)"
msgid "Floating rounded theme"
msgstr "Ujuv ümardatud teema"

View File

@@ -1466,9 +1466,6 @@ msgstr "نمایش آیکون دسکتاپ"
msgid "Show Desktop button padding (px)"
msgstr "حاشیه‌ی دکمه‌ی نمایش دسکتاپ (px)"
msgid "Floating rounded theme"
msgstr "تم گرد و شناور"
#~ msgid "Show Details"
#~ msgstr "نمایش جزییات"

View File

@@ -21,6 +21,3 @@ msgstr "Näytä työpöytä-kuvake"
msgid "Show Desktop button padding (px)"
msgstr "Näytä työpöytä painikkeen asettelu (px)"
msgid "Floating rounded theme"
msgstr "Kelluva ja pyöristetty teema"

875
po/fr.po

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,3 @@ msgstr "Taispeáin deilbhín Deisce"
msgid "Show Desktop button padding (px)"
msgstr "Stuáil Taispeáin cnaipe Deisce (px)"
msgid "Floating rounded theme"
msgstr "Téama chothromú ar snámh"

View File

@@ -1505,9 +1505,6 @@ msgstr "Mostrar iconas na escritorio"
msgid "Show Desktop button padding (px)"
msgstr "Recheo Mostrar o botón do escritorio (px)"
msgid "Floating rounded theme"
msgstr "Tema redondeado flotante"
#~ msgid "Top, with plugin icons collapsed to bottom"
#~ msgstr "Arriba, coas iconas contraídas"

View File

@@ -21,6 +21,3 @@ msgstr "ડેસ્કટ .પ ચિહ્ન બતાવો"
msgid "Show Desktop button padding (px)"
msgstr "ડેસ્કટtopપ બટન બતાવો પેડિંગ (પીએક્સ)"
msgid "Floating rounded theme"
msgstr "ફ્લોટિંગ ગોળાકાર થીમ"

View File

@@ -21,6 +21,3 @@ msgstr "הצגת סמל שולחן העבודה"
msgid "Show Desktop button padding (px)"
msgstr "ריפוד הצגת כפתור שולחן עבודה (פיקסלים)"
msgid "Floating rounded theme"
msgstr "ערכת נושא מעוגלת עם ריחוף"

View File

@@ -22,8 +22,5 @@ msgstr "डेस्कटॉप आइकन दिखाएं"
msgid "Show Desktop button padding (px)"
msgstr "डेस्कटॉप बटन दिखाएं पैडिंग (पीएक्स)"
msgid "Floating rounded theme"
msgstr "फ़्लोटिंग गोलाकार थीम"
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "एप्लिकेशन स्विचिंग सेटिंग्स में कार्यस्थलों और मॉनिटर को अलग करें"

View File

@@ -21,6 +21,3 @@ msgstr "Prikaži ikonu radne površine"
msgid "Show Desktop button padding (px)"
msgstr "Podmetač Prikaži gumb radne površine (px)"
msgid "Floating rounded theme"
msgstr "Plutajuća zaobljena tema"

View File

@@ -1503,9 +1503,6 @@ msgstr "Asztali ikon megjelenítése"
msgid "Show Desktop button padding (px)"
msgstr "Asztal megjelenítése gomb margója (px)"
msgid "Floating rounded theme"
msgstr "Lebegő lekerekített téma"
#~ msgid "Current Show Applications icon"
#~ msgstr "Jelenlegi „Alkalmazások megjelenítése” ikon"

View File

@@ -22,8 +22,5 @@ msgstr "Tampilkan ikon desktop"
msgid "Show Desktop button padding (px)"
msgstr "Tampilkan tombol desktop padding (px)"
msgid "Floating rounded theme"
msgstr "Tema bulat mengambang"
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Isolasi Ruang Kerja dan Monitor dalam pengaturan Pengalihan Aplikasi"

View File

@@ -21,6 +21,3 @@ msgstr "Sýna skjáborðstáknið"
msgid "Show Desktop button padding (px)"
msgstr "„Sýna skjáborðshnapp“ padding (px)"
msgid "Floating rounded theme"
msgstr "Fljótandi ávalið þema"

255
po/it.po
View File

@@ -2,15 +2,16 @@
# This file is distributed under the same license as the Dash to Panel package.
# Enrico Bella <enricobe@hotmail.com>, 2018.
# Kowalski7cc <kowalski.7cc@gmail.com>, 2020.
# Albano Battistella <albanobattistella@gmail.com>, 2023.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-02-08 08:31-0500\n"
"PO-Revision-Date: 2020-05-15 23:12+0200\n"
"Last-Translator: l3nn4rt <l3nn4rt@protonmail.com>\n"
"Language-Team: \n"
"PO-Revision-Date: 2023-12-22 20:38+0200\n"
"Last-Translator: Albano Battistella <albanoattistella@gmail.com>\n"
"Language-Team: Italian\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -35,9 +36,8 @@ msgid "Left"
msgstr "Sinistra"
#: prefs.js:318
#, fuzzy
msgid "Center"
msgstr "Allinea al centro dello spazio disponibile"
msgstr "Centro"
#: prefs.js:319 ui/SettingsPosition.ui.h:13 ui/SettingsStyle.ui.h:12
msgid "Right"
@@ -50,7 +50,7 @@ msgstr "Alto"
#: prefs.js:322 prefs.js:327 ui/SettingsPosition.ui.h:21
msgid "Middle"
msgstr ""
msgstr "A metà"
#: prefs.js:323 ui/BoxWindowPreviewOptions.ui.h:37 ui/SettingsPosition.ui.h:10
#: ui/SettingsStyle.ui.h:9
@@ -59,11 +59,11 @@ msgstr "Basso"
#: prefs.js:326 ui/SettingsPosition.ui.h:20
msgid "Start"
msgstr ""
msgstr "Inizio"
#: prefs.js:328 ui/SettingsPosition.ui.h:22
msgid "End"
msgstr ""
msgstr "Fine"
#: prefs.js:413
msgid "Show Applications button"
@@ -155,7 +155,7 @@ msgstr "Opzioni Mostra Applicazioni"
#: prefs.js:530
msgid "Open icon"
msgstr ""
msgstr "Apri icona"
#: prefs.js:577
msgid "Show Desktop options"
@@ -164,7 +164,7 @@ msgstr "Opzioni Mostra Desktop"
#: prefs.js:661
#, javascript-format
msgid "%d ms"
msgstr ""
msgstr "%d ms"
#: prefs.js:666
#, javascript-format
@@ -185,8 +185,8 @@ msgstr ""
#, javascript-format
msgid "%d icon"
msgid_plural "%d icons"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d icona"
msgstr[1] "%d icone"
#: prefs.js:782
msgid "Running Indicator Options"
@@ -241,9 +241,8 @@ msgid "Advanced Options"
msgstr "Impostazioni avanzate"
#: prefs.js:2040
#, fuzzy
msgid "App icon animation options"
msgstr "Opzioni Mostra Applicazioni"
msgstr "Opzioni di animazione dell'icona dell'app"
#: prefs.js:2088
msgid "Export settings"
@@ -288,9 +287,8 @@ msgid "Terminal"
msgstr "Terminale"
#: appIcons.js:1824
#, fuzzy
msgid "System Monitor"
msgstr "Isola monitor"
msgstr "Monitor di sistema"
#: appIcons.js:1829
msgid "Files"
@@ -330,50 +328,47 @@ msgstr "Ancora niente!"
#: ui/BoxAdvancedOptions.ui.h:2
msgid "For real..."
msgstr ""
msgstr "Per davvero..."
#: ui/BoxAnimateAppIconHoverOptions.ui.h:1
#, fuzzy
msgid "Animation type"
msgstr "Durata animazione (ms)"
msgstr "Tipo di animazione"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:2
msgid "Simple"
msgstr ""
msgstr "Semplice"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:3
msgid "Ripple"
msgstr ""
msgstr "Ondulata"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:4
msgid "Plank"
msgstr ""
msgstr "Plank"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:5
msgid "Duration"
msgstr ""
msgstr "Durata"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:6
#, fuzzy
msgid "Rotation"
msgstr "Posizione"
msgstr "Rotazione"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:7
msgid "Travel"
msgstr ""
msgstr "Gamma di movimento"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:8
msgid "Zoom"
msgstr ""
msgstr "Zoom"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:9
msgid "Convexity"
msgstr ""
msgstr "Convessità"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:10
#, fuzzy
msgid "Extent"
msgstr "Estensioni"
msgstr "Estensione"
#: ui/BoxDotOptions.ui.h:1
msgid "Highlight focused application"
@@ -498,16 +493,12 @@ msgid "Font color of the minimized application titles"
msgstr "Colore font titoli delle applicazioni minimizzate"
#: ui/BoxGroupAppsOptions.ui.h:10
#, fuzzy
msgid "Maximum width (px) of the application titles"
msgstr "Larghezza massima (px) dei titoli delle app (predef. 160)"
msgstr "Larghezza massima (px) dei titoli delle applicazioni"
#: ui/BoxGroupAppsOptions.ui.h:11
#, fuzzy
msgid "(default is 160)"
msgstr ""
"Dimensione pannello\n"
"(predefinito 48)"
msgstr "(predefinito è 160)"
#: ui/BoxGroupAppsOptions.ui.h:12
msgid "Use a fixed width for the application titles"
@@ -532,9 +523,8 @@ msgid "Use the favorite icons as application launchers"
msgstr "Usa le icone dei Preferiti come lanciatori delle app"
#: ui/BoxIntellihideOptions.ui.h:1
#, fuzzy
msgid "Only hide the panel when it is obstructed by windows"
msgstr "Nascondi pannello solo quando è ostruito dalle finestre "
msgstr "Nascondi il pannello solo quando è ostruito da finestre"
#: ui/BoxIntellihideOptions.ui.h:2
msgid "The panel hides from"
@@ -557,14 +547,12 @@ msgid "Allow the panel to be revealed while in fullscreen mode"
msgstr "Permetti al pannello di apparire quando in modalità fullscreen"
#: ui/BoxIntellihideOptions.ui.h:10
#, fuzzy
msgid "Only hide secondary panels"
msgstr "Visualizza l'orologio su pannelli secondari"
msgstr "Nascondi solo i pannelli secondari"
#: ui/BoxIntellihideOptions.ui.h:11
#, fuzzy
msgid "(requires multi-monitors option)"
msgstr "Opzioni multi-monitor"
msgstr "(richiede l'opzione multi-monitor)"
#: ui/BoxIntellihideOptions.ui.h:12
msgid "Keyboard shortcut to reveal and hold the panel"
@@ -627,9 +615,8 @@ msgid "Toggle single / Preview multiple"
msgstr "Commuta finestra singola e mostra anteprime"
#: ui/BoxMiddleClickOptions.ui.h:9 ui/SettingsAction.ui.h:6
#, fuzzy
msgid "Toggle single / Cycle multiple"
msgstr "Commuta finestra singola e mostra anteprime"
msgstr "Attiva singolo / Ciclo multiplo"
#: ui/BoxMiddleClickOptions.ui.h:11
msgid "Middle-Click action"
@@ -757,9 +744,8 @@ msgid "<i>Show Details</i> menu item"
msgstr "Visualizza <i>Mostra Dettagli</i>"
#: ui/BoxShowApplicationsOptions.ui.h:1
#, fuzzy
msgid "Show Applications icon"
msgstr "Opzioni Mostra Applicazioni"
msgstr "Mostra l'icona Applicazioni"
#: ui/BoxShowApplicationsOptions.ui.h:2
msgid "Show Applications icon side padding (px)"
@@ -772,7 +758,7 @@ msgstr ""
#: ui/BoxShowDesktopOptions.ui.h:1
msgid "Override Show Desktop line color"
msgstr ""
msgstr "Sostituisci Mostra colore linea desktop"
#: ui/BoxShowDesktopOptions.ui.h:2
msgid "Reveal the desktop when hovering the Show Desktop button"
@@ -788,23 +774,21 @@ msgid "Fade duration (ms)"
msgstr "Durata dissolvenza (ms)"
#: ui/BoxWindowPreviewOptions.ui.h:1
#, fuzzy
msgid "Time (ms) before showing"
msgstr ""
"Tempo (ms) prima della visualizzazione (400 è l'impostazione predefinita)"
"Tempo (ms) prima della visualizzazione"
#: ui/BoxWindowPreviewOptions.ui.h:2
msgid "(400 is default)"
msgstr ""
msgstr "(400 è predefinita)"
#: ui/BoxWindowPreviewOptions.ui.h:3
#, fuzzy
msgid "Time (ms) before hiding"
msgstr "Tempo (ms) prima di nascondersi (100 è l'impostazione predefinita)"
msgstr "Tempo (ms) prima di nascondersi"
#: ui/BoxWindowPreviewOptions.ui.h:4
msgid "(100 is default)"
msgstr ""
msgstr "(100 è predefinito)"
#: ui/BoxWindowPreviewOptions.ui.h:5
msgid "Immediate on application icon click"
@@ -927,11 +911,10 @@ msgid "Use custom opacity for the previews background"
msgstr "Usa l'opacità personalizzata per lo sfondo delle anteprime"
#: ui/BoxWindowPreviewOptions.ui.h:35
#, fuzzy
msgid ""
"If disabled, the previews background have the same opacity as the panel."
msgstr ""
"Se disabilitato, lo sfondo delle anteprime ha la stessa opacità del pannello"
"Se disabilitato, lo sfondo delle anteprime avrà la stessa opacità del pannello."
#: ui/BoxWindowPreviewOptions.ui.h:36
msgid "Close button and header position"
@@ -942,15 +925,12 @@ msgid "Display window preview headers"
msgstr "Visualizza le intestazioni di anteprima della finestra"
#: ui/BoxWindowPreviewOptions.ui.h:40
#, fuzzy
msgid "Icon size (px) of the window preview"
msgstr "Dimensione carattere (px) dei titoli di anteprima"
msgstr "Dimensioni dell'icona (px) dell'anteprima della finestra"
#: ui/BoxWindowPreviewOptions.ui.h:41
#, fuzzy
msgid "If disabled, the previews icon size will be based on headerbar size"
msgstr ""
"Se disabilitato, lo sfondo delle anteprime ha la stessa opacità del pannello"
msgstr "Se disabilitato, la dimensione dell'icona delle anteprime sarà basata sulla dimensione della barra di intestazione"
#: ui/BoxWindowPreviewOptions.ui.h:42
msgid "Font size (px) of the preview titles"
@@ -1003,25 +983,23 @@ msgstr ""
#: ui/SettingsAbout.ui.h:1
msgid "Info"
msgstr ""
msgstr "Informazioni"
#: ui/SettingsAbout.ui.h:2
#, fuzzy
msgid "Version"
msgstr "versione: "
msgstr "versione"
#: ui/SettingsAbout.ui.h:3
msgid "Source"
msgstr ""
msgstr "Sorgente"
#: ui/SettingsAbout.ui.h:4
msgid "GitHub"
msgstr "GitHub"
#: ui/SettingsAbout.ui.h:5
#, fuzzy
msgid "Export and Import"
msgstr "Esporta e importa impostazioni"
msgstr "Esporta e importa"
#: ui/SettingsAbout.ui.h:6
msgid "Export and import settings"
@@ -1067,9 +1045,8 @@ msgid "Toggle windows"
msgstr "Commuta le finestre"
#: ui/SettingsAction.ui.h:10
#, fuzzy
msgid "Scroll action"
msgstr "Azione scorrimento icona"
msgstr "Azione di scorrimento"
#: ui/SettingsAction.ui.h:11
msgid "Scroll panel action"
@@ -1109,9 +1086,8 @@ msgid "Same as panel"
msgstr "Stesso del pannello"
#: ui/SettingsAction.ui.h:20
#, fuzzy
msgid "Hotkey overlay"
msgstr "Sovrimpressione numero"
msgstr "Sovrapposizione tasti di scelta rapida"
#: ui/SettingsAction.ui.h:21
msgid "Use hotkeys to activate apps"
@@ -1126,9 +1102,8 @@ msgstr ""
"assieme a Shift e Ctrl."
#: ui/SettingsBehavior.ui.h:1
#, fuzzy
msgid "Applications"
msgstr "Non raggruppare applicazioni"
msgstr "Applicazioni"
#: ui/SettingsBehavior.ui.h:2
msgid "Show favorite applications"
@@ -1152,7 +1127,7 @@ msgstr "Non raggruppare applicazioni"
#: ui/SettingsBehavior.ui.h:7
msgid "Show notification counter badge"
msgstr ""
msgstr "Mostra il badge del contatore delle notifiche"
#: ui/SettingsBehavior.ui.h:8
msgid "Show window previews on hover"
@@ -1163,9 +1138,8 @@ msgid "Show tooltip on hover"
msgstr "Mostra suggerimento al passaggio"
#: ui/SettingsBehavior.ui.h:10
#, fuzzy
msgid "Isolate"
msgstr "Isola monitor"
msgstr "Isola"
#: ui/SettingsBehavior.ui.h:11
msgid "Isolate Workspaces"
@@ -1177,70 +1151,55 @@ msgstr "Isola monitor"
#: ui/SettingsBehavior.ui.h:13
msgid "Overview"
msgstr ""
msgstr "Panoramica"
#: ui/SettingsBehavior.ui.h:14
msgid "Click empty space to close overview"
msgstr ""
msgstr "Fare clic su uno spazio vuoto per chiudere la panoramica"
#: ui/SettingsBehavior.ui.h:15
msgid "Disable show overview on startup"
msgstr ""
msgstr "Disabilita mostra panoramica all'avvio"
#: ui/SettingsFineTune.ui.h:1
msgid "Font size"
msgstr ""
msgstr "Dimensione del font"
#: ui/SettingsFineTune.ui.h:2
msgid "Tray Font Size"
msgstr ""
msgstr "Dimensione font Tray"
#: ui/SettingsFineTune.ui.h:3
#, fuzzy
msgid "(0 = theme default)"
msgstr ""
"Dimens. Font Tray\n"
"(0 = predefinito)"
msgstr "(0 = tema predefinito)"
#: ui/SettingsFineTune.ui.h:4
#, fuzzy
msgid "LeftBox Font Size"
msgstr ""
"Dimens. Font LeftBox\n"
"(0 = predefinito)"
msgstr "Dimensione font casella sinistra"
#: ui/SettingsFineTune.ui.h:5
msgid "Padding"
msgstr ""
msgstr "Imbottitura"
#: ui/SettingsFineTune.ui.h:6
#, fuzzy
msgid "Tray Item Padding"
msgstr ""
"Spaziatura Icone Tray\n"
"(-1 = predefinito)"
msgstr "Imbottitura degli elementi della tray"
#: ui/SettingsFineTune.ui.h:7
#, fuzzy
msgid "(-1 = theme default)"
msgstr ""
"Spaziatura LeftBox\n"
"(-1 = predefinito)"
msgstr "(-1 = tema predefinito)"
#: ui/SettingsFineTune.ui.h:8
#, fuzzy
msgid "Status Icon Padding"
msgstr ""
"Spaziatura icone stato\n"
"(-1 = predefinito)"
msgstr "Imbottitura icona di stato"
#: ui/SettingsFineTune.ui.h:9
msgid "LeftBox Padding"
msgstr ""
msgstr "Imbottitura della casella sinistra"
#: ui/SettingsFineTune.ui.h:10
msgid "Animate"
msgstr ""
msgstr "Animato"
#: ui/SettingsFineTune.ui.h:11
msgid "Animate switching applications"
@@ -1252,49 +1211,43 @@ msgstr "Animazione apertura nuove finestre"
#: ui/SettingsFineTune.ui.h:13
msgid "Gnome functionality"
msgstr ""
msgstr "Funzionalità Gnome"
#: ui/SettingsFineTune.ui.h:14
#, fuzzy
msgid "Keep original gnome-shell dash"
msgstr "Mantieni dash originale di gnome-shell (schermata panoramica)"
msgstr "Mantieni dash originale di gnome-shell"
#: ui/SettingsFineTune.ui.h:15
msgid "(overview)"
msgstr ""
msgstr "(panoramica)"
#: ui/SettingsFineTune.ui.h:16
msgid "Keep original gnome-shell top panel"
msgstr "Mantieni il pannello superiore della gnome-shell originale"
#: ui/SettingsFineTune.ui.h:17
#, fuzzy
msgid "Activate panel menu buttons on click only"
msgstr ""
"Attiva i pulsanti del menu del pannello (ad es. Menu della data) solo al clic"
msgstr "Attiva i pulsanti del menu del pannello solo con un clic"
#: ui/SettingsFineTune.ui.h:18
#, fuzzy
msgid "(e.g. date menu)"
msgstr "Data e ora"
msgstr "(es. menu data)"
#: ui/SettingsFineTune.ui.h:19
msgid "Force Activities hot corner on primary monitor"
msgstr "Forza angolo attivo delle attività sul monitor principale"
#: ui/SettingsFineTune.ui.h:20
#, fuzzy
msgid "App icon secondary menu"
msgstr "Menu secondario (clic destro) delle icone"
msgstr "Menu secondario dell'icona dell'app"
#: ui/SettingsFineTune.ui.h:21
#, fuzzy
msgid "(right-click menu)"
msgstr "Menu secondario (clic destro) delle icone"
msgstr "(menù cliccabile con il tasto destro)"
#: ui/SettingsPosition.ui.h:1
msgid "Panel"
msgstr ""
msgstr "Pannello"
#: ui/SettingsPosition.ui.h:2
msgid "Display the main panel on"
@@ -1313,14 +1266,12 @@ msgid "Hide and reveal the panel according to preferences"
msgstr "Mostra e nascondi il pannello secondo le preferenze"
#: ui/SettingsPosition.ui.h:6
#, fuzzy
msgid "Order and Position on monitors"
msgstr "Ordinamento e posizione sullo schermo"
msgstr "Ordinamento e posizione sui monitor"
#: ui/SettingsPosition.ui.h:7
#, fuzzy
msgid "Monitor"
msgstr "Monitor "
msgstr "Monitor"
#: ui/SettingsPosition.ui.h:8
msgid "Apply changes to all monitors"
@@ -1331,79 +1282,57 @@ msgid "Panel screen position"
msgstr "Posizione pannello sullo schermo"
#: ui/SettingsPosition.ui.h:14
#, fuzzy
msgid "Panel thickness"
msgstr "Pannello Intellihide"
msgstr "Spessore del pannello"
#: ui/SettingsPosition.ui.h:15
#, fuzzy
msgid "(default is 48)"
msgstr ""
"Dimensione pannello\n"
"(predefinito 48)"
msgstr "(predefinito è 48)"
#: ui/SettingsPosition.ui.h:17
#, no-c-format
msgid "Panel length (%)"
msgstr ""
msgstr "Lunghezza del pannello (%)"
#: ui/SettingsPosition.ui.h:18
#, fuzzy
msgid "(default is 100)"
msgstr ""
"Dimensione pannello\n"
"(predefinito 48)"
msgstr "(predefinito è 100)"
#: ui/SettingsPosition.ui.h:19
msgid "Anchor"
msgstr ""
msgstr "Ancora"
#: ui/SettingsPosition.ui.h:23
#, fuzzy
msgid "Taskbar Display"
msgstr "Taskbar"
msgstr "Visualizzazione Taskbar"
#: ui/SettingsStyle.ui.h:1
msgid "AppIcon style"
msgstr ""
msgstr "Stile icona dell'app"
#: ui/SettingsStyle.ui.h:2
#, fuzzy
msgid "App Icon Margin"
msgstr ""
"Margine icone app\n"
"(predefinito 8)"
msgstr "Margine icona app"
#: ui/SettingsStyle.ui.h:3
#, fuzzy
msgid "(default is 8)"
msgstr ""
"Dimensione pannello\n"
"(predefinito 48)"
msgstr "(predefinito è 8)"
#: ui/SettingsStyle.ui.h:4
#, fuzzy
msgid "App Icon Padding"
msgstr ""
"Spaziatura icone app\n"
"(predefinito 4)"
msgstr "Imbottitura delle icone dell'app"
#: ui/SettingsStyle.ui.h:5
#, fuzzy
msgid "(default is 4)"
msgstr ""
"Dimensione pannello\n"
"(predefinito 48)"
msgstr "(predefinito è 4)"
#: ui/SettingsStyle.ui.h:6
#, fuzzy
msgid "Animate hovering app icons"
msgstr "Animazione passaggio tra applicazioni"
msgstr "Animazione passaggio tra le icone delle app"
#: ui/SettingsStyle.ui.h:7
#, fuzzy
msgid "Running indicator"
msgstr "Posizione indicatore di esecuzione"
msgstr "Indicatore di esecuzione"
#: ui/SettingsStyle.ui.h:8
msgid "Running indicator position"
@@ -1446,14 +1375,12 @@ msgid "Running indicator style (Unfocused apps)"
msgstr "Stile indicatore di esecuzione (app senza focus)"
#: ui/SettingsStyle.ui.h:22
#, fuzzy
msgid "Panel style"
msgstr "Pannello Intellihide"
msgstr "Stile del pannello"
#: ui/SettingsStyle.ui.h:23
#, fuzzy
msgid "Override panel theme background color"
msgstr "Ignora il colore di sfondo del pannello "
msgstr "Sostituisci il colore di sfondo del tema del pannello"
#: ui/SettingsStyle.ui.h:24
msgid "Override panel theme background opacity"
@@ -1473,9 +1400,8 @@ msgid "Change opacity when a window gets close to the panel"
msgstr "Cambia l'opacità quando una finestra è vicina al pannello"
#: ui/SettingsStyle.ui.h:30
#, fuzzy
msgid "Override panel theme gradient"
msgstr "Ignora gradiente del pannello "
msgstr "Sostituisci il gradiente del tema del pannello"
#: ui/SettingsStyle.ui.h:32
#, no-c-format
@@ -1502,9 +1428,6 @@ msgstr "Mostra le icone del Desktop"
msgid "Show Desktop button padding (px)"
msgstr "Spaziatura del pulsante Mostra Desktop (px)"
msgid "Floating rounded theme"
msgstr "Tema arrotondato fluttuante"
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Isola aree di lavoro e monitor nelle impostazioni di Cambio applicazione"
@@ -1607,7 +1530,7 @@ msgstr "Isola aree di lavoro e monitor nelle impostazioni di Cambio applicazione
#~ "about/\">Leggi di più</a>"
#~ msgid "About"
#~ msgstr "Informazioni su"
#~ msgstr "Informazioni"
#~ msgid "Top, with plugin icons collapsed to bottom"
#~ msgstr "In alto, con le icone dei plugin raggruppate in bassoa"

3973
po/ja.po

File diff suppressed because it is too large Load Diff

View File

@@ -15,6 +15,3 @@ msgstr "აჩვენე დესკტოპის იკონები"
msgid "Show Desktop button padding (px)"
msgstr "ღილაკი აჩვენე დესკტოპი"
msgid "Floating rounded theme"
msgstr "მოფარფატე მომრგვალო თემა"

View File

@@ -21,6 +21,3 @@ msgstr "ಡೆಸ್ಕ್ಟಾಪ್ ಐಕಾನ್ ತೋರಿಸಿ"
msgid "Show Desktop button padding (px)"
msgstr "ಡೆಸ್ಕ್ಟಾಪ್ ಬಟನ್ ತೋರಿಸು ಪ್ಯಾಡಿಂಗ್ (ಪಿಎಕ್ಸ್)"
msgid "Floating rounded theme"
msgstr "ತೇಲುವ ದುಂಡಾದ ಥೀಮ್"

View File

@@ -1469,9 +1469,6 @@ msgstr "바탕 화면 아이콘 표시"
msgid "Show Desktop button padding (px)"
msgstr "바탕 화면 버튼 표시 패딩(px)"
msgid "Floating rounded theme"
msgstr "떠 다니는 둥근 테마"
#~ msgid "Current Show Applications icon"
#~ msgstr "현재 프로그램 표시 아이콘"

View File

@@ -21,6 +21,3 @@ msgstr "Rodyti Darbalaukio ikoną"
msgid "Show Desktop button padding (px)"
msgstr "Rodyti Darbalaukio mygtuką"
msgid "Floating rounded theme"
msgstr "Plūduriuojanti apskrita tema"

View File

@@ -21,6 +21,3 @@ msgstr "Rādīt darbvirsmas ikonu"
msgid "Show Desktop button padding (px)"
msgstr "Rādīt darbvirsmas pogu polsterējums (px)"
msgid "Floating rounded theme"
msgstr "Peldoša noapaļota tēma"

View File

@@ -18,6 +18,3 @@ msgstr "Покажете ја иконата за работната површ
msgid "Show Desktop button padding (px)"
msgstr "Пополнување „Покажи копче за работна површина“ (px)"
msgid "Floating rounded theme"
msgstr "Лебдечка заоблена тема"

View File

@@ -21,6 +21,3 @@ msgstr "Tunjukkan ikon Atas Meja"
msgid "Show Desktop button padding (px)"
msgstr "Pemadatan Tunjuk butang Atas Meja (px)"
msgid "Floating rounded theme"
msgstr "Tema bundar terapung"

View File

@@ -21,6 +21,3 @@ msgstr "डेस्कटप प्रतिमा देखाउनुहो
msgid "Show Desktop button padding (px)"
msgstr "डेस्कटप बटन देखाउनुहोस् प्याडि ((px)"
msgid "Floating rounded theme"
msgstr "फ्लोटिंग गोल थिम"

View File

@@ -1502,9 +1502,6 @@ msgstr "Pictogram Bureaublad weergeven"
msgid "Show Desktop button padding (px)"
msgstr "Opvulling Pictogram bureaublad weergeven (px)"
msgid "Floating rounded theme"
msgstr "Zwevend afgerond thema"
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Isoleer werkruimten en monitoren in de instellingen voor het Wisselen tussen toepassingen"

View File

@@ -21,6 +21,3 @@ msgstr "ਡੈਸਕਟਾਪ ਆਈਕਾਨ ਵੇਖਾਓ"
msgid "Show Desktop button padding (px)"
msgstr "ਡੈਸਕਟਾਪ ਬਟਨ ਦਿਖਾਓ ਭਰਾਵ (px)"
msgid "Floating rounded theme"
msgstr "ਫਲੋਟਿੰਗ ਗੋਲ ਥੀਮ"

3979
po/pl.po

File diff suppressed because it is too large Load Diff

View File

@@ -22,8 +22,5 @@ msgstr "Mostrar ícone da Área de Trabalho"
msgid "Show Desktop button padding (px)"
msgstr "Preenchimento do botão Mostrar Área de Trabalho (px)"
msgid "Floating rounded theme"
msgstr "Tema arredondado flutuante"
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Isolar espaços de trabalho e monitores nas configurações de Comutação de aplicações"

View File

@@ -69,7 +69,7 @@ msgstr "Final"
#: prefs.js:413
msgid "Show Applications button"
msgstr "Mostrar botão de plicações"
msgstr "Mostrar botão de aplicações"
#: prefs.js:414
msgid "Activities button"
@@ -1136,12 +1136,12 @@ msgstr ""
#: ui/SettingsBehavior.ui.h:1
#, fuzzy
msgid "Applications"
msgstr "Mostrar botão de plicações"
msgstr "Mostrar botão de aplicações"
#: ui/SettingsBehavior.ui.h:2
#, fuzzy
msgid "Show favorite applications"
msgstr "Mostrar botão de plicações"
msgstr "Mostrar botão de aplicações"
#: ui/SettingsBehavior.ui.h:3
msgid "Show favorite applications on secondary panels"
@@ -1150,7 +1150,7 @@ msgstr ""
#: ui/SettingsBehavior.ui.h:4
#, fuzzy
msgid "Show running applications"
msgstr "Mostrar botão de plicações"
msgstr "Mostrar botão de aplicações"
#: ui/SettingsBehavior.ui.h:5
msgid "Show <i>AppMenu</i> button"
@@ -1513,9 +1513,6 @@ msgstr "Mostrar ícone da Área de Trabalho"
msgid "Show Desktop button padding (px)"
msgstr "Preenchimento do botão Mostrar Área de Trabalho (px)"
msgid "Floating rounded theme"
msgstr "Tema arredondado flutuante"
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Isolar espaços de trabalho e monitores nas configurações de Comutação de aplicações"

1078
po/ru.po

File diff suppressed because it is too large Load Diff

253
po/sk.po
View File

@@ -2,29 +2,30 @@
# Copyright (C) 2018
# This file is distributed under the same license as the dash-to-panel package.
# Jose Riha <jose1711 gmail com>, 2021.
# Jozef Gaal <preklady@mayday.sk>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-02-08 08:31-0500\n"
"PO-Revision-Date: 2021-08-05 14:16+0200\n"
"Last-Translator: Jose Riha <jose1711@gmail.com>\n"
"Language-Team: \n"
"PO-Revision-Date: 2024-12-07 02:10+0100\n"
"Last-Translator: Jozef Gaal <preklady@mayday.sk>\n"
"Language-Team: Jozef Gaal <preklady@mayday.sk>\n"
"Language: sk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.0\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n>=2 && n<=4 ? 1 : 2);\n"
"X-Generator: Poedit 3.4.2\n"
#: prefs.js:247
msgid "Show Desktop button height (px)"
msgstr "Výška tlačidla plochy (px)"
msgstr "Výška tlačidla zobrazenia plochy (px)"
#: prefs.js:247
msgid "Show Desktop button width (px)"
msgstr "Šírka tlačidla plochy (px)"
msgstr "Šírka tlačidla zobrazenia plochy (px)"
#: prefs.js:259
msgid "Unavailable when gnome-shell top panel is present"
@@ -78,11 +79,11 @@ msgstr "Zoznam úloh"
#: prefs.js:416
msgid "Date menu"
msgstr "Menu hodín"
msgstr "Ponuka dátumu"
#: prefs.js:417
msgid "System menu"
msgstr "Systémové menu"
msgstr "Ponuka systému"
#: prefs.js:418
msgid "Left box"
@@ -118,19 +119,19 @@ msgstr "Vyberte umiestnenie prvku"
#: prefs.js:443
msgid "Stacked to top"
msgstr "Zvrchu"
msgstr "Hore"
#: prefs.js:443
msgid "Stacked to left"
msgstr "Zľava"
msgstr "Vľavo"
#: prefs.js:444
msgid "Stacked to bottom"
msgstr "Zdola"
msgstr "Dole"
#: prefs.js:444
msgid "Stacked to right"
msgstr "Sprava"
msgstr "Vpravo"
#: prefs.js:445
msgid "Centered"
@@ -158,7 +159,7 @@ msgstr "Otvoriť ikonu"
#: prefs.js:577
msgid "Show Desktop options"
msgstr "Nastavenia plochy"
msgstr "Nastavenia tlačidla zobrazenia plochy"
#: prefs.js:661
#, javascript-format
@@ -168,7 +169,7 @@ msgstr "%d ms"
#: prefs.js:666
#, javascript-format
msgid "%d °"
msgstr ""
msgstr "%d °"
#: prefs.js:671 prefs.js:676
#, javascript-format
@@ -190,7 +191,7 @@ msgstr[2] "%d ikon"
#: prefs.js:782
msgid "Running Indicator Options"
msgstr "Možnosti indikátora bežiacich aplikácií"
msgstr "Možnosti indikátora činnosti"
#: prefs.js:928
msgid "Primary monitor"
@@ -234,7 +235,7 @@ msgstr "Nastavenie ďalších klávesových skratiek"
#: prefs.js:1898
msgid "Secondary Menu Options"
msgstr "Nastavenie sekundárneho menu"
msgstr "Možnosti sekundárnej ponuky"
#: prefs.js:1924 ui/SettingsFineTune.ui.h:22
msgid "Advanced Options"
@@ -327,7 +328,7 @@ msgstr "Zatiaľ nedostupné!"
#: ui/BoxAdvancedOptions.ui.h:2
msgid "For real..."
msgstr ""
msgstr "Naozaj..."
#: ui/BoxAnimateAppIconHoverOptions.ui.h:1
msgid "Animation type"
@@ -343,7 +344,7 @@ msgstr "Vlnenie"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:4
msgid "Plank"
msgstr "Prekrytie"
msgstr "Doska"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:5
msgid "Duration"
@@ -351,7 +352,7 @@ msgstr "Trvanie"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:6
msgid "Rotation"
msgstr "Otočenie"
msgstr "Otáčanie"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:7
msgid "Travel"
@@ -363,11 +364,11 @@ msgstr "Priblíženie"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:9
msgid "Convexity"
msgstr "Vypuklina"
msgstr "Vypuklosť"
#: ui/BoxAnimateAppIconHoverOptions.ui.h:10
msgid "Extent"
msgstr "Rozšírenie"
msgstr "Rozsah"
#: ui/BoxDotOptions.ui.h:1
msgid "Highlight focused application"
@@ -453,7 +454,7 @@ msgstr "0"
#: ui/BoxDynamicOpacityOptions.ui.h:9
msgid "Opacity change animation duration (ms)"
msgstr "Rýchlosť animácie zobrazenia/skrytia panela"
msgstr "Dĺžka animácie zmeny priehľadnosti (ms)"
#: ui/BoxGroupAppsOptions.ui.h:1
msgid "Font size (px) of the application titles (default is 14)"
@@ -492,16 +493,12 @@ msgid "Font color of the minimized application titles"
msgstr "Farba písma názvu minimalizovanej aplikácie"
#: ui/BoxGroupAppsOptions.ui.h:10
#, fuzzy
msgid "Maximum width (px) of the application titles"
msgstr "Maximálna šírka (px) pre názov aplikácie (predvolená: 160)"
msgstr "Maximálna šírka (px) pre názov aplikácie"
#: ui/BoxGroupAppsOptions.ui.h:11
#, fuzzy
msgid "(default is 160)"
msgstr ""
"Dĺžka panela (%)\n"
"(predvolená: 100)"
msgstr "(predvolená je 160)"
#: ui/BoxGroupAppsOptions.ui.h:12
msgid "Use a fixed width for the application titles"
@@ -525,9 +522,8 @@ msgid "Use the favorite icons as application launchers"
msgstr "Použiť ikony obľúbených aplikácií ako spúšťače"
#: ui/BoxIntellihideOptions.ui.h:1
#, fuzzy
msgid "Only hide the panel when it is obstructed by windows"
msgstr "Skryť panel iba pri prekrytí oknami aplikácií "
msgstr "Skryť panel len vtedy, keď je prekrytý oknami"
#: ui/BoxIntellihideOptions.ui.h:2
msgid "The panel hides from"
@@ -550,14 +546,12 @@ msgid "Allow the panel to be revealed while in fullscreen mode"
msgstr "Povoliť zobrazenie panela v režime celej obrazovky"
#: ui/BoxIntellihideOptions.ui.h:10
#, fuzzy
msgid "Only hide secondary panels"
msgstr "Skryť iba sekundárne panely (pre viac monitorov)"
msgstr "Skryť iba sekundárne panely"
#: ui/BoxIntellihideOptions.ui.h:11
#, fuzzy
msgid "(requires multi-monitors option)"
msgstr "Skryť iba sekundárne panely (pre viac monitorov)"
msgstr "(vyžaduje možnosť viacerých monitorov)"
#: ui/BoxIntellihideOptions.ui.h:12
msgid "Keyboard shortcut to reveal and hold the panel"
@@ -585,7 +579,7 @@ msgstr "Oneskorenie pred skrytím pri štarte (ms)"
#: ui/BoxMiddleClickOptions.ui.h:1
msgid "Shift+Click action"
msgstr "Akcia pri Shift+Click"
msgstr "Akcia pri Shift+Kliknutie"
#: ui/BoxMiddleClickOptions.ui.h:2
msgid ""
@@ -640,7 +634,7 @@ msgstr "Shift + prostredné tlačidlo myši."
#: ui/BoxOverlayShortcut.ui.h:1
msgid "Hotkeys prefix"
msgstr "Skratka"
msgstr "Predpona klávesových skratiek"
#: ui/BoxOverlayShortcut.ui.h:2
msgid "Hotkeys will either be Super+Number or Super+Alt+Num"
@@ -686,7 +680,7 @@ msgstr "Skratka pre zobrazenie prehľadu na 2 sekundy"
#: ui/BoxOverlayShortcut.ui.h:13
msgid "e.g. <Super>q"
msgstr "napr: <Super>q"
msgstr "napr. <Super>q"
#: ui/BoxOverlayShortcut.ui.h:14
msgid "Show window previews on hotkey"
@@ -735,16 +729,15 @@ msgstr ""
#: ui/BoxSecondaryMenuOptions.ui.h:1
msgid "Integrate <i>AppMenu</i> items"
msgstr "Zobraziť položky menu <i>aplikácie</i>"
msgstr "Integrovať položky <i>ponuky aplikácií</i>"
#: ui/BoxSecondaryMenuOptions.ui.h:2
msgid "<i>Show Details</i> menu item"
msgstr "Zobraziť menu <i>Detail</i>"
msgstr "Položka ponuky <i>Zobraziť podrobnosti</i>"
#: ui/BoxShowApplicationsOptions.ui.h:1
#, fuzzy
msgid "Show Applications icon"
msgstr "Zobraziť ikonu <i>aplikácií</i>"
msgstr "Zobraziť ikonu aplikácií"
#: ui/BoxShowApplicationsOptions.ui.h:2
msgid "Show Applications icon side padding (px)"
@@ -756,7 +749,7 @@ msgstr "Zmeniť správanie klávesu Esc a vrátiť sa na plochu"
#: ui/BoxShowDesktopOptions.ui.h:1
msgid "Override Show Desktop line color"
msgstr "Vlastná farba deliacej čiary plochy"
msgstr "Prepísať farbu čiary tlačidla zobrazenia plochy"
#: ui/BoxShowDesktopOptions.ui.h:2
msgid "Reveal the desktop when hovering the Show Desktop button"
@@ -771,22 +764,20 @@ msgid "Fade duration (ms)"
msgstr "Skryť po (ms)"
#: ui/BoxWindowPreviewOptions.ui.h:1
#, fuzzy
msgid "Time (ms) before showing"
msgstr "Pauza (ms) pred zobrazením náhľadu (predvolená: 400)"
msgstr "Čas (ms) pred zobrazením"
#: ui/BoxWindowPreviewOptions.ui.h:2
msgid "(400 is default)"
msgstr ""
msgstr "(400 is predvolené)"
#: ui/BoxWindowPreviewOptions.ui.h:3
#, fuzzy
msgid "Time (ms) before hiding"
msgstr "Pauza (ms) pred skrytím náhľadu (predvolená: 100)"
msgstr "Čas (ms) pred skrytím"
#: ui/BoxWindowPreviewOptions.ui.h:4
msgid "(100 is default)"
msgstr ""
msgstr "(100 is predvolené)"
#: ui/BoxWindowPreviewOptions.ui.h:5
msgid "Immediate on application icon click"
@@ -909,10 +900,10 @@ msgid "Use custom opacity for the previews background"
msgstr "Použiť vlastné nastavenie priehľadnosti náhľadov"
#: ui/BoxWindowPreviewOptions.ui.h:35
#, fuzzy
msgid ""
"If disabled, the previews background have the same opacity as the panel."
msgstr "Pri vypnutí sa použije hodnota priehľadnosti panela"
msgstr ""
"Ak je vypnuté, pozadie náhľadov bude mať rovnakú nepriehľadnosť ako panel."
#: ui/BoxWindowPreviewOptions.ui.h:36
msgid "Close button and header position"
@@ -979,25 +970,23 @@ msgstr "Všetky okna, okrem aktívneho, majú rovnaké nastavenie priehľadnosti
#: ui/SettingsAbout.ui.h:1
msgid "Info"
msgstr ""
msgstr "Informácie"
#: ui/SettingsAbout.ui.h:2
#, fuzzy
msgid "Version"
msgstr "verzia: "
msgstr "Verzia"
#: ui/SettingsAbout.ui.h:3
msgid "Source"
msgstr ""
msgstr "Zdroj"
#: ui/SettingsAbout.ui.h:4
msgid "GitHub"
msgstr "GitHub"
#: ui/SettingsAbout.ui.h:5
#, fuzzy
msgid "Export and Import"
msgstr "Export a import nastavení"
msgstr "Export a import"
#: ui/SettingsAbout.ui.h:6
msgid "Export and import settings"
@@ -1042,13 +1031,12 @@ msgid "Toggle windows"
msgstr "Prepínanie okien"
#: ui/SettingsAction.ui.h:10
#, fuzzy
msgid "Scroll action"
msgstr "Akcia kolieska myši"
#: ui/SettingsAction.ui.h:11
msgid "Scroll panel action"
msgstr "Akcia panelu pri skrolovaní"
msgstr "Akcia kolieska myši na paneli"
#: ui/SettingsAction.ui.h:12
msgid "Behavior when mouse scrolling over the panel."
@@ -1072,7 +1060,7 @@ msgstr "Upraviť hlasitosť"
#: ui/SettingsAction.ui.h:17
msgid "Scroll icon action"
msgstr "Akcia kolieska myši"
msgstr "Akcia kolieska myši na ikone"
#: ui/SettingsAction.ui.h:18
msgid "Behavior when mouse scrolling over an application icon."
@@ -1083,9 +1071,8 @@ msgid "Same as panel"
msgstr "Rovnaké ako panel"
#: ui/SettingsAction.ui.h:20
#, fuzzy
msgid "Hotkey overlay"
msgstr "Zobraziť číslo"
msgstr "Klávesové skratky"
#: ui/SettingsAction.ui.h:21
msgid "Use hotkeys to activate apps"
@@ -1100,9 +1087,8 @@ msgstr ""
"použiť v kombinácií s Shift a Ctrl."
#: ui/SettingsBehavior.ui.h:1
#, fuzzy
msgid "Applications"
msgstr "Nezoskupené aplikácie"
msgstr "Aplikácie"
#: ui/SettingsBehavior.ui.h:2
msgid "Show favorite applications"
@@ -1118,7 +1104,7 @@ msgstr "Zobraziť bežiace aplikácie"
#: ui/SettingsBehavior.ui.h:5
msgid "Show <i>AppMenu</i> button"
msgstr "Zobraziť tlačidlo aplikácií"
msgstr "Zobraziť tlačidlo <i>ponuky aplikácií</i>"
#: ui/SettingsBehavior.ui.h:6
msgid "Ungroup applications"
@@ -1126,7 +1112,7 @@ msgstr "Nezoskupené aplikácie"
#: ui/SettingsBehavior.ui.h:7
msgid "Show notification counter badge"
msgstr ""
msgstr "Zobraziť znak počítadla oznámení"
#: ui/SettingsBehavior.ui.h:8
msgid "Show window previews on hover"
@@ -1137,9 +1123,8 @@ msgid "Show tooltip on hover"
msgstr "Zobraziť tip okna pri podržaní myši"
#: ui/SettingsBehavior.ui.h:10
#, fuzzy
msgid "Isolate"
msgstr "Oddeliť monitory"
msgstr "Oddeliť"
#: ui/SettingsBehavior.ui.h:11
msgid "Isolate Workspaces"
@@ -1151,7 +1136,7 @@ msgstr "Oddeliť monitory"
#: ui/SettingsBehavior.ui.h:13
msgid "Overview"
msgstr ""
msgstr "Prehľad"
#: ui/SettingsBehavior.ui.h:14
msgid "Click empty space to close overview"
@@ -1163,59 +1148,43 @@ msgstr "Vypnúť zobrazenie prehľadu po štarte"
#: ui/SettingsFineTune.ui.h:1
msgid "Font size"
msgstr ""
msgstr "Veľkosť písma"
#: ui/SettingsFineTune.ui.h:2
msgid "Tray Font Size"
msgstr ""
msgstr "Veľkosť písma systémového bloku"
#: ui/SettingsFineTune.ui.h:3
#, fuzzy
msgid "(0 = theme default)"
msgstr ""
"Veľkosť písma stavovej oblasti\n"
"(0 = určená motívom)"
msgstr "(0 = predvolené témou)"
#: ui/SettingsFineTune.ui.h:4
#, fuzzy
msgid "LeftBox Font Size"
msgstr ""
"Veľkosť písma ľavého bloku\n"
"(0 = určená motívom)"
msgstr "Veľkosť písma ľavého bloku"
#: ui/SettingsFineTune.ui.h:5
msgid "Padding"
msgstr ""
msgstr "Odsadenie"
#: ui/SettingsFineTune.ui.h:6
#, fuzzy
msgid "Tray Item Padding"
msgstr ""
"Odsadenie položiek v systémovej oblasti\n"
"(-1 = určené motívom)"
msgstr "Odsadenie položky v systémovom bloku"
#: ui/SettingsFineTune.ui.h:7
#, fuzzy
msgid "(-1 = theme default)"
msgstr ""
"Odsadenie v ľavom bloku\n"
"(-1 = určené motívom)"
msgstr "(-1 = predvolené témou)"
#: ui/SettingsFineTune.ui.h:8
#, fuzzy
msgid "Status Icon Padding"
msgstr ""
"Odsadenie medzi stavovými ikonami\n"
"(-1 = určené motívom)"
msgstr "Odsadenie stavových ikon"
#: ui/SettingsFineTune.ui.h:9
msgid "LeftBox Padding"
msgstr ""
msgstr "Odsadenie ľavého bloku"
#: ui/SettingsFineTune.ui.h:10
#, fuzzy
msgid "Animate"
msgstr "Typ animácie"
msgstr "Animovať"
#: ui/SettingsFineTune.ui.h:11
msgid "Animate switching applications"
@@ -1227,48 +1196,43 @@ msgstr "Animovať vytváranie nových okien"
#: ui/SettingsFineTune.ui.h:13
msgid "Gnome functionality"
msgstr ""
msgstr "Funkcionalita Gnome"
#: ui/SettingsFineTune.ui.h:14
#, fuzzy
msgid "Keep original gnome-shell dash"
msgstr "Ponechať pôvodný 'gnome-shell dash' (prehľad úloh)"
msgstr "Ponechať pôvodný gnome-shell dash"
#: ui/SettingsFineTune.ui.h:15
msgid "(overview)"
msgstr ""
msgstr "(prehľad)"
#: ui/SettingsFineTune.ui.h:16
msgid "Keep original gnome-shell top panel"
msgstr "Ponechať pôvodný horný panel gnome-shell"
#: ui/SettingsFineTune.ui.h:17
#, fuzzy
msgid "Activate panel menu buttons on click only"
msgstr "Aktivovať tlačidlá na paneli iba po stlačení (napr. menu hodín)"
msgstr "Aktivovať tlačidlá ponuky na paneli iba pri kliknutí"
#: ui/SettingsFineTune.ui.h:18
#, fuzzy
msgid "(e.g. date menu)"
msgstr "Menu hodín"
msgstr "(napr. ponuka s dátumom)"
#: ui/SettingsFineTune.ui.h:19
msgid "Force Activities hot corner on primary monitor"
msgstr "Vynútiť aktívny roh na primárnom monitore"
#: ui/SettingsFineTune.ui.h:20
#, fuzzy
msgid "App icon secondary menu"
msgstr "Nastavenie pravého kliknutia na ikonu aplikácie"
msgstr "Sekundárna ponuka ikony aplikácie"
#: ui/SettingsFineTune.ui.h:21
#, fuzzy
msgid "(right-click menu)"
msgstr "Nastavenie pravého kliknutia na ikonu aplikácie"
msgstr "(ponuka pravého tlačidla myši)"
#: ui/SettingsPosition.ui.h:1
msgid "Panel"
msgstr ""
msgstr "Panel"
#: ui/SettingsPosition.ui.h:2
msgid "Display the main panel on"
@@ -1287,14 +1251,12 @@ msgid "Hide and reveal the panel according to preferences"
msgstr "Zobraziť/skryť panel podľa nastavení"
#: ui/SettingsPosition.ui.h:6
#, fuzzy
msgid "Order and Position on monitors"
msgstr "Poradie a pozícia na monitore"
msgstr "Poradie a pozícia na monitoroch"
#: ui/SettingsPosition.ui.h:7
#, fuzzy
msgid "Monitor"
msgstr "Monitor "
msgstr "Monitor"
#: ui/SettingsPosition.ui.h:8
msgid "Apply changes to all monitors"
@@ -1305,90 +1267,65 @@ msgid "Panel screen position"
msgstr "Pozícia panela na obrazovke"
#: ui/SettingsPosition.ui.h:14
#, fuzzy
msgid "Panel thickness"
msgstr ""
"Šírka panela\n"
"(predvolená: 48)"
msgstr "Šírka panela"
#: ui/SettingsPosition.ui.h:15
#, fuzzy
msgid "(default is 48)"
msgstr ""
"Šírka panela\n"
"(predvolená: 48)"
msgstr "(predvolená je 48)"
#: ui/SettingsPosition.ui.h:17
#, fuzzy, no-c-format
#, no-c-format
msgid "Panel length (%)"
msgstr ""
"Dĺžka panela (%)\n"
"(predvolená: 100)"
msgstr "Dĺžka panela (%)"
#: ui/SettingsPosition.ui.h:18
#, fuzzy
msgid "(default is 100)"
msgstr ""
"Dĺžka panela (%)\n"
"(predvolená: 100)"
msgstr "(predvolená je 100)"
#: ui/SettingsPosition.ui.h:19
msgid "Anchor"
msgstr "Ukotvenie"
#: ui/SettingsPosition.ui.h:23
#, fuzzy
msgid "Taskbar Display"
msgstr "Zoznam úloh"
msgstr "Zobrazenie panela úloh"
#: ui/SettingsStyle.ui.h:1
msgid "AppIcon style"
msgstr ""
msgstr "Štýl ikony aplikácií"
#: ui/SettingsStyle.ui.h:2
#, fuzzy
msgid "App Icon Margin"
msgstr ""
"Rozostup ikon aplikácií\n"
"(predvolený: 8)"
msgstr "Rozostup ikon aplikácií"
#: ui/SettingsStyle.ui.h:3
#, fuzzy
msgid "(default is 8)"
msgstr ""
"Rozostup ikon aplikácií\n"
"(predvolený: 8)"
msgstr "(predvolené je 8)"
#: ui/SettingsStyle.ui.h:4
#, fuzzy
msgid "App Icon Padding"
msgstr ""
"Odsadenie ikon aplikácií\n"
"(predvolené: 4)"
msgstr "Odsadenie ikon aplikácií"
#: ui/SettingsStyle.ui.h:5
#, fuzzy
msgid "(default is 4)"
msgstr ""
"Odsadenie ikon aplikácií\n"
"(predvolené: 4)"
msgstr "(predvolené je 4)"
#: ui/SettingsStyle.ui.h:6
msgid "Animate hovering app icons"
msgstr "Animovať prepínanie medzi ikonami aplikácií"
#: ui/SettingsStyle.ui.h:7
#, fuzzy
msgid "Running indicator"
msgstr "Pozícia indikátora"
msgstr "Indikátor činnosti"
#: ui/SettingsStyle.ui.h:8
msgid "Running indicator position"
msgstr "Pozícia indikátora"
msgstr "Pozícia indikátora činnosti"
#: ui/SettingsStyle.ui.h:13
msgid "Running indicator style (Focused app)"
msgstr "Štýl indikátora bežiacich aplikácií (na popredí)"
msgstr "Štýl indikátora bežiacich aplikácií (na popredí)činnosti"
#: ui/SettingsStyle.ui.h:14
msgid "Dots"
@@ -1404,7 +1341,7 @@ msgstr "Čiarky"
#: ui/SettingsStyle.ui.h:17
msgid "Segmented"
msgstr "Segmenty"
msgstr "Segmentované"
#: ui/SettingsStyle.ui.h:18
msgid "Solid"
@@ -1423,18 +1360,16 @@ msgid "Running indicator style (Unfocused apps)"
msgstr "Štýl indikátora bežiacich aplikácií (na pozadí)"
#: ui/SettingsStyle.ui.h:22
#, fuzzy
msgid "Panel style"
msgstr "Inteligentné skrývanie (Intellihide)"
msgstr "Štýl panelu"
#: ui/SettingsStyle.ui.h:23
#, fuzzy
msgid "Override panel theme background color"
msgstr "Vlastná farba pozadia panela (ignorovať motív) "
msgstr "Prepísať farbu pozadia témy panela"
#: ui/SettingsStyle.ui.h:24
msgid "Override panel theme background opacity"
msgstr "Vlastná priehľadnosť panela (ignorovať motív)"
msgstr "Prepísať nepriehľadnosť pozadia témy panela"
#: ui/SettingsStyle.ui.h:26
#, no-c-format
@@ -1450,9 +1385,8 @@ msgid "Change opacity when a window gets close to the panel"
msgstr "Zmeniť priehľadnosť pri priblížení okna"
#: ui/SettingsStyle.ui.h:30
#, fuzzy
msgid "Override panel theme gradient"
msgstr "Vlastné nastavenie farebného prechodu panela (ignorovať motív) "
msgstr "Prepísať gradient témy panela"
#: ui/SettingsStyle.ui.h:32
#, no-c-format
@@ -1470,9 +1404,6 @@ msgstr "Zobrať ikonu plochy"
msgid "Show Desktop button padding (px)"
msgstr "Zobraziť ikonu plochy výplň (px)"
msgid "Floating rounded theme"
msgstr "Zaoblený plávajúci motív"
#, javascript-format
#~ msgid "%d ."
#~ msgstr "%d ."

View File

@@ -21,6 +21,3 @@ msgstr "Pokaži ikono za namizje"
msgid "Show Desktop button padding (px)"
msgstr "Pokaži ikono za namizje razmik (px)"
msgid "Floating rounded theme"
msgstr "Plavajoča zaokrožena tema"

View File

@@ -15,6 +15,3 @@ msgstr "Shfaq ikonën e desktopit"
msgid "Show Desktop button padding (px)"
msgstr "Mbushja Shfaq butonin e desktopit (px)"
msgid "Floating rounded theme"
msgstr "Temë lundruese e rrumbullakosur"

View File

@@ -21,6 +21,3 @@ msgstr "Прикажи икону радне површине"
msgid "Show Desktop button padding (px)"
msgstr "Подлога „Прикажи дугме радне површине“ (пк)"
msgid "Floating rounded theme"
msgstr "Плутајућа заобљена тема"

View File

@@ -1504,9 +1504,6 @@ msgstr "Visa Skrivbordsikonen"
msgid "Show Desktop button padding (px)"
msgstr "Fyllnad (px) för knappen Visa Skrivbordet"
msgid "Floating rounded theme"
msgstr "Flytande rundat tema"
#~ msgid "Top, with plugin icons collapsed to bottom"
#~ msgstr "Topp, med tilläggsikoner kollapsade till botten"

View File

@@ -21,6 +21,3 @@ msgstr "டெஸ்க்டாப் ஐகானைக் காட்டு"
msgid "Show Desktop button padding (px)"
msgstr "டெஸ்க்டாப் பொத்தானைக் காட்டு திணிப்பு (px)"
msgid "Floating rounded theme"
msgstr "மிதக்கும் வட்டமான தீம்"

View File

@@ -21,6 +21,3 @@ msgstr "డెస్క్‌టాప్ చిహ్నాన్ని చూ
msgid "Show Desktop button padding (px)"
msgstr "డెస్క్‌టాప్ బటన్ చూపించు పాడింగ్ (px)"
msgid "Floating rounded theme"
msgstr "తేలియాడే గుండ్రని థీమ్"

View File

@@ -21,6 +21,3 @@ msgstr "แสดงไอคอนเดสก์ท็อป"
msgid "Show Desktop button padding (px)"
msgstr "ช่องว่างภายใน แสดงปุ่มเดสก์ท็อป (px)"
msgid "Floating rounded theme"
msgstr "ธีมกลมลอย"

1476
po/tr.po

File diff suppressed because it is too large Load Diff

1896
po/uk.po

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,3 @@ msgstr "Hiển thị biểu tượng Desktop"
msgid "Show Desktop button padding (px)"
msgstr "Phần đệm Show Desktop button (px)"
msgid "Floating rounded theme"
msgstr "Theme có dạng bo tròn nỗi"

View File

@@ -1441,9 +1441,6 @@ msgstr "显示桌面图标"
msgid "Show Desktop button padding (px)"
msgstr "“显示桌面按钮”的内边距(px)"
msgid "Floating rounded theme"
msgstr "悬浮圆角主题"
#, javascript-format
#~ msgid "%d ."
#~ msgstr "%d ."

View File

@@ -1498,9 +1498,6 @@ msgstr "顯示桌面圖示"
msgid "Show Desktop button padding (px)"
msgstr "顯示桌面按鈕 空間 (像素)"
msgid "Floating rounded theme"
msgstr "浮動圓滑主題"
#~ msgid "Show Details"
#~ msgstr "顯示詳細資訊"

1170
prefs.js

File diff suppressed because it is too large Load Diff

View File

@@ -1,598 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Dash to Panel extension
*/
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Gio = imports.gi.Gio;
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Pango = imports.gi.Pango;
const St = imports.gi.St;
const Signals = imports.signals;
const Utils = Me.imports.utils;
var ProgressManager = class {
constructor() {
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);
}
}
};
Signals.addSignalMethods(ProgressManager.prototype);
class AppProgress {
constructor(dbusName, appId, properties) {
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(Me.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(Me.settings.get_boolean('progress-show-bar') && other[property].get_boolean());
} else if (property == 'urgent') {
this.setUrgent(other[property].get_boolean());
} else {
// Not implemented yet
}
}
}
}
}
};
Signals.addSignalMethods(AppProgress.prototype);
var 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,
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.START,
x_expand: true, y_expand: true
});
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 Clutter.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 Clutter.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(1.0, 1.0, 1.0, 1.0, 0.1);
stroke.addColorStopRGBA(1.0, 1.0, 1.0, 1.0, 0.1);
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 = null;
fill = new Cairo.LinearGradient(0, y, 0, y + height);
fill.addColorStopRGBA(0.0, 0.0, 0.0, 0.0, 1.0);
fill.addColorStopRGBA(0.0, 0.0, 0.0, 0.0, 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;
}
}
};

View File

@@ -1,261 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
*/
const Meta = imports.gi.Meta;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Utils = Me.imports.utils;
//timeout intervals
const MIN_UPDATE_MS = 200;
//timeout names
const T1 = 'limitUpdateTimeout';
var Mode = {
ALL_WINDOWS: 0,
FOCUSED_WINDOWS: 1,
MAXIMIZED_WINDOWS: 2
};
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 Meta.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
});
}
};
var 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 &&
metaWindow.window_type != Meta.WindowType.DESKTOP &&
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)));
}
};

View File

@@ -18,6 +18,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.zorin-taskbar.scrollAction'>
<value value='0' nick='NOTHING'/>
@@ -71,7 +72,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">
@@ -99,11 +100,6 @@
<summary>Style of the running indicator (unfocused)</summary>
<description>Style of the running indicator for the icon for applications which are not currently focused</description>
</key>
<key type="b" name="dot-color-dominant">
<default>false</default>
<summary>Running indicator dominant color</summary>
<description>Whether to use the app icon's dominant color for .app-well-running-dot</description>
</key>
<key type="b" name="stockgs-keep-top-panel">
<default>false</default>
<summary>Keep top panel</summary>
@@ -119,6 +115,10 @@
<summary>Lock the taskbar</summary>
<description>Specifies if the user can modify the taskbar</description>
</key>
<key type="i" name="panel-margin">
<default>0</default>
<summary>Panel margin</summary>
</key>
<key type="b" name="trans-use-custom-opacity">
<default>false</default>
<summary>Custom background color</summary>
@@ -149,6 +149,26 @@
<summary>Modified panel opacity</summary>
<description>Modified opacity for the panel when a window is near</description>
</key>
<key type="b" name="trans-use-border">
<default>false</default>
<summary>Display border</summary>
<description>Display a border between panel and the rest of the desktop</description>
</key>
<key type="i" name="trans-border-width">
<default>1</default>
<summary>Width of panel border</summary>
<description>Customize the width of the panel border</description>
</key>
<key type="b" name="trans-border-use-custom-color">
<default>false</default>
<summary>Override panel border color</summary>
<description>Replace current panel border color</description>
</key>
<key type="s" name="trans-border-custom-color">
<default>"rgba(200,200,200,0.2)"</default>
<summary>Custom panel border color</summary>
<description>Custom panel border color</description>
</key>
<key type="b" name="intellihide">
<default>false</default>
<summary>Intellihide</summary>
@@ -156,24 +176,49 @@
</key>
<key type="b" name="intellihide-hide-from-windows">
<default>true</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.zorin-taskbar.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="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>
@@ -189,10 +234,9 @@
<summary>Keybinding toggle intellihide</summary>
<description>Keybinding to reveal the panel while in intellihide mode</description>
</key>
<key type="b" name="intellihide-floating-rounded-theme">
<default>true</default>
<summary>Floating rounded theme</summary>
<description>Display the panel with a floating rounded theme while in intellihide mode</description>
<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="as" name="panel-context-menu-commands">
<default>[]</default>
@@ -279,11 +323,6 @@
<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>
@@ -292,7 +331,7 @@
<key type="b" name="show-favorites-all-monitors">
<default>true</default>
<summary>Display the favorites on all monitors</summary>
<description>Specifies if every panel should display the favorite applications. If false, the favorite appplications are only displayed on the primary monitor.</description>
<description>Specifies if every panel should display the favorite applications. If false, the favorite applications are only displayed on the primary monitor.</description>
</key>
<key type="b" name="customize-click">
<default>true</default>
@@ -337,6 +376,10 @@
<summary>Middle click preview to close window</summary>
<description>Middle click on the window preview to close that window</description>
</key>
<key type="i" name="global-border-radius">
<default>0</default>
<summary>Border radius of panel elements</summary>
</key>
<key type="s" name="shortcut-text">
<default>"&lt;Super&gt;q"</default>
<summary>Keybinding to show the dock and the number overlay.</summary>
@@ -802,5 +845,9 @@
<summary>Show badge count on app icon</summary>
<description>Whether to show badge count overlay on app icon, for supported applications.</description>
</key>
<key type="s" name="target-prefs-page">
<default>''</default>
<summary>The preferences page name to display</summary>
</key>
</schema>
</schemalist>

2049
src/appIcons.js Normal file

File diff suppressed because it is too large Load Diff

View 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)
}
}

173
src/extension.js Normal file
View File

@@ -0,0 +1,173 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 ZORIN_DASH_UUID = 'zorin-dash@zorinos.com'
export const ZORIN_TILING_SHELL_UUID = 'zorin-tiling-shell@zorinos.com'
let panelManager
let zorinDashDelayId = 0
export let DTP_EXTENSION = null
export let SETTINGS = null
export let TILINGSETTINGS = null
export let SHELLSETTINGS = 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 ZorinTaskbarExtension extends Extension {
constructor(metadata) {
super(metadata)
//create an object that persists until gnome-shell is restarted, even if the extension is disabled
PERSISTENTSTORAGE = {}
}
async enable() {
// Workaround for race condition in GNOME Shell where enable() may be called multiple times
if (this._alreadyEnabled) {
return
}
this._alreadyEnabled = true
DTP_EXTENSION = this
SETTINGS = this.getSettings('org.gnome.shell.extensions.zorin-taskbar')
try {
TILINGSETTINGS = new Gio.Settings({
schema_id: 'org.gnome.shell.extensions.zorin-tiling-shell',
})
} catch (e) {
console.log(e)
}
SHELLSETTINGS = new Gio.Settings({
schema_id: 'org.gnome.shell',
})
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.zorinTaskbar = new EventEmitter()
await PanelSettings.init(SETTINGS)
// To remove later, try to map settings using monitor indexes to monitor ids
PanelSettings.adjustMonitorSettings(SETTINGS)
this.enableGlobalStyles()
let completeEnable = () => {
panelManager = new PanelManager.PanelManager()
panelManager.enable()
zorinDashDelayId = 0
return GLib.SOURCE_REMOVE
}
// disable Zorin Dash if present
if (Main.extensionManager._extensionOrder.indexOf(ZORIN_DASH_UUID) >= 0) {
let disabled = global.settings.get_strv('disabled-extensions')
if (disabled.indexOf(ZORIN_DASH_UUID) < 0) {
disabled.push(ZORIN_DASH_UUID)
global.settings.set_strv('disabled-extensions', disabled)
// wait a bit so Zorin Dash can disable itself and restore the showappsbutton
zorinDashDelayId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
200,
completeEnable,
)
}
} else completeEnable()
}
disable() {
if (zorinDashDelayId) GLib.Source.remove(zorinDashDelayId)
zorinDashDelayId = 0
panelManager?.disable()
PanelSettings.clearCache()
DTP_EXTENSION = null
SETTINGS = null
TILINGSETTINGS = null
SHELLSETTINGS = null
DESKTOPSETTINGS = null
TERMINALSETTINGS = null
NOTIFICATIONSSETTINGS = null
panelManager = null
tracker = null
delete global.zorinTaskbar
this.disableGlobalStyles()
AppIcons.resetRecentlyClickedApp()
this._alreadyEnabled = false
}
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 * 5}`,
)
}
disableGlobalStyles() {
;['br5', 'br10', 'br15', 'br20', 'br25'].forEach((c) =>
Main.layoutManager.uiGroup.remove_style_class_name(c),
)
}
}

593
src/intellihide.js Normal file
View File

@@ -0,0 +1,593 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
*/
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'
const INTELLIHIDE_PRESSURE_THRESHOLD = 100
const INTELLIHIDE_PRESSURE_TIME = 1000
const INTELLIHIDE_ANIMATION_TIME = 200
const INTELLIHIDE_CLOSE_DELAY = 400
const INTELLIHIDE_REVEAL_DELAY = 0
const INTELLIHIDE_ENABLE_START_DELAY = 2000
//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,
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'
],
() => 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(
INTELLIHIDE_PRESSURE_THRESHOLD,
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 = INTELLIHIDE_CLOSE_DELAY * 0.001
else if (destination == 0)
delay = 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
: 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
}
}

216
src/notificationsMonitor.js Normal file
View File

@@ -0,0 +1,216 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
*/
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))
}
}

518
src/overview.js Normal file
View File

@@ -0,0 +1,518 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Dash to Panel extension
* 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-'
const OVERLAY_TIMEOUT = 750
const SHORTCUT_TIMEOUT = 2000
// 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.toggleDash()
this._adaptAlloc()
this._signalsHandler.add([
SETTINGS,
['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()
}
toggleDash(visible) {
if (visible === undefined) {
visible = false
}
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',
],
() => {
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 = 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) {
// 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)
})
}
}
_onSwipeBegin() {
this._swiping = true
return true
}
_onSwipeEnd() {
this._timeoutsHandler.add([T1, 0, () => (this._swiping = false)])
return true
}
}

1578
src/panel.js Normal file

File diff suppressed because it is too large Load Diff

1120
src/panelManager.js Normal file

File diff suppressed because it is too large Load Diff

70
src/panelPositions.js Normal file
View File

@@ -0,0 +1,70 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
*/
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: LEFT_BOX, visible: true, position: STACKED_TL },
{ element: SHOW_APPS_BTN, visible: false, position: STACKED_TL },
{ element: TASKBAR, visible: true, position: STACKED_TL },
{ element: CENTER_BOX, visible: true, position: STACKED_BR },
{ element: ACTIVITIES_BTN, visible: true, position: STACKED_BR },
{ element: RIGHT_BOX, visible: true, position: STACKED_BR },
{ element: SYSTEM_MENU, visible: true, position: STACKED_BR },
{ element: DATE_MENU, visible: true, position: STACKED_BR },
{ element: DESKTOP_BTN, visible: false, position: STACKED_BR },
]
export const anchorToPosition = {
[START]: STACKED_TL,
[MIDDLE]: CENTERED_MONITOR,
[END]: STACKED_BR,
}
export const optionDialogFunctions = {}
optionDialogFunctions[DATE_MENU] = '_showDateMenuOptions'
optionDialogFunctions[DESKTOP_BTN] = '_showDesktopButtonOptions'
export function checkIfCentered(position) {
return position == CENTERED || position == CENTERED_MONITOR
}

300
src/panelSettings.js Normal file
View File

@@ -0,0 +1,300 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 useCache = false
let cache = {}
let monitorIdToIndex = {}
let monitorIndexToId = {}
export var displayConfigProxy = null
export var availableMonitors = []
export async function init(settings) {
useCache = true
cache = {}
await setMonitorsInfo(settings)
}
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 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) {
/* Commented out as Zorin Taskbar always uses gnome-shell primary monitor
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')
}

168
src/panelStyle.js Normal file
View File

@@ -0,0 +1,168 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
* 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'
export const PanelStyle = class {
enable(panel) {
this.panel = panel
this._applyStyles()
}
disable() {
this._removeStyles()
}
_applyStyles() {
this._rightBoxOperations = []
// center box has been moved next to the right box and will be treated the same
this._centerBoxOperations = this._rightBoxOperations
this._leftBoxOperations = []
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)
}
}
}
_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)
}
}
}

1855
src/prefs.js Normal file

File diff suppressed because it is too large Load Diff

299
src/proximity.js Normal file
View File

@@ -0,0 +1,299 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
*/
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 &&
metaWindow.window_type != Meta.WindowType.DESKTOP &&
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),
))
)
}
}

207
src/stylesheet.css Normal file
View File

@@ -0,0 +1,207 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Dash to Panel extension
* Some code was also adapted from the upstream Gnome Shell source code.
*/
#zorintaskbarTaskbar .dash-item-container > StWidget,
.zorintaskbarMainPanel .dash-item-container .show-apps {
margin: 0;
padding: 0;
}
#zorintaskbarScrollview .overview-tile,
.zorintaskbarMainPanel .overview-tile {
background: none;
}
#zorintaskbarScrollview .overview-tile .overview-label {
/* must match TITLE_RIGHT_PADDING in apppicons.js */
padding-right: 8px;
text-align: left;
}
.zorintaskbarMainPanel .dash-item-container .show-apps .overview-icon {
color: #FFF;
}
#zorintaskbarTaskbar .dash-item-container .overview-tile:hover,
#zorintaskbarTaskbar .dash-item-container .overview-tile .dtp-container .overview-icon,
.zorintaskbarMainPanel .dash-item-container .show-apps:hover .overview-icon {
background: none;
}
#zorintaskbarScrollview .overview-tile .favorite {
/*background-color: rgba(80, 150, 255, 0.4);*/
}
#zorintaskbarTaskbar .scrollview-fade {
background-gradient-end: rgba(0, 0, 0, 0);
}
.zorintaskbarSecondaryMenu {
max-width: 400px;
}
.zorintaskbarMainPanel.vertical .panel-button {
text-align: center;
}
.zorintaskbarMainPanel.vertical .panel-button.vertical *,
.zorintaskbarMainPanel.vertical .panel-button.clock-display * {
padding: 0;
margin: 0;
}
.zorintaskbarMainPanel.vertical .panel-button > *,
.zorintaskbarMainPanel.vertical .panel-button.vertical > *,
.zorintaskbarMainPanel.vertical .panel-button.vertical .system-status-icon,
.zorintaskbarMainPanel.vertical .panel-button.clock-display > *,
.zorintaskbarMainPanel.vertical .panel-button.clock-display .clock {
padding: 8px 0;
}
.zorintaskbarMainPanel.vertical .panel-button.clock-display {
-natural-hpadding: 0;
-minimum-hpadding: 0;
}
#zorintaskbarThumbnailList {
spacing: 0em;
padding: 0 1em;
}
#zorintaskbarThumbnailList .popup-menu-item {
padding: 0;
border-radius: 5px;
spacing: 0;
}
#zorintaskbarThumbnailList .window-box {
padding: 0;
spacing: 0;
}
#zorintaskbarThumbnailList .preview-window-title {
padding-top: 1em;
}
.popup-menu.panel-menu {
margin-bottom: 0;
}
#panel #panelLeft, #panel #panelCenter {
spacing: 0px;
}
#zorintaskbarScrollview .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;
}
#zorintaskbarScrollview .number-overlay {
background-color: rgba(0,0,0,0.8);
}
#zorintaskbarScrollview .notification-badge {
background-color: rgba(255,0,0,0.8);
margin: 2px;
}
#zorintaskbarScrollview .progress-bar {
/* Customization of the progress bar style, e.g.:
-progress-bar-background: rgba(0.8, 0.8, 0.8, 1);
-progress-bar-border: rgba(0.9, 0.9, 0.9, 1); */
}
.preview-container,
#preview-menu {
border-radius: 10px;
}
/* border radius, grrr no css variables in ST */
#uiGroup.br5 .zorintaskbarPanel.dock,
#uiGroup.br5 .zorintaskbarPanel.dock .zorintaskbarMainPanel,
#uiGroup.br5 .show-apps,
#uiGroup.br5 .dtp-container,
#uiGroup.br5 .dtp-dots-container {
border-radius: 5px !important;
overflow: hidden !important;
}
#uiGroup.br5 .zorintaskbarMainPanel .panel-button,
#uiGroup.br5 .zorintaskbarMainPanel .panel-button.clock-display .clock {
border-radius: 5px;
}
#uiGroup.br10 .zorintaskbarPanel.dock,
#uiGroup.br10 .zorintaskbarPanel.dock .zorintaskbarMainPanel,
#uiGroup.br10 .show-apps,
#uiGroup.br10 .dtp-container,
#uiGroup.br10 .dtp-dots-container {
border-radius: 10px !important;
overflow: hidden !important;
}
#uiGroup.br10 .zorintaskbarMainPanel .panel-button,
#uiGroup.br10 .zorintaskbarMainPanel .panel-button.clock-display .clock {
border-radius: 10px;
}
#uiGroup.br15 .zorintaskbarPanel.dock,
#uiGroup.br15 .zorintaskbarPanel.dock .zorintaskbarMainPanel,
#uiGroup.br15 .show-apps,
#uiGroup.br15 .dtp-container,
#uiGroup.br15 .dtp-dots-container {
border-radius: 15px !important;
overflow: hidden !important;
}
#uiGroup.br15 .zorintaskbarMainPanel .panel-button,
#uiGroup.br15 .zorintaskbarMainPanel .panel-button.clock-display .clock {
border-radius: 15px;
}
#uiGroup.br20 .zorintaskbarPanel.dock,
#uiGroup.br20 .zorintaskbarPanel.dock .zorintaskbarMainPanel,
#uiGroup.br20 .show-apps,
#uiGroup.br20 .dtp-container,
#uiGroup.br20 .dtp-dots-container {
border-radius: 20px !important;
overflow: hidden !important;
}
#uiGroup.br20 .zorintaskbarMainPanel .panel-button,
#uiGroup.br20 .zorintaskbarMainPanel .panel-button.clock-display .clock {
border-radius: 20px;
}
#uiGroup.br25 .zorintaskbarPanel.dock,
#uiGroup.br25 .zorintaskbarPanel.dock .zorintaskbarMainPanel,
#uiGroup.br25 .show-apps,
#uiGroup.br25 .dtp-container,
#uiGroup.br25 .dtp-dots-container {
border-radius: 25px !important;
overflow: hidden !important;
}
#uiGroup.br25 .zorintaskbarMainPanel .panel-button,
#uiGroup.br25 .zorintaskbarMainPanel .panel-button.clock-display .clock {
border-radius: 25px;
}

1479
src/taskbar.js Normal file

File diff suppressed because it is too large Load Diff

245
src/transparency.js Normal file
View File

@@ -0,0 +1,245 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
*/
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'
const TRANS_DYNAMIC_DISTANCE = 20
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._updateAllAndSet()
this._updateProximityWatch()
}
destroy() {
this._signalsHandler.destroy()
this._proximityManager.removeWatch(this._proximityWatchId)
this._dtpPanel.panel.set_style(this._initialPanelStyle)
}
updateExternalStyle() {
this._setStyle()
}
_bindSignals() {
this._signalsHandler.add(
[Utils.getStageTheme(), 'changed', () => this._updateAllAndSet()],
[Main.overview, ['showing', 'hiding'], () => this._updateAlphaAndSet()],
[
SETTINGS,
[
'changed::trans-use-custom-opacity',
'changed::trans-panel-opacity',
'changed::trans-dynamic-anim-target',
'changed::trans-use-dynamic-opacity',
],
() => this._updateAlphaAndSet(),
],
[
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',
],
() => this._updateProximityWatch(),
],
)
}
_updateProximityWatch() {
this._proximityManager.removeWatch(this._proximityWatchId)
if (SETTINGS.get_boolean('trans-use-dynamic-opacity')) {
let isVertical = this._dtpPanel.geom.vertical
let threshold = 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()
},
)
}
}
_updateAllAndSet() {
let themeBackground = this._getThemeBackground(true)
this._updateColor(themeBackground)
this._updateAlpha(themeBackground)
this._updateBorder()
this._updateBackground()
this._setStyle()
}
_updateAlphaAndSet() {
this._updateAlpha()
this._updateBackground()
this._setStyle()
}
_updateBorderAndSet() {
this._updateBorder()
this._setStyle()
}
_updateColor(themeBackground) {
this.backgroundColorRgb = 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 : ''
}
_updateBackground() {
this.currentBackgroundColor = Utils.getrgbaColor(
this.backgroundColorRgb,
this.alpha,
)
this._backgroundStyle = `background-color: ${this.currentBackgroundColor}`
}
_setStyle() {
const transition = 'transition-duration: 300ms;'
this._dtpPanel.panel.set_style(
transition +
this._backgroundStyle +
this._borderStyle,
)
console.log('Set DTP Panel style to', this._dtpPanel.panel.get_style())
}
_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
View File

@@ -0,0 +1,969 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Dash to Panel extension
* 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()
}

1384
src/windowPreview.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,146 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Dash to Panel extension
* Some code was also adapted from the upstream Gnome Shell source code.
*/
#zorintaskbarTaskbar .dash-item-container > StWidget,
.zorintaskbarMainPanel .show-apps {
margin: 0;
padding: 0;
}
#zorintaskbarScrollview .app-well-app .overview-icon,
.zorintaskbarMainPanel .show-apps .overview-icon {
background: none;
border: none;
margin: 0;
padding: 0;
}
#zorintaskbarScrollview .app-well-app .overview-label {
/* must match TITLE_RIGHT_PADDING in apppicons.js */
padding-right: 8px;
}
#zorintaskbarScrollview .app-well-app .favorite {
/*background-color: rgba(80, 150, 255, 0.4);*/
}
#zorintaskbarScrollview .app-well-app-running-dot {
margin-bottom: 0;
}
#zorintaskbarTaskbar .scrollview-fade {
background-gradient-end: rgba(0, 0, 0, 0);
}
.zorintaskbarSecondaryMenu {
max-width: 400px;
}
.zorintaskbarMainPanel.vertical .panel-button {
text-align: center;
}
.zorintaskbarMainPanel.vertical .panel-button.vertical *,
.zorintaskbarMainPanel.vertical .panel-button.clock-display * {
padding: 0;
margin: 0;
}
.zorintaskbarMainPanel.vertical .panel-button > *,
.zorintaskbarMainPanel.vertical .panel-button.vertical > *,
.zorintaskbarMainPanel.vertical .panel-button.vertical .system-status-icon,
.zorintaskbarMainPanel.vertical .panel-button.clock-display > *,
.zorintaskbarMainPanel.vertical .panel-button.clock-display .clock {
padding: 8px 0;
}
.zorintaskbarMainPanel.vertical .panel-button.clock-display {
-natural-hpadding: 0;
-minimum-hpadding: 0;
}
#zorintaskbarThumbnailList {
spacing: 0em;
padding: 0 1em;
}
#zorintaskbarThumbnailList .popup-menu-item {
padding: 0;
border-radius: 5px;
spacing: 0;
}
#zorintaskbarThumbnailList .window-box {
padding: 0;
spacing: 0;
}
#zorintaskbarThumbnailList .preview-window-title {
padding-top: 1em;
}
.popup-menu.panel-menu {
margin-bottom: 0;
}
#panel #panelLeft, #panel #panelCenter {
spacing: 0px;
}
#panelBox.floating {
padding: 8px;
background: transparent;
}
#panelBox.floating #panel,
#panelBox.floating .panel-button,
#panelBox.floating .panel-button.clock-display .clock {
border-radius: 10px;
}
#zorintaskbarScrollview .badge {
color: rgba(255, 255, 255, 1);
font-weight: bold;
text-align: center;
}
#zorintaskbarScrollview .number-overlay {
background-color: rgba(0,0,0,0.8);
}
#zorintaskbarScrollview .notification-badge {
background-color: rgba(255,0,0,0.8);
margin: 2px;
}
#zorintaskbarScrollview .progress-bar {
/* Customization of the progress bar style, e.g.:
-progress-bar-background: rgba(0.8, 0.8, 0.8, 1);
-progress-bar-border: rgba(0.9, 0.9, 0.9, 1);
*/
}
.preview-container,
#preview-menu {
border-radius: 10px;
}

1281
taskbar.js

File diff suppressed because it is too large Load Diff

View File

@@ -1,204 +0,0 @@
/*
* This file is part of the Zorin Taskbar extension for Zorin OS.
*
* 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 Panel extension
*/
const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf;
const Main = imports.ui.main;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Config = imports.misc.config;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Panel = Me.imports.panel;
const Proximity = Me.imports.proximity;
const Utils = Me.imports.utils;
const TRANS_DYNAMIC_DISTANCE = 20;
var 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._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()
],
[
Me.settings,
[
'changed::trans-use-custom-opacity',
'changed::trans-panel-opacity',
'changed::trans-dynamic-anim-target',
'changed::trans-use-dynamic-opacity'
],
() => this._updateAlphaAndSet()
],
[
Me.settings,
[
'changed::trans-dynamic-behavior',
'changed::trans-use-dynamic-opacity'
],
() => this._updateProximityWatch()
]
);
}
_updateProximityWatch() {
this._proximityManager.removeWatch(this._proximityWatchId);
if (Me.settings.get_boolean('trans-use-dynamic-opacity')) {
let isVertical = this._dtpPanel.checkIfVertical();
let threshold = TRANS_DYNAMIC_DISTANCE;
this._windowOverlap = false;
this._updateAlphaAndSet()
this._proximityWatchId = this._proximityManager.createWatch(
this._dtpPanel.panelBox.get_parent(),
this._dtpPanel.monitor.index,
Proximity.Mode[Me.settings.get_string('trans-dynamic-behavior')],
isVertical ? threshold : 0,
isVertical ? 0 : threshold,
overlap => {
this._windowOverlap = overlap;
this._updateAlphaAndSet();
}
);
}
}
_updateAllAndSet() {
let themeBackground = this._getThemeBackground(true);
this._updateColor(themeBackground);
this._updateAlpha(themeBackground);
this._updateComplementaryStyles();
this._setBackground();
this._setActorStyle();
}
_updateAlphaAndSet() {
this._updateAlpha();
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 = themeBackground || this._getThemeBackground();
}
_updateAlpha(themeBackground) {
if (this._windowOverlap && !Main.overview.visibleTarget && Me.settings.get_boolean('trans-use-dynamic-opacity')) {
this.alpha = Me.settings.get_double('trans-dynamic-anim-target');
} else {
this.alpha = Me.settings.get_boolean('trans-use-custom-opacity') ?
Me.settings.get_double('trans-panel-opacity') :
(themeBackground || this._getThemeBackground()).alpha * 0.003921569; // 1 / 255 = 0.003921569
}
}
_setBackground() {
this.currentBackgroundColor = Utils.getrgbaColor(this.backgroundColorRgb, this.alpha);
let transition = 'transition-duration: 300ms;';
this._dtpPanel.set_style('background-color: ' + this.currentBackgroundColor + transition + this._complementaryStyles);
}
_setActorStyle() {
this._dtpPanel.panel.set_style(
'background: none; ' +
'border-image: none; ' +
'background-image: none; ' +
'transition-duration: 300ms;'
);
}
_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;
}
}

View File

@@ -1,47 +1,56 @@
<?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="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">Floating rounded theme</property>
<property name="title" translatable="yes">Only hide the panel from windows</property>
<child>
<object class="GtkSwitch" id="intellihide_floating_rounded_theme_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>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Only hide the panel when it is obstructed by windows</property>
<child>
<object class="GtkSwitch" id="intellihide_window_hide_switch">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="intellihide_behaviour_options">
<property name="title" translatable="yes">The panel hides from</property>
@@ -57,16 +66,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>
@@ -74,13 +134,10 @@
</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>
@@ -91,11 +148,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>
@@ -103,24 +159,41 @@
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="subtitle" translatable="yes">Syntax: &amp;lt;Shift&amp;gt;, &amp;lt;Ctrl&amp;gt;, &amp;lt;Alt&amp;gt;, &amp;lt;Super&amp;gt;</property>
<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>
<child>
<object class="GtkEntry" id="intellihide_toggle_entry">
<property name="placeholder-text" translatable="yes">e.g. &lt;Super&gt;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 "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. &lt;Super&gt;i</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -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>
@@ -97,4 +100,4 @@
</object>
</interface>
</interface>

View File

@@ -1,23 +1,22 @@
<?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="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>
@@ -29,11 +28,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>
@@ -46,37 +44,34 @@
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="subtitle" translatable="yes">Syntax: &amp;lt;Shift&amp;gt;, &amp;lt;Ctrl&amp;gt;, &amp;lt;Alt&amp;gt;, &amp;lt;Super&amp;gt;</property>
<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>
<child>
<object class="GtkEntry" id="shortcut_entry">
<property name="placeholder-text" translatable="yes">e.g. &lt;Super&gt;q</property>
<property name="valign">center</property>
<property name="width_chars">12</property>
<property name="placeholder_text" translatable="yes">e.g. &lt;Super&gt;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="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 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>
@@ -89,9 +84,7 @@
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -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="title">Action</property>
<property name="icon_name">view-pin-symbolic</property>
<!-- group click action -->
<property name="icon-name">input-mouse-symbolic</property>
<property name="title" translatable="yes">Action</property>
<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,23 +44,19 @@
</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 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="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>
@@ -70,26 +65,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>
@@ -104,15 +95,11 @@
</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 top panel</property>
@@ -123,7 +110,6 @@
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Activate panel menu buttons on click only</property>
@@ -135,9 +121,7 @@
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -2,7 +2,7 @@
<interface>
<requires lib="gtk" version="4.0"/>
<object class="AdwPreferencesPage" id="behavior">
<property name="title">Behavior</property>
<property name="title" translatable="yes">Behavior</property>
<property name="icon_name">preferences-system-symbolic</property>
<!-- group applications -->
@@ -42,7 +42,7 @@
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Ungroup applications</property>
@@ -87,7 +87,7 @@
<!-- group hover -->
<child>
<object class="AdwPreferencesGroup" id="behavior_group_hover">
<property name="title">Hover</property>
<property name="title" translatable="yes">Hover</property>
<child>
<object class="AdwActionRow">

View File

@@ -1,201 +1,186 @@
<?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="title">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 panels on all monitors</property>
<child>
<object class="GtkSwitch" id="multimon_multi_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" swapped="no"/>
</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" swapped="no"/>
</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" swapped="no"/>
</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" swapped="no"/>
</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">350</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" swapped="no"/>
</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">350</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>
<property name="icon-name">find-location-symbolic</property>
<property name="title" translatable="yes">Position</property>
<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 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_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>

Some files were not shown because too many files have changed in this diff Show More