diff --git a/.gitignore b/.gitignore
index 062535b..fdc00a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ zorin-taskbar@zorinos.com*.zip
*.mo
po/zorin-taskbar.pot
ui/*.ui.h
+node_modules/
diff --git a/Makefile b/Makefile
index 0dfa877..66e451b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,11 @@
# 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)),)
INSTALLBASE = $(HOME)/.local/share/gnome-shell/extensions
@@ -49,7 +47,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; \
@@ -79,12 +77,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/
diff --git a/appIcons.js b/appIcons.js
deleted file mode 100644
index 60fdbce..0000000
--- a/appIcons.js
+++ /dev/null
@@ -1,1666 +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 .
- *
- *
- * 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 GLib from 'gi://GLib';
-import Gio from 'gi://Gio';
-import Graphene from 'gi://Graphene';
-import GObject from 'gi://GObject';
-import Mtk from 'gi://Mtk';
-import Shell from 'gi://Shell';
-import St from 'gi://St';
-
-import * as AppDisplay from 'resource:///org/gnome/shell/ui/appDisplay.js';
-import * as AppMenu from 'resource:///org/gnome/shell/ui/appMenu.js';
-import * as Dash from 'resource:///org/gnome/shell/ui/dash.js';
-import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
-import * as Main from 'resource:///org/gnome/shell/ui/main.js';
-import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
-import * as Util from 'resource:///org/gnome/shell/misc/util.js';
-import * as BoxPointer from 'resource:///org/gnome/shell/ui/boxpointer.js';
-import {EventEmitter} from 'resource:///org/gnome/shell/misc/signals.js';
-
-import * as Utils from './utils.js';
-import * as PanelSettings from './panelSettings.js';
-import * as Taskbar from './taskbar.js';
-import * as Progress from './progress.js';
-import {DTP_EXTENSION, SETTINGS, DESKTOPSETTINGS, EXTENSION_PATH} from './extension.js';
-import {gettext as _, ngettext} from 'resource:///org/gnome/shell/extensions/extension.js';
-
-//timeout names
-const T2 = 'mouseScrollTimeout';
-const T3 = 'showDotsTimeout';
-const T4 = 'overviewWindowDragEndTimeout';
-const T5 = 'switchWorkspaceTimeout';
-const T6 = 'displayProperIndicatorTimeout';
-
-const SCROLL_ICON_DELAY = 400;
-const DOT_SIZE = 3;
-
-//right padding defined for .overview-label in stylesheet.css
-const TITLE_RIGHT_PADDING = 8;
-const DOUBLE_CLICK_DELAY_MS = 450;
-
-let LABEL_GAP = 5;
-let MAX_INDICATORS = 4;
-export const DEFAULT_PADDING_SIZE = 4;
-
-let DOT_STYLE = {
- DOTS: "DOTS",
- SQUARES: "SQUARES",
- DASHES: "DASHES",
- SEGMENTED: "SEGMENTED",
- CILIORA: "CILIORA",
- METRO: "METRO",
- SOLID: "SOLID"
-}
-
-let DOT_POSITION = {
- TOP: "TOP",
- BOTTOM: "BOTTOM",
- LEFT: 'LEFT',
- RIGHT: 'RIGHT'
-}
-
-let recentlyClickedAppLoopId = 0;
-let recentlyClickedApp = null;
-let recentlyClickedAppWindows = null;
-let recentlyClickedAppIndex = 0;
-let recentlyClickedAppMonitorIndex;
-
-let tracker = Shell.WindowTracker.get_default();
-
-/**
- * Extend AppIcon
- *
- * - Apply a css class based on the number of windows of each application (#N);
- * - Draw a dot for each window of the application based on the default "dot" style which is hidden (#N);
- * a class of the form "running#N" is applied to the AppWellIcon actor.
- * like the original .running one.
- * - add a .focused style to the focused app
- * - Customize click actions.
- * - Update minimization animation target
- *
- */
-
-export const TaskbarAppIcon = GObject.registerClass({
-}, class TaskbarAppIcon extends AppDisplay.AppIcon {
-
- _init(appInfo, panel, iconParams, previewMenu, iconAnimator) {
- this.dtpPanel = panel;
- this._nWindows = 0;
- this.window = appInfo.window;
- this.isLauncher = appInfo.isLauncher;
- this._previewMenu = previewMenu;
- this.iconAnimator = iconAnimator;
- this.lastClick = 0;
-
- super._init(appInfo.app, iconParams);
-
- this._timeoutsHandler = new Utils.TimeoutsHandler();
-
- // Fix touchscreen issues before the listener is added by the parent constructor.
- this._onTouchEvent = function(actor, event) {
- if (event.type() == Clutter.EventType.TOUCH_BEGIN) {
- // Open the popup menu on long press.
- this._setPopupTimeout();
- } else if (this._menuTimeoutId != 0 && (event.type() == Clutter.EventType.TOUCH_END || event.type() == Clutter.EventType.TOUCH_CANCEL)) {
- // Activate/launch the application.
- this.activate(1);
- this._removeMenuTimeout();
- }
- // Disable dragging via touch screen as it's buggy as hell. Not perfect for tablet users, but the alternative is way worse.
- // Also, EVENT_PROPAGATE launches applications twice with this solution, so this.activate(1) above must only be called if there's already a window.
- return Clutter.EVENT_STOP;
- };
- // Hack for missing TOUCH_END event.
- this._onLeaveEvent = function(actor, event) {
- this.fake_release();
- if (this._menuTimeoutId != 0) this.activate(1); // Activate/launch the application if TOUCH_END didn't fire.
- this._removeMenuTimeout();
- };
-
-
- this._dot.set_width(0);
- this._isGroupApps = SETTINGS.get_boolean('group-apps');
-
- this._container = new St.Widget({ style_class: 'dtp-container', layout_manager: new Clutter.BinLayout() });
- this._dotsContainer = new St.Widget({ layout_manager: new Clutter.BinLayout() });
- this._dtpIconContainer = new St.Widget({ layout_manager: new Clutter.BinLayout(), style: getIconContainerStyle(panel.checkIfVertical()) });
-
- this.remove_child(this._iconContainer);
-
- this._dtpIconContainer.add_child(this._iconContainer);
-
- if (appInfo.window) {
- let box = new St.BoxLayout();
-
- this._windowTitle = new St.Label({
- y_align: Clutter.ActorAlign.CENTER,
- x_align: Clutter.ActorAlign.START,
- style_class: 'overview-label'
- });
-
- this._updateWindowTitle();
- this._updateWindowTitleStyle();
-
- this._scaleFactorChangedId = Utils.getStageTheme().connect('changed', () => this._updateWindowTitleStyle());
-
- box.add_child(this._dtpIconContainer);
- box.add_child(this._windowTitle);
-
- this._dotsContainer.add_child(box);
- } else {
- this._dotsContainer.add_child(this._dtpIconContainer);
- }
-
- this._container.add_child(this._dotsContainer);
- this.set_child(this._container);
-
- if (panel.checkIfVertical()) {
- this.set_width(panel.geom.w);
- }
-
- // Monitor windows-changes instead of app state.
- // Keep using the same Id and function callback (that is extended)
- if(this._stateChangedId > 0) {
- this.app.disconnect(this._stateChangedId);
- this._stateChangedId = 0;
- }
-
- this._setAppIconPadding();
- this._showDots();
-
- this._focusWindowChangedId = global.display.connect('notify::focus-window',
- this._onFocusAppChanged.bind(this));
-
- this._windowEnteredMonitorId = this._windowLeftMonitorId = 0;
- this._stateChangedId = this.app.connect('windows-changed', this.onWindowsChanged.bind(this));
-
- if (!this.window) {
- if (SETTINGS.get_boolean('isolate-monitors')) {
- this._windowEnteredMonitorId = Utils.DisplayWrapper.getScreen().connect('window-entered-monitor', this.onWindowEnteredOrLeft.bind(this));
- this._windowLeftMonitorId = Utils.DisplayWrapper.getScreen().connect('window-left-monitor', this.onWindowEnteredOrLeft.bind(this));
- }
-
- this._titleWindowChangeId = 0;
- this._minimizedWindowChangeId = 0;
- } else {
- this._titleWindowChangeId = this.window.connect('notify::title',
- this._updateWindowTitle.bind(this));
-
- this._minimizedWindowChangeId = this.window.connect('notify::minimized',
- this._updateWindowTitleStyle.bind(this));
- }
-
- this._scrollEventId = this.connect('scroll-event', this._onMouseScroll.bind(this));
-
- this._overviewWindowDragEndId = Main.overview.connect('window-drag-end',
- this._onOverviewWindowDragEnd.bind(this));
-
- this._switchWorkspaceId = global.window_manager.connect('switch-workspace',
- this._onSwitchWorkspace.bind(this));
-
- this._hoverChangeId = this.connect('notify::hover', () => this._onAppIconHoverChanged());
-
- this._dtpSettingsSignalIds = [
- SETTINGS.connect('changed::panel-positions', this._settingsChangeRefresh.bind(this)),
- SETTINGS.connect('changed::dot-style-focused', this._settingsChangeRefresh.bind(this)),
- SETTINGS.connect('changed::dot-style-unfocused', this._settingsChangeRefresh.bind(this)),
- SETTINGS.connect('changed::panel-positions', this._settingsChangeRefresh.bind(this)),
- SETTINGS.connect('changed::group-apps-label-max-width', this._updateWindowTitleStyle.bind(this)),
- SETTINGS.connect('changed::group-apps-use-fixed-width', this._updateWindowTitleStyle.bind(this)),
- ]
-
- this._progressIndicator = new Progress.ProgressIndicator(this, panel.progressManager);
-
- this._numberOverlay();
- }
-
- getDragActor() {
- return this.app.create_icon_texture(this.dtpPanel.taskbar.iconSize);
- }
-
- shouldShowTooltip() {
- if (!SETTINGS.get_boolean('show-tooltip') ||
- (!this.isLauncher && SETTINGS.get_boolean("show-window-previews") &&
- this.getAppIconInterestingWindows().length > 0)) {
- return false;
- } else {
- return this.hover && !this.window &&
- (!this._menu || !this._menu.isOpen) &&
- (this._previewMenu.getCurrentAppIcon() !== this);
- }
- }
-
- _onAppIconHoverChanged() {
- if (!SETTINGS.get_boolean('show-window-previews') ||
- (!this.window && !this._nWindows)) {
- return;
- }
-
- if (this.hover) {
- this._previewMenu.requestOpen(this);
- } else {
- this._previewMenu.requestClose();
- }
- }
-
- _onDestroy() {
- super._onDestroy();
-
- this._timeoutsHandler.destroy();
-
- this._previewMenu.close(true);
-
- // Disconect global signals
- if (this._stateChangedId > 0) {
- this.app.disconnect(this._stateChangedId);
- this._stateChangedId = 0;
- }
-
- if(this._overviewWindowDragEndId)
- Main.overview.disconnect(this._overviewWindowDragEndId);
-
- if(this._focusWindowChangedId)
- global.display.disconnect(this._focusWindowChangedId);
-
- if(this._titleWindowChangeId)
- this.window.disconnect(this._titleWindowChangeId);
-
- if(this._minimizedWindowChangeId)
- this.window.disconnect(this._minimizedWindowChangeId);
-
- if (this._windowEnteredMonitorId) {
- Utils.DisplayWrapper.getScreen().disconnect(this._windowEnteredMonitorId);
- Utils.DisplayWrapper.getScreen().disconnect(this._windowLeftMonitorId);
- }
-
- if(this._switchWorkspaceId)
- global.window_manager.disconnect(this._switchWorkspaceId);
-
- if(this._scaleFactorChangedId)
- Utils.getStageTheme().disconnect(this._scaleFactorChangedId);
-
- if (this._hoverChangeId) {
- this.disconnect(this._hoverChangeId);
- }
-
- if (this._scrollEventId) {
- this.disconnect(this._scrollEventId);
- }
-
- for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) {
- SETTINGS.disconnect(this._dtpSettingsSignalIds[i]);
- }
- }
-
- onWindowsChanged() {
- this._updateWindows();
- this.updateIcon();
-
- if (this._isGroupApps)
- this._setIconStyle();
- }
-
- onWindowEnteredOrLeft(display, number, metaWindow) {
- if (number > 0 && tracker.get_window_app(metaWindow) == this.app) {
- this._updateWindows();
- this._displayProperIndicator();
- }
- }
-
- updateTitleStyle() {
- this._updateWindowTitleStyle();
- }
-
- // Update indicator and target for minimization animation
- updateIcon() {
-
- // If (for unknown reason) the actor is not on the stage the reported size
- // and position are random values, which might exceeds the integer range
- // resulting in an error when assigned to the a rect. This is a more like
- // a workaround to prevent flooding the system with errors.
- if (this.get_stage() == null)
- return;
-
- let rect = new Mtk.Rectangle();
-
- [rect.x, rect.y] = this.get_transformed_position();
- [rect.width, rect.height] = this.get_transformed_size();
-
- let windows = this.window ? [this.window] : this.getAppIconInterestingWindows(true);
- windows.forEach(function(w) {
- w.set_icon_geometry(rect);
- });
- }
-
- _onMouseScroll(actor, event) {
- let scrollAction = SETTINGS.get_string('scroll-icon-action');
-
- if (scrollAction === 'NOTHING' || (!this.window && !this._nWindows)) {
- return;
- }
-
- let direction = Utils.getMouseScrollDirection(event);
-
- if (direction && !this._timeoutsHandler.getId(T2)) {
- this._timeoutsHandler.add([T2, SCROLL_ICON_DELAY, () => {}]);
-
- let windows = this.getAppIconInterestingWindows();
-
- windows.sort(Taskbar.sortWindowsCompareFunction);
- Utils.activateSiblingWindow(windows, direction, this.window);
- }
- }
-
- _showDots() {
- // Just update style if dots already exist
- if (this._focusedDots && this._unfocusedDots) {
- this._updateWindows();
- return;
- }
-
- if (!this._isGroupApps) {
- this._focusedDots = new St.Widget({
- layout_manager: new Clutter.BinLayout(),
- x_expand: true, y_expand: true,
- visible: false
- });
-
- let mappedId = this.connect('notify::mapped', () => {
- this._displayProperIndicator();
- this.disconnect(mappedId);
- });
- } else {
- this._focusedDots = new St.DrawingArea(),
- this._unfocusedDots = new St.DrawingArea();
-
- this._focusedDots.connect('repaint', () => {
- if (!this._dashItemContainer.animatingOut)
- // don't draw and trigger more animations if the icon is in the middle of
- // being removed from the panel
- this._drawRunningIndicator(this._focusedDots, SETTINGS.get_string('dot-style-focused'), true);
- });
-
- this._unfocusedDots.connect('repaint', () => {
- if (!this._dashItemContainer.animatingOut)
- this._drawRunningIndicator(this._unfocusedDots, SETTINGS.get_string('dot-style-unfocused'), false);
- });
-
- this._dotsContainer.add_child(this._unfocusedDots);
-
- this._updateWindows();
-
- this._timeoutsHandler.add([T3, 0, () => {
- this._resetDots();
- this._displayProperIndicator();
- }]);
- }
-
- this._dotsContainer.add_child(this._focusedDots);
- }
-
- _resetDots() {
- let position = PanelSettings.getPanelPosition(SETTINGS, this.dtpPanel.monitor.index);
- let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM;
- let sizeProp = isHorizontalDots ? 'width' : 'height';
- let focusedDotStyle = SETTINGS.get_string('dot-style-focused');
- let unfocusedDotStyle = SETTINGS.get_string('dot-style-unfocused');
-
- this._focusedIsWide = this._isWideDotStyle(focusedDotStyle);
- this._unfocusedIsWide = this._isWideDotStyle(unfocusedDotStyle);
-
- [, this._containerSize] = this._container[`get_preferred_${sizeProp}`](-1);
-
- [this._focusedDots, this._unfocusedDots].forEach(d => {
- d.set_size(-1, -1);
- d.x_expand = d.y_expand = false;
-
- d[sizeProp] = 1;
- d[(isHorizontalDots ? 'y' : 'x') + '_expand'] = true;
- });
- }
-
- _settingsChangeRefresh() {
- if (this._isGroupApps) {
- this._updateWindows();
- this._resetDots();
- this._focusedDots.queue_repaint();
- this._unfocusedDots.queue_repaint();
- }
-
- this._displayProperIndicator();
- }
-
- _updateWindowTitleStyle() {
- if (this._windowTitle) {
- let useFixedWidth = SETTINGS.get_boolean('group-apps-use-fixed-width');
- let scaleFactor = Utils.getScaleFactor();
- let maxLabelWidth = SETTINGS.get_int('group-apps-label-max-width') * scaleFactor;
- let variableWidth = !useFixedWidth || this.dtpPanel.checkIfVertical() || this.dtpPanel.taskbar.fullScrollView;
-
- this._windowTitle[(maxLabelWidth > 0 ? 'show' : 'hide')]();
- this._windowTitle.set_width(variableWidth ? -1 : maxLabelWidth + TITLE_RIGHT_PADDING * scaleFactor);
-
- this._windowTitle.clutter_text.natural_width = useFixedWidth ? maxLabelWidth : 0;
- this._windowTitle.clutter_text.natural_width_set = useFixedWidth;
-
- this._windowTitle.set_style(useFixedWidth ? '' : 'max-width: ' + maxLabelWidth + 'px;');
- }
- }
-
- _updateWindowTitle() {
- if (this._windowTitle.text != this.window.title) {
- this._windowTitle.text = (this.window.title ? this.window.title : this.app.get_name()).replace(/\r?\n|\r/g, '').trim();
-
- if (this._focusedDots) {
- this._displayProperIndicator();
- }
- }
- }
-
- _setIconStyle(isFocused) {
- let inlineStyle = 'margin: 0;';
-
- if(this._dotsContainer.get_style() != inlineStyle) {
- this._dotsContainer.set_style(inlineStyle);
- }
- }
-
- _checkIfFocusedApp() {
- return tracker.focus_app == this.app;
- }
-
- _checkIfMonitorHasFocus() {
- return global.display.focus_window &&
- (!SETTINGS.get_boolean('multi-monitors') || // only check same monitor index if multi window is enabled.
- !SETTINGS.get_boolean('isolate-monitors') ||
- global.display.focus_window.get_monitor() === this.dtpPanel.monitor.index);
- }
-
- _setAppIconPadding() {
- let padding = getIconPadding(this.dtpPanel.monitor.index);
- let margin = Taskbar.APPICON_MARGIN;
-
- this.set_style('padding:' + (this.dtpPanel.checkIfVertical() ? margin + 'px 0' : '0 ' + margin + 'px;'));
- this._iconContainer.set_style('padding: ' + padding + 'px;');
- }
-
- popupMenu() {
- this._removeMenuTimeout();
- this.fake_release();
-
- if (!this._menu) {
- this._menu = new TaskbarSecondaryMenu(this, this.dtpPanel.geom.position);
- this._menu.setApp(this.app);
- this._menu.connect('open-state-changed', (menu, isPoppedUp) => {
- if (!isPoppedUp)
- this._onMenuPoppedDown();
- else
- this._previewMenu.close(true);
- });
- let id = Main.overview.connect('hiding', () => {
- this._menu.close();
- });
- this.connect('destroy', () => {
- Main.overview.disconnect(id);
- });
-
- // We want to keep the item hovered while the menu is up
- this._menu.blockSourceEvents = true;
-
- Main.uiGroup.add_child(this._menu.actor);
- this._menuManager.addMenu(this._menu);
- }
- this._menu.updateQuitText();
-
- this.emit('menu-state-changed', true);
-
- this.set_hover(true);
- this._menu.open(BoxPointer.PopupAnimation.FULL);
- this._menuManager.ignoreRelease();
- this.emit('sync-tooltip');
-
- return false;
- }
-
- _onFocusAppChanged(windowTracker) {
- this._displayProperIndicator();
- }
-
- _onOverviewWindowDragEnd(windowTracker) {
- this._timeoutsHandler.add([T4, 0, () => {
- if (SETTINGS.get_boolean('isolate-workspaces'))
- this._updateWindows()
-
- this._displayProperIndicator()
- }]);
- }
-
- _onSwitchWorkspace(windowTracker) {
- if (this._isGroupApps) {
- this._timeoutsHandler.add([T5, 0, () => this._displayProperIndicator()]);
- } else {
- this._displayProperIndicator();
- }
- }
-
- _displayProperIndicator() {
- let isFocused = this._isFocusedWindow();
- let position = PanelSettings.getPanelPosition(SETTINGS, this.dtpPanel.monitor.index);
- let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM;
-
- this._setIconStyle(isFocused);
-
- if(!this._isGroupApps) {
- if (this.window && isFocused) {
- let align = Clutter.ActorAlign[position == DOT_POSITION.TOP || position == DOT_POSITION.LEFT ? 'START' : 'END'];
-
- this._focusedDots.set_size(0, 0);
- this._focusedDots[isHorizontalDots ? 'height' : 'width'] = this._getRunningIndicatorSize();
-
- this._focusedDots.y_align = this._focusedDots.x_align = Clutter.ActorAlign.FILL;
- this._focusedDots[(isHorizontalDots ? 'y' : 'x') + '_align'] = align;
- this._focusedDots.background_color = this._getRunningIndicatorColor(isFocused);
- this._focusedDots.show();
- } else if (this._focusedDots.visible) {
- this._focusedDots.hide();
- }
- } else {
- let sizeProp = isHorizontalDots ? 'width' : 'height';
- let newFocusedDotsSize = 0;
- let newFocusedDotsOpacity = 0;
- let newUnfocusedDotsSize = 0;
- let newUnfocusedDotsOpacity = 0;
-
- isFocused = this._checkIfFocusedApp() && this._checkIfMonitorHasFocus();
-
- this._timeoutsHandler.add([T6, 0, () => {
- if(isFocused)
- this.add_style_class_name('focused');
- else
- this.remove_style_class_name('focused');
- }]);
-
- if(this._focusedIsWide) {
- newFocusedDotsSize = (isFocused && this._nWindows > 0) ? this._containerSize : 0;
- newFocusedDotsOpacity = 255;
- } else {
- newFocusedDotsSize = this._containerSize;
- newFocusedDotsOpacity = (isFocused && this._nWindows > 0) ? 255 : 0;
- }
-
- if(this._unfocusedIsWide) {
- newUnfocusedDotsSize = (!isFocused && this._nWindows > 0) ? this._containerSize : 0;
- newUnfocusedDotsOpacity = 255;
- } else {
- newUnfocusedDotsSize = this._containerSize;
- newUnfocusedDotsOpacity = (!isFocused && this._nWindows > 0) ? 255 : 0;
- }
-
- // Only animate if...
- // going from a wide style to a narrow style indicator or vice-versa
- // OR going from an open app to a closed app or vice versa
- let animate = (this._focusedIsWide != this._unfocusedIsWide) ||
- (this._focusedDots[sizeProp] != newUnfocusedDotsSize || this._unfocusedDots[sizeProp] != newFocusedDotsSize)
- let duration = animate ? Taskbar.DASH_ANIMATION_TIME : 0.001;
-
- this._animateDotDisplay(this._focusedDots, newFocusedDotsSize, this._unfocusedDots, newUnfocusedDotsOpacity, sizeProp, duration);
- this._animateDotDisplay(this._unfocusedDots, newUnfocusedDotsSize, this._focusedDots, newFocusedDotsOpacity, sizeProp, duration);
- }
- }
-
- _animateDotDisplay(dots, newSize, otherDots, newOtherOpacity, sizeProp, duration) {
- Utils.stopAnimations(dots)
-
- let tweenOpts = {
- time: duration,
- transition: 'easeInOutCubic',
- onComplete: () => {
- if(newOtherOpacity > 0)
- otherDots.opacity = newOtherOpacity;
- }
- };
-
- if(newOtherOpacity == 0)
- otherDots.opacity = newOtherOpacity;
-
- tweenOpts[sizeProp] = newSize;
-
- Utils.animate(dots, tweenOpts);
- }
-
- _isFocusedWindow() {
- let focusedWindow = global.display.focus_window;
-
- while (focusedWindow) {
- if (focusedWindow == this.window) {
- return true;
- }
-
- focusedWindow = focusedWindow.get_transient_for();
- }
-
- return false;
- }
-
- _isWideDotStyle(dotStyle) {
- return dotStyle == DOT_STYLE.SEGMENTED ||
- dotStyle == DOT_STYLE.CILIORA ||
- dotStyle == DOT_STYLE.METRO ||
- dotStyle == DOT_STYLE.SOLID;
- }
-
- _isThemeProvidingIndicator() {
- // This is an attempt to determine if the theme is providing their own
- // running indicator by way of a border image on the icon, for example in
- // the theme Ciliora
- return (this.icon.get_stage() &&
- this.icon.get_theme_node().get_border_image());
- }
-
- activate(button, modifiers, handleAsGrouped) {
- let event = Clutter.get_current_event();
-
- modifiers = event ? event.get_state() : modifiers || 0;
-
- // Only consider SHIFT and CONTROL as modifiers (exclude SUPER, CAPS-LOCK, etc.)
- modifiers = modifiers & (Clutter.ModifierType.SHIFT_MASK | Clutter.ModifierType.CONTROL_MASK);
-
- let ctrlPressed = modifiers & Clutter.ModifierType.CONTROL_MASK
-
- if (ctrlPressed) {
- // CTRL-click or hotkey with ctrl
- return this._launchNewInstance(true);
- }
-
- // We check what type of click we have and if the modifier SHIFT is
- // being used. We then define what buttonAction should be for this
- // event.
- let buttonAction = 0;
- let doubleClick;
-
- if (button && button == 2 ) {
- if (modifiers & Clutter.ModifierType.SHIFT_MASK)
- buttonAction = SETTINGS.get_string('shift-middle-click-action');
- else
- buttonAction = SETTINGS.get_string('middle-click-action');
- }
- // fixed issue #1676 by checking for button 0 or 1 to also handle touchscreen
- // input, probably not the proper fix as i'm not aware button 0 should exist
- // but from using this fix for months it seems to not create any issues
- else if (button === 0 || button === 1) {
- let now = global.get_current_time()
-
- doubleClick = now - this.lastClick < DOUBLE_CLICK_DELAY_MS
- this.lastClick = now
-
- if (modifiers & Clutter.ModifierType.SHIFT_MASK)
- buttonAction = SETTINGS.get_string('shift-click-action');
- else
- buttonAction = SETTINGS.get_string('click-action');
- }
-
- let closePreview = () => this._previewMenu.close(true);
- let appCount = this.getAppIconInterestingWindows().length;
- let previewedAppIcon = this._previewMenu.getCurrentAppIcon();
-
- if (this.window || buttonAction != 'TOGGLE-SHOWPREVIEW')
- closePreview()
-
- // We check if the app is running, and that the # of windows is > 0 in
- // case we use workspace isolation,
- let appIsRunning = this.app.state == Shell.AppState.RUNNING && appCount > 0;
-
- // We customize the action only when the application is already running
- if (appIsRunning && !this.isLauncher) {
- if (this.window && !handleAsGrouped) {
- //ungrouped applications behaviors
- switch (buttonAction) {
- case 'RAISE': case 'CYCLE': case 'CYCLE-MIN': case 'MINIMIZE': case 'TOGGLE-SHOWPREVIEW': case 'TOGGLE-CYCLE':
- if (!Main.overview._shown &&
- (buttonAction == 'MINIMIZE' || buttonAction == 'TOGGLE-SHOWPREVIEW' || buttonAction == 'TOGGLE-CYCLE' || buttonAction == 'CYCLE-MIN') &&
- (this._isFocusedWindow() || (buttonAction == 'MINIMIZE' && (button == 2 || modifiers & Clutter.ModifierType.SHIFT_MASK)))) {
- this.window.minimize();
- } else {
- Main.activateWindow(this.window);
- }
-
- break;
-
- case "LAUNCH":
- this._launchNewInstance();
- break;
-
- case "QUIT":
- this.window.delete(global.get_current_time());
- break;
- }
- } else {
- //grouped application behaviors
- let monitor = this.dtpPanel.monitor;
- let appHasFocus = this._checkIfFocusedApp() && this._checkIfMonitorHasFocus();
-
- switch (buttonAction) {
- case "RAISE":
- activateAllWindows(this.app, monitor);
- break;
-
- case "LAUNCH":
- this._launchNewInstance();
- break;
-
- case "MINIMIZE":
- // In overview just activate the app, unless the acion is explicitely
- // requested with a keyboard modifier
- if (!Main.overview._shown || modifiers){
- // If we have button=2 or a modifier, allow minimization even if
- // the app is not focused
- if (appHasFocus || button == 2 || modifiers & Clutter.ModifierType.SHIFT_MASK) {
- // minimize all windows on double click and always in the case of primary click without
- // additional modifiers
- let all_windows = (button == 1 && ! modifiers) || doubleClick;
- minimizeWindow(this.app, all_windows, monitor);
- }
- else
- activateAllWindows(this.app, monitor);
- }
- else
- this.app.activate();
- break;
-
- case "CYCLE":
- if (!Main.overview._shown){
- if (appHasFocus)
- cycleThroughWindows(this.app, false, false, monitor);
- else {
- activateFirstWindow(this.app, monitor);
- }
- }
- else
- this.app.activate();
- break;
- case "CYCLE-MIN":
- if (!Main.overview._shown){
- if (appHasFocus || (recentlyClickedApp == this.app && recentlyClickedAppWindows[recentlyClickedAppIndex % recentlyClickedAppWindows.length] == "MINIMIZE"))
- cycleThroughWindows(this.app, false, true, monitor);
- else {
- activateFirstWindow(this.app, monitor);
- }
- }
- else
- this.app.activate();
- break;
- case "TOGGLE-SHOWPREVIEW":
- if (!Main.overview._shown) {
- if (appCount == 1) {
- closePreview()
-
- if (appHasFocus)
- minimizeWindow(this.app, false, monitor);
- else
- activateFirstWindow(this.app, monitor);
- } else {
- if (doubleClick) {
- // minimize all windows if double clicked
- closePreview()
- minimizeWindow(this.app, true, monitor);
- } else if (previewedAppIcon != this) {
- this._previewMenu.open(this);
- }
-
- this.emit('sync-tooltip');
- }
- }
- else
- this.app.activate();
- break;
- case "TOGGLE-CYCLE":
- if (!Main.overview._shown) {
- if (appCount == 1) {
- if (appHasFocus)
- minimizeWindow(this.app, false, monitor);
- else
- activateFirstWindow(this.app, monitor);
- } else {
- cycleThroughWindows(this.app, false, false, monitor);
- }
- }
- else
- this.app.activate();
- break;
- case "QUIT":
- closeAllWindows(this.app, monitor);
- break;
- }
- }
- }
- else {
- this._launchNewInstance();
- }
-
- global.display.emit('grab-op-begin', null, null);
- Main.overview.hide();
- }
-
- _launchNewInstance(ctrlPressed) {
- if ((ctrlPressed || this.app.state == Shell.AppState.RUNNING) &&
- this.app.can_open_new_window()) {
- this.animateLaunch();
- this.app.open_new_window(-1);
- } else {
- let windows = this.window ? [this.window] : this.app.get_windows();
-
- if (windows.length) {
- Main.activateWindow(windows[0]);
- } else {
- this.animateLaunch();
- this.app.activate();
- }
- }
- }
-
- _updateWindows() {
- let windows = [this.window];
-
- if (!this.window) {
- windows = this.getAppIconInterestingWindows();
-
- this._nWindows = windows.length;
-
- for (let i = 1; i <= MAX_INDICATORS; i++){
- let className = 'running'+i;
- if(i != this._nWindows)
- this.remove_style_class_name(className);
- else
- this.add_style_class_name(className);
- }
- }
-
- this._previewMenu.update(this, windows);
- }
-
- _getRunningIndicatorCount() {
- return Math.min(this._nWindows, MAX_INDICATORS);
- }
-
- _getRunningIndicatorSize() {
- return DOT_SIZE * Utils.getScaleFactor();
- }
-
- _getRunningIndicatorColor(isFocused) {
- let color;
- const fallbackColor = new Utils.ColorUtils.Color({ red: 82, green: 148, blue: 226, alpha: 255 });
-
- // Re-use the style - background color, and border width and color -
- // of the default dot
- let themeNode = this._dot.get_theme_node();
- color = themeNode.get_background_color();
-
- // theme didn't provide one, use a default
- if(color.alpha == 0) color = fallbackColor;
-
- return color;
- }
-
- _drawRunningIndicator(area, type, isFocused) {
- let n = this._getRunningIndicatorCount();
-
- if (!n) {
- return;
- }
-
- let position = PanelSettings.getPanelPosition(SETTINGS, this.dtpPanel.monitor.index);
- let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM;
- let bodyColor = this._getRunningIndicatorColor(isFocused);
- let [areaWidth, areaHeight] = area.get_surface_size();
- let cr = area.get_context();
- let size = this._getRunningIndicatorSize();
-
- let areaSize = areaWidth;
- let startX = 0;
- let startY = 0;
-
- if (isHorizontalDots) {
- if (position == DOT_POSITION.BOTTOM) {
- startY = areaHeight - size;
- }
- } else {
- areaSize = areaHeight;
-
- if (position == DOT_POSITION.RIGHT) {
- startX = areaWidth - size;
- }
- }
-
- if (type == DOT_STYLE.SOLID || type == DOT_STYLE.METRO) {
- if (type == DOT_STYLE.SOLID || n <= 1) {
- cr.translate(startX, startY);
- cr.setSourceColor(bodyColor);
- cr.newSubPath();
- cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [areaSize, size] : [size, areaSize]));
- cr.fill();
- } else {
- let blackenedLength = (1 / 48) * areaSize; // need to scale with the SVG for the stacked highlight
- let darkenedLength = isFocused ? (2 / 48) * areaSize : (10 / 48) * areaSize;
- let blackenedColor = new Utils.ColorUtils.Color({ red: bodyColor.red * .3, green: bodyColor.green * .3, blue: bodyColor.blue * .3, alpha: bodyColor.alpha });
- let darkenedColor = new Utils.ColorUtils.Color({ red: bodyColor.red * .7, green: bodyColor.green * .7, blue: bodyColor.blue * .7, alpha: bodyColor.alpha });
- let solidDarkLength = areaSize - darkenedLength;
- let solidLength = solidDarkLength - blackenedLength;
-
- cr.translate(startX, startY);
-
- cr.setSourceColor(bodyColor);
- cr.newSubPath();
- cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [solidLength, size] : [size, solidLength]));
- cr.fill();
- cr.setSourceColor(blackenedColor);
- cr.newSubPath();
- cr.rectangle.apply(cr, isHorizontalDots ? [solidLength, 0, 1, size] : [0, solidLength, size, 1]);
- cr.fill();
- cr.setSourceColor(darkenedColor);
- cr.newSubPath();
- cr.rectangle.apply(cr, isHorizontalDots ? [solidDarkLength, 0, darkenedLength, size] : [0, solidDarkLength, size, darkenedLength]);
- cr.fill();
- }
- } else {
- let spacing = Math.ceil(areaSize / 18); // separation between the indicators
- let length;
- let radius;
- let dist;
- let indicatorSize;
- let translate;
- let preDraw = () => {};
- let draw;
- let drawDash = (i, dashLength) => {
- dist = i * dashLength + i * spacing;
- cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0, dashLength, size] : [0, dist, size, dashLength]));
- };
-
- switch (type) {
- // Using the code from Ciliora Round style in pull request https://github.com/home-sweet-gnome/dash-to-panel/pull/1720
- case DOT_STYLE.CILIORA:
- spacing = size;
- radius = size / 2;
- length = areaSize - (size * (n - 1)) - (spacing * (n - 1));
- translate = () => cr.translate(startX, startY);
- preDraw = () => {
- cr.newSubPath();
- cr.arc.apply(cr, (isHorizontalDots ? [radius, radius] : [radius, radius]).concat([radius, 0, 2 * Math.PI]));
- cr.arc.apply(cr, (isHorizontalDots ? [length - radius, radius] : [radius, length - radius]).concat([radius, 0, 2 * Math.PI]));
- cr.rectangle.apply(cr, (isHorizontalDots ? [radius, 0, length - size, size] : [0, radius, size, length - size]));
- };
- draw = i => {
- dist = length + (i * spacing) + ((i - 1) * size) + radius;
- cr.arc.apply(cr, (isHorizontalDots ? [dist, radius] : [radius, dist]).concat([radius, 0, 2 * Math.PI]));
- };
- break;
- case DOT_STYLE.DOTS:
- radius = size / 2;
-
- translate = () => {
- indicatorSize = Math.floor((areaSize - n * size - (n - 1) * spacing) / 2);
- cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]);
- }
- draw = i => {
- dist = (2 * i + 1) * radius + i * spacing;
- cr.arc.apply(cr, (isHorizontalDots ? [dist, radius] : [radius, dist]).concat([radius, 0, 2 * Math.PI]));
- };
- break;
- case DOT_STYLE.SQUARES:
- translate = () => {
- indicatorSize = Math.floor((areaSize - n * size - (n - 1) * spacing) / 2);
- cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]);
- }
- draw = i => {
- dist = i * size + i * spacing;
- cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0] : [0, dist]).concat([size, size]));
- };
- break;
- case DOT_STYLE.DASHES:
- length = Math.floor(areaSize / 4) - spacing;
- translate = () => {
- indicatorSize = Math.floor((areaSize - n * length - (n - 1) * spacing) / 2);
- cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]);
- }
- draw = i => drawDash(i, length);
- break;
- case DOT_STYLE.SEGMENTED:
- length = Math.ceil((areaSize - ((n - 1) * spacing)) / n);
- translate = () => cr.translate(startX, startY);
- draw = i => drawDash(i, length);
- break;
- }
-
- translate();
-
- cr.setSourceColor(bodyColor);
- preDraw();
- for (let i = 0; i < n; i++) {
- cr.newSubPath();
- draw(i);
- }
- cr.fill();
- }
-
- cr.$dispose();
- }
-
- _numberOverlay() {
- // Add label for a Hot-Key visual aid
- this._numberOverlayLabel = new St.Label({ style_class: 'badge' });
- this._numberOverlayBin = new St.Bin({
- child: this._numberOverlayLabel, y: 2
- });
- this._numberOverlayLabel.add_style_class_name('number-overlay');
- this._numberOverlayOrder = -1;
- this._numberOverlayBin.hide();
-
- this._dtpIconContainer.add_child(this._numberOverlayBin);
- }
-
- updateHotkeyNumberOverlay() {
- this.updateNumberOverlay(this._numberOverlayBin, true);
- }
-
- updateNumberOverlay(bin, fixedSize) {
- // We apply an overall scale factor that might come from a HiDPI monitor.
- // Clutter dimensions are in physical pixels, but CSS measures are in logical
- // pixels, so make sure to consider the scale.
- // Set the font size to something smaller than the whole icon so it is
- // still visible. The border radius is large to make the shape circular
- let [minWidth, natWidth] = this._dtpIconContainer.get_preferred_width(-1);
- let font_size = Math.round(Math.max(12, 0.2 * natWidth) / Utils.getScaleFactor());
- let size = Math.round(font_size * 1.3);
- let label = bin.child;
- let style = 'font-size: ' + font_size + 'px;' +
- 'border-radius: ' + this.icon.iconSize + 'px;' +
- 'height: ' + size +'px;';
-
- if (fixedSize) {
- style += 'width: ' + size + 'px;';
- } else {
- style += 'padding: 0.2em 0.5em;';
- }
-
- bin.x = 2;
- label.set_style(style);
- }
-
- setNumberOverlay(number) {
- this._numberOverlayOrder = number;
- this._numberOverlayLabel.set_text(number.toString());
- }
-
- toggleNumberOverlay(activate) {
- if (activate && this._numberOverlayOrder > -1)
- this._numberOverlayBin.show();
- else
- this._numberOverlayBin.hide();
- }
-
- handleDragOver(source, actor, x, y, time) {
- if (source == Main.xdndHandler) {
- this._previewMenu.close(true);
- }
-
- return DND.DragMotionResult.CONTINUE;
- }
-
- getAppIconInterestingWindows(isolateMonitors) {
- return getInterestingWindows(this.app, this.dtpPanel.monitor, isolateMonitors);
- }
-});
-TaskbarAppIcon.prototype.scaleAndFade = TaskbarAppIcon.prototype.undoScaleAndFade = () => {};
-
-export function minimizeWindow(app, param, monitor){
- // Param true make all app windows minimize
- let windows = getInterestingWindows(app, monitor);
- let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace();
- for (let i = 0; i < windows.length; i++) {
- let w = windows[i];
- if (w.get_workspace() == current_workspace && w.showing_on_its_workspace()){
- w.minimize();
- // Just minimize one window. By specification it should be the
- // focused window on the current workspace.
- if(!param)
- break;
- }
- }
-}
-
-/*
- * By default only non minimized windows are activated.
- * This activates all windows in the current workspace.
- */
-export function activateAllWindows(app, monitor){
-
- // First activate first window so workspace is switched if needed,
- // then activate all other app windows in the current workspace.
- let windows = getInterestingWindows(app, monitor);
- let w = windows[0];
- Main.activateWindow(w);
- let activeWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace_index();
-
- if (windows.length <= 0)
- return;
-
- for (let i = windows.length - 1; i >= 0; i--){
- if (windows[i].get_workspace().index() == activeWorkspace){
- Main.activateWindow(windows[i]);
- }
- }
-}
-
-export function activateFirstWindow(app, monitor){
-
- let windows = getInterestingWindows(app, monitor);
- Main.activateWindow(windows[0]);
-}
-
-export function cycleThroughWindows(app, reversed, shouldMinimize, monitor) {
- // Store for a little amount of time last clicked app and its windows
- // since the order changes upon window interaction
- let MEMORY_TIME=3000;
-
- let app_windows = getInterestingWindows(app, monitor);
-
- if(shouldMinimize)
- app_windows.push("MINIMIZE");
-
- if (recentlyClickedAppLoopId > 0)
- GLib.Source.remove(recentlyClickedAppLoopId);
-
- recentlyClickedAppLoopId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
- MEMORY_TIME, resetRecentlyClickedApp);
-
- // If there isn't already a list of windows for the current app,
- // or the stored list is outdated, use the current windows list.
- if (!recentlyClickedApp ||
- recentlyClickedApp.get_id() != app.get_id() ||
- recentlyClickedAppWindows.length != app_windows.length ||
- recentlyClickedAppMonitorIndex != monitor.index) {
- recentlyClickedApp = app;
- recentlyClickedAppWindows = app_windows;
- recentlyClickedAppIndex = 0;
- recentlyClickedAppMonitorIndex = monitor.index;
- }
-
- if (reversed) {
- recentlyClickedAppIndex--;
- if (recentlyClickedAppIndex < 0) recentlyClickedAppIndex = recentlyClickedAppWindows.length - 1;
- } else {
- recentlyClickedAppIndex++;
- }
- let index = recentlyClickedAppIndex % recentlyClickedAppWindows.length;
-
- if(recentlyClickedAppWindows[index] === "MINIMIZE")
- minimizeWindow(app, true, monitor);
- else
- Main.activateWindow(recentlyClickedAppWindows[index]);
-}
-
-export function resetRecentlyClickedApp() {
- if (recentlyClickedAppLoopId > 0)
- GLib.Source.remove(recentlyClickedAppLoopId);
-
- recentlyClickedAppLoopId=0;
- recentlyClickedApp =null;
- recentlyClickedAppWindows = null;
- recentlyClickedAppIndex = 0;
- recentlyClickedAppMonitorIndex = null;
-
- return false;
-}
-
-export function closeAllWindows(app, monitor) {
- let windows = getInterestingWindows(app, monitor);
- for (let i = 0; i < windows.length; i++)
- windows[i].delete(global.get_current_time());
-}
-
-// Filter out unnecessary windows, for instance
-// nautilus desktop window.
-export function getInterestingWindows(app, monitor, isolateMonitors) {
- let windows = (
- app ?
- app.get_windows() :
- global.get_window_actors().map(wa => wa.get_meta_window())
- ).filter(w => !w.skip_taskbar);
-
- // When using workspace or monitor isolation, we filter out windows
- // that are not in the current workspace or on the same monitor as the appicon
- if (SETTINGS.get_boolean('isolate-workspaces'))
- windows = windows.filter(function(w) {
- return w.get_workspace() &&
- w.get_workspace() == Utils.getCurrentWorkspace();
- });
-
- if (monitor && SETTINGS.get_boolean('multi-monitors') && (isolateMonitors || SETTINGS.get_boolean('isolate-monitors'))) {
- windows = windows.filter(function(w) {
- return w.get_monitor() == monitor.index;
- });
- }
-
- return windows;
-}
-
-export function cssHexTocssRgba(cssHex, opacity) {
- let bigint = parseInt(cssHex.slice(1), 16);
- let r = (bigint >> 16) & 255;
- let g = (bigint >> 8) & 255;
- let b = bigint & 255;
-
- return 'rgba(' + [r, g, b].join(',') + ',' + opacity + ')';
-}
-
-export function getIconPadding(monitorIndex) {
- let panelSize = PanelSettings.getPanelSize(SETTINGS, monitorIndex);
- let padding = Taskbar.APPICON_PADDING;
- let availSize = panelSize - Taskbar.MIN_ICON_SIZE - panelSize % 2;
-
- if (padding * 2 > availSize) {
- padding = availSize * .5;
- }
-
- return padding;
-}
-
-/**
- * Extend AppMenu (AppIconMenu for pre gnome 41)
- *
- * - hide 'Show Details' according to setting
- * - show windows header only if show-window-previews is disabled
- * - Add close windows option based on quitfromdash extension
- * (https://github.com/deuill/shell-extension-quitfromdash)
- */
-
-export class TaskbarSecondaryMenu extends AppMenu.AppMenu {
-
- constructor(source, side) {
- super(source, side);
- // constructor parameter does nos work for some reason
- this._enableFavorites = true;
- this._showSingleWindows = true;
-
- // replace quit item
- delete this._quitItem;
- this._quitItem = this.addAction(_('Quit'), () => this._quitFromTaskbar());
- }
-
- updateQuitText() {
- let count = this.sourceActor.window ? 1 :
- getInterestingWindows(this._app, this.sourceActor.dtpPanel.monitor).length;
-
- if ( count > 0) {
- let quitFromTaskbarMenuText = "";
- if (count == 1)
- quitFromTaskbarMenuText = _("Quit");
- else
- quitFromTaskbarMenuText = ngettext('Quit %d Window', 'Quit %d Windows', count).format(count);
-
- this._quitItem.label.set_text(quitFromTaskbarMenuText);
- }
- }
-
- _quitFromTaskbar() {
- let time = global.get_current_time()
- let windows =
- this.sourceActor.window ? // ungrouped applications
- [this.sourceActor.window] :
- getInterestingWindows(this._app, this.sourceActor.dtpPanel.monitor)
-
- if (windows.length == this._app.get_windows().length)
- this._app.request_quit()
-
- GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
- windows.forEach((w) => !!w.get_compositor_private() && w.delete(time++));
-
- return GLib.SOURCE_REMOVE;
- });
- }
-};
-
-/**
- * This function is used for extendDashItemContainer
- */
-export function ItemShowLabel() {
- if (!this._labelText)
- return;
-
- this.label.set_text(this._labelText);
- this.label.opacity = 0;
- this.label.show();
-
- let [stageX, stageY] = this.get_transformed_position();
- let node = this.label.get_theme_node();
-
- let itemWidth = this.allocation.x2 - this.allocation.x1;
- let itemHeight = this.allocation.y2 - this.allocation.y1;
-
- let labelWidth = this.label.get_width();
- let labelHeight = this.label.get_height();
-
- let position = this._dtpPanel.getPosition();
- let labelOffset = node.get_length('-x-offset');
-
- let xOffset = Math.floor((itemWidth - labelWidth) / 2);
- let x = stageX + xOffset
- let y = stageY + (itemHeight - labelHeight) * .5;
-
- switch(position) {
- case St.Side.TOP:
- y = stageY + labelOffset + itemHeight;
- break;
- case St.Side.BOTTOM:
- y = stageY - labelHeight - labelOffset;
- break;
- case St.Side.LEFT:
- x = stageX + labelOffset + itemWidth;
- break;
- case St.Side.RIGHT:
- x = stageX - labelWidth - labelOffset;
- break;
- }
-
- // keep the label inside the screen border
- // Only needed for the x coordinate.
-
- // Leave a few pixel gap
- let gap = LABEL_GAP;
- let monitor = Main.layoutManager.findMonitorForActor(this);
- if ( x - monitor.x < gap)
- x += monitor.x - x + labelOffset;
- else if ( x + labelWidth > monitor.x + monitor.width - gap)
- x -= x + labelWidth -( monitor.x + monitor.width) + gap;
-
- this.label.set_position(Math.round(x), Math.round(y));
-
- let duration = Dash.DASH_ITEM_LABEL_SHOW_TIME;
-
- if (duration > 1) {
- duration /= 1000;
- }
-
- Utils.animate(this.label, {
- opacity: 255,
- time: duration,
- transition: 'easeOutQuad',
- });
-}
-
-/**
- * A wrapper class around the ShowAppsIcon class.
- *
- * - Pass settings to the constructor
- * - set label position based on dash orientation (Note, I am reusing most machinery of the appIcon class)
- * - implement a popupMenu based on the AppIcon code (Note, I am reusing most machinery of the appIcon class)
- *
- * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973.
- * thus use this pattern where the real showAppsIcon object is encaptulated, and a reference to it will be properly wired upon
- * use of this class in place of the original showAppsButton.
- *
- */
-export const ShowAppsIconWrapper = class extends EventEmitter {
-
- constructor(dtpPanel) {
- super();
-
- this.realShowAppsIcon = new Dash.ShowAppsIcon();
-
- /* the variable equivalent to toggleButton has a different name in the appIcon class
- (actor): duplicate reference to easily reuse appIcon methods */
- this.actor = this.realShowAppsIcon.toggleButton;
- this.realShowAppsIcon.show(false);
-
- // Re-use appIcon methods
- this._removeMenuTimeout = AppDisplay.AppIcon.prototype._removeMenuTimeout;
- this._setPopupTimeout = AppDisplay.AppIcon.prototype._setPopupTimeout;
- this._onKeyboardPopupMenu = AppDisplay.AppIcon.prototype._onKeyboardPopupMenu;
-
- // No action on clicked (showing of the appsview is controlled elsewhere)
- this._onClicked = (actor, button) => this._removeMenuTimeout();
-
- this.actor.connect('leave-event', this._onLeaveEvent.bind(this));
- this.actor.connect('button-press-event', this._onButtonPress.bind(this));
- this.actor.connect('touch-event', this._onTouchEvent.bind(this));
- this.actor.connect('clicked', this._onClicked.bind(this));
- this.actor.connect('popup-menu', this._onKeyboardPopupMenu.bind(this));
-
- this._menu = null;
- this._menuManager = new PopupMenu.PopupMenuManager(this.actor);
- this._menuTimeoutId = 0;
-
- this.realShowAppsIcon._dtpPanel = dtpPanel;
- Taskbar.extendDashItemContainer(this.realShowAppsIcon);
-
- this.realShowAppsIcon.icon.createIcon = function(size) {
- this._iconActor = new St.Icon({ icon_name: 'view-app-grid-symbolic',
- icon_size: size,
- style_class: 'show-apps-icon',
- track_hover: true });
-
- return this._iconActor;
- };
-
- this.setShowAppsPadding();
- }
-
- _onButtonPress(_actor, event) {
- let button = event.get_button();
- if (button == 1) {
- this._setPopupTimeout();
- } else if (button == 3) {
- this.popupMenu();
- return Clutter.EVENT_STOP;
- }
- return Clutter.EVENT_PROPAGATE;
- }
-
- _onLeaveEvent(_actor, _event) {
- this.actor.fake_release();
- this._removeMenuTimeout();
- }
-
- _onTouchEvent(actor, event) {
- if (event.type() == Clutter.EventType.TOUCH_BEGIN)
- this._setPopupTimeout();
-
- return Clutter.EVENT_PROPAGATE;
- }
-
- _onMenuPoppedDown() {
- this._menu.sourceActor = this.actor;
- this.actor.sync_hover();
- this.emit('menu-state-changed', false);
- }
-
- setShowAppsPadding() {
- let padding = getIconPadding(this.realShowAppsIcon._dtpPanel.monitor.index);
-
- this.actor.set_style('padding:' + padding + 'px;');
- }
-
- createMenu() {
- if (!this._menu) {
- this._menu = new MyShowAppsIconMenu(this.realShowAppsIcon, this.realShowAppsIcon._dtpPanel);
- this._menu.connect('open-state-changed', (menu, isPoppedUp) => {
- if (!isPoppedUp)
- this._onMenuPoppedDown();
- });
- let id = Main.overview.connect('hiding', () => {
- this._menu.close();
- });
- this._menu.actor.connect('destroy', () => {
- Main.overview.disconnect(id);
- });
-
- // We want to keep the item hovered while the menu is up
- this._menu.blockSourceEvents = true;
-
- Main.uiGroup.add_child(this._menu.actor);
- this._menuManager.addMenu(this._menu);
- }
- }
-
- popupMenu(sourceActor = null) {
- this._removeMenuTimeout();
- this.actor.fake_release();
- this.createMenu();
-
- this._menu.updateItems(sourceActor == null ? this.realShowAppsIcon : sourceActor);
-
- this.actor.set_hover(true);
- this._menu.open(BoxPointer.PopupAnimation.FULL);
- this._menuManager.ignoreRelease();
- this.emit('sync-tooltip');
-
- return false;
- }
-
- shouldShowTooltip() {
- return SETTINGS.get_boolean('show-tooltip') &&
- (this.actor.hover && (!this._menu || !this._menu.isOpen));
- }
-
- destroy() {
- this.realShowAppsIcon.destroy();
- }
-};
-
-/**
- * A menu for the showAppsIcon
- */
-export const MyShowAppsIconMenu = class extends PopupMenu.PopupMenu {
-
- constructor(actor, dtpPanel) {
- super(actor, 0, dtpPanel.getPosition());
-
- this._dtpPanel = dtpPanel;
-
- this.updateItems(actor);
- }
-
- updateItems(sourceActor) {
- this.sourceActor = sourceActor;
-
- this.removeAll();
-
- this._appendItem({
- title: _('System Monitor'),
- cmd: ['gnome-system-monitor']
- });
-
- this._appendItem({
- title: _('Files'),
- cmd: ['nautilus']
- });
-
- this._appendItem({
- title: _('Settings'),
- cmd: ['gnome-control-center']
- });
-
- this._appendItem({
- title: _('Zorin Appearance'),
- cmd: ['zorin-appearance']
- });
-
- this._appendList(
- SETTINGS.get_strv('panel-context-menu-commands'),
- SETTINGS.get_strv('panel-context-menu-titles')
- )
-
- this._appendSeparator();
-
- let lockTaskbarMenuItem = this._appendMenuItem(SETTINGS.get_boolean('taskbar-locked') ? _('Unlock taskbar') : _('Lock taskbar'));
- lockTaskbarMenuItem.connect('activate', () => {
- SETTINGS.set_boolean('taskbar-locked', !SETTINGS.get_boolean('taskbar-locked'));
- });
-
- let settingsMenuItem = this._appendMenuItem(_('Taskbar Settings'));
- settingsMenuItem.connect('activate', () => DTP_EXTENSION.openPreferences())
-
- if(this.sourceActor == Main.layoutManager.dummyCursor) {
- this._appendSeparator();
- let item = this._appendMenuItem(this._dtpPanel._restoreWindowList ? _('Restore Windows') : _('Show Desktop'));
- item.connect('activate', this._dtpPanel._onShowDesktopButtonPress.bind(this._dtpPanel));
- }
- }
-
-
- // Only add menu entries for commands that exist in path
- _appendItem(info) {
- if (GLib.find_program_in_path(info.cmd[0])) {
- let item = this._appendMenuItem(_(info.title));
-
- item.connect('activate', function() {
- print("activated: " + info.title);
- Util.spawn(info.cmd);
- });
- return item;
- }
-
- return null;
- }
-
- _appendList(commandList, titleList) {
- if (commandList.length != titleList.length) {
- return;
- }
-
- for (let entry = 0; entry < commandList.length; entry++) {
- this._appendItem({
- title: titleList[entry],
- cmd: commandList[entry].split(' ')
- });
- }
- }
-
- _appendSeparator() {
- let separator = new PopupMenu.PopupSeparatorMenuItem();
- this.addMenuItem(separator);
- }
-
- _appendMenuItem(labelText) {
- // FIXME: app-well-menu-item style
- let item = new PopupMenu.PopupMenuItem(labelText);
- this.addMenuItem(item);
- return item;
- }
-};
-
-
-export const getIconContainerStyle = function(isVertical) {
- let style = 'padding: ';
-
- if (SETTINGS.get_boolean('group-apps')) {
- style += (isVertical ? '0;' : '0 ' + DEFAULT_PADDING_SIZE + 'px;');
- } else {
- style += (isVertical ? '' : '0 ') + DEFAULT_PADDING_SIZE + 'px;';
- }
-
- return style;
-}
diff --git a/debian/changelog b/debian/changelog
index 7ee9cf7..50a41a3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,21 @@
+gnome-shell-extension-zorin-taskbar (68.1) noble; urgency=medium
+
+ * Adjusted app icon margins and padding
+
+ -- Artyom Zorin 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 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 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
diff --git a/desktopIconsIntegration.js b/desktopIconsIntegration.js
deleted file mode 100644
index e403516..0000000
--- a/desktopIconsIntegration.js
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * The code in this file is distributed under a "1-clause BSD license",
- * which makes it compatible with GPLv2 and GPLv3 too, and others.
- *
- * License text:
- *
- * Copyright (C) 2021 Sergio Costas (rastersoft@gmail.com)
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*******************************************************************************
- * Integration class
- *
- * This class must be added to other extensions in order to integrate
- * them with Desktop Icons NG. It allows an extension to notify how much margin
- * it uses in each side of each monitor.
- *
- * DON'T SEND PATCHES TO THIS FILE TO THE EXTENSION MAINTAINER. SEND THEM TO
- * DESKTOP ICONS NG MAINTAINER: https://gitlab.com/rastersoft/desktop-icons-ng
- *
- * In the *enable()* function, create a *DesktopIconsUsableAreaClass()*
- * object with
- *
- * new DesktopIconsIntegration.DesktopIconsUsableAreaClass(object);
- *
- * Now, in the *disable()* function just call to the *destroy()* method before
- * nullifying the pointer. You must create a new object in enable() the next
- * time the extension is enabled.
- *
- * In your code, every time you change the margins, you should call first to
- * *resetMargins()* method to clear the current margins, and then call to
- * *setMargins(...)* method as many times as you need to set the margins in each
- * monitor. You don't need to call it for all the monitors, only for those where
- * you are painting something. If you don't set values for a monitor, they will
- * be considered zero.
- *
- * The margins values are relative to the monitor border.
- *
- *******************************************************************************/
-
-import GLib from 'gi://GLib';
-import * as Main from 'resource:///org/gnome/shell/ui/main.js';
-import * as ExtensionUtils from 'resource:///org/gnome/shell/misc/extensionUtils.js';
-import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
-
-const IDENTIFIER_UUID = "130cbc66-235c-4bd6-8571-98d2d8bba5e2";
-
-export class DesktopIconsUsableAreaClass {
- _checkIfExtensionIsEnabled(extension) {
- return (extension?.state === ExtensionUtils.ExtensionState.ENABLED) ||
- (extension?.state === ExtensionUtils.ExtensionState.ACTIVE);
- }
-
- constructor() {
- const Me = Extension.lookupByURL(import.meta.url);
- this._UUID = Me.uuid;
- this._extensionManager = Main.extensionManager;
- this._timedMarginsID = 0;
- this._margins = {};
- this._emID = this._extensionManager.connect('extension-state-changed', (_obj, extension) => {
- if (!extension)
- return;
-
- // If an extension is being enabled and lacks the DesktopIconsUsableArea object, we can avoid launching a refresh
- if (this._checkIfExtensionIsEnabled(extension)) {
- this._sendMarginsToExtension(extension);
- return;
- }
- // if the extension is being disabled, we must do a full refresh, because if there were other extensions originally
- // loaded after that extension, those extensions will be disabled and enabled again without notification
- this._changedMargins();
- });
- }
-
- /**
- * Sets or updates the top, bottom, left and right margins for a
- * monitor. Values are measured from the monitor border (and NOT from
- * the workspace border).
- *
- * @param {int} monitor Monitor number to which set the margins.
- * A negative value means "the primary monitor".
- * @param {int} top Top margin in pixels
- * @param {int} bottom Bottom margin in pixels
- * @param {int} left Left margin in pixels
- * @param {int} right Right margin in pixels
- */
- setMargins(monitor, top, bottom, left, right) {
- this._margins[monitor] = {
- 'top': top,
- 'bottom': bottom,
- 'left': left,
- 'right': right
- };
- this._changedMargins();
- }
-
- /**
- * Clears the current margins. Must be called before configuring the monitors
- * margins with setMargins().
- */
- resetMargins() {
- this._margins = {};
- this._changedMargins();
- }
-
- /**
- * Disconnects all the signals and removes the margins.
- */
- destroy() {
- if (this._emID) {
- this._extensionManager.disconnect(this._emID);
- this._emID = 0;
- }
- if (this._timedMarginsID) {
- GLib.source_remove(this._timedMarginsID);
- this._timedMarginsID = 0;
- }
- this._margins = null;
- this._changedMargins();
- }
-
- _changedMargins() {
- if (this._timedMarginsID) {
- GLib.source_remove(this._timedMarginsID);
- }
- this._timedMarginsID = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, ()=> {
- this._sendMarginsToAll();
- this._timedMarginsID = 0;
- return GLib.SOURCE_REMOVE;
- });
- }
-
- _sendMarginsToAll() {
- this._extensionManager.getUuids().forEach(uuid =>
- this._sendMarginsToExtension(this._extensionManager.lookup(uuid)));
- }
-
- _sendMarginsToExtension(extension) {
- // check that the extension is an extension that has the logic to accept
- // working margins
- if (!this._checkIfExtensionIsEnabled(extension))
- return;
-
- const usableArea = extension?.stateObj?.DesktopIconsUsableArea;
- if (usableArea?.uuid === IDENTIFIER_UUID)
- usableArea.setMarginsForExtension(this._UUID, this._margins);
- }
-}
diff --git a/extension.js b/extension.js
deleted file mode 100644
index 9cf6ed9..0000000
--- a/extension.js
+++ /dev/null
@@ -1,132 +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 .
- *
- */
-
-
-import Gio from 'gi://Gio';
-
-import * as Main from 'resource:///org/gnome/shell/ui/main.js';
-import {EventEmitter} from 'resource:///org/gnome/shell/misc/signals.js';
-import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
-
-import * as PanelManager from './panelManager.js';
-import * as AppIcons from './appIcons.js';
-
-
-const ZORIN_DASH_UUID = 'zorin-dash@zorinos.com';
-
-let panelManager;
-let extensionChangedHandler;
-let startupCompleteHandler;
-let disabledZorinDash;
-let extensionSystem = Main.extensionManager;
-
-export let DTP_EXTENSION = null;
-export let SETTINGS = null;
-export let DESKTOPSETTINGS = null;
-export let TERMINALSETTINGS = null;
-export let PERSISTENTSTORAGE = null;
-export let EXTENSION_UUID = null;
-export let EXTENSION_PATH = null;
-
-export default class ZorinTaskbarExtension extends Extension {
- constructor(metadata) {
- super(metadata);
-
- this._realHasOverview = Main.sessionMode.hasOverview;
-
- //create an object that persists until gnome-shell is restarted, even if the extension is disabled
- PERSISTENTSTORAGE = {};
- }
-
- enable() {
- DTP_EXTENSION = this;
-
- // The 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(this);
- }
- });
-
- //create a global object that can emit signals and conveniently expose functionalities to other extensions
- global.zorinTaskbar = new EventEmitter();
-
- _enable(this);
- }
-
- disable(reset = false) {
- panelManager.disable();
-
- DTP_EXTENSION = null;
- SETTINGS = null;
- DESKTOPSETTINGS = null;
- TERMINALSETTINGS = null;
- panelManager = null;
-
- if (!reset) {
- extensionSystem.disconnect(extensionChangedHandler);
-
- if (disabledZorinDash) {
- disabledZorinDash = false;
- extensionSystem.enableExtension(ZORIN_DASH_UUID);
- }
-
- delete global.zorinTaskbar;
-
- AppIcons.resetRecentlyClickedApp();
- }
-
- if (startupCompleteHandler) {
- Main.layoutManager.disconnect(startupCompleteHandler);
- startupCompleteHandler = null;
- }
-
- Main.sessionMode.hasOverview = this._realHasOverview;
- }
-}
-
-function _enable(extension) {
- let enabled = global.settings.get_strv('enabled-extensions');
-
- if (enabled?.indexOf(ZORIN_DASH_UUID) >= 0) {
- disabledZorinDash = true;
- extensionSystem.disableExtension(ZORIN_DASH_UUID);
- }
-
- if (panelManager)
- return panelManager.toggleDash(); // already initialized but Zorin Dash restored the original dash on disable
-
- SETTINGS = extension.getSettings('org.gnome.shell.extensions.zorin-taskbar');
- DESKTOPSETTINGS = new Gio.Settings({schema_id: 'org.gnome.desktop.interface'});
- TERMINALSETTINGS = new Gio.Settings({schema_id: 'org.gnome.desktop.default-applications.terminal'})
- EXTENSION_UUID = extension.uuid
- EXTENSION_PATH = extension.path
-
- Main.layoutManager.startInOverview = false;
-
- if (Main.layoutManager._startingUp) {
- Main.sessionMode.hasOverview = false;
- startupCompleteHandler = Main.layoutManager.connect('startup-complete', () => {
- Main.sessionMode.hasOverview = extension._realHasOverview
- });
- }
-
- panelManager = new PanelManager.PanelManager();
-
- panelManager.enable();
-}
diff --git a/intellihide.js b/intellihide.js
deleted file mode 100644
index f8cdb0f..0000000
--- a/intellihide.js
+++ /dev/null
@@ -1,434 +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 .
- *
- * Credits:
- * This file is based on code from the Dash to Panel extension
- */
-
-import Clutter from 'gi://Clutter';
-import Meta from 'gi://Meta';
-import Shell from 'gi://Shell';
-import St from 'gi://St';
-
-import * as GrabHelper from 'resource:///org/gnome/shell/ui/grabHelper.js';
-import * as Layout from 'resource:///org/gnome/shell/ui/layout.js';
-import * as Main from 'resource:///org/gnome/shell/ui/main.js';
-import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js';
-import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.js';
-
-import * as Proximity from './proximity.js';
-import * as Utils from './utils.js';
-import {SETTINGS} from './extension.js';
-
-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 SIDE_CONTROLS_ANIMATION_TIME = OverviewControls.SIDE_CONTROLS_ANIMATION_TIME / (OverviewControls.SIDE_CONTROLS_ANIMATION_TIME > 1 ? 1000 : 1);
-
-export const Hold = {
- NONE: 0,
- TEMPORARY: 1,
- PERMANENT: 2
-};
-
-export const Intellihide = class {
-
- constructor(dtpPanel) {
- this._dtpPanel = dtpPanel;
- this._panelBox = dtpPanel.panelBox;
- this._panelManager = dtpPanel.panelManager;
- this._proximityManager = this._panelManager.proximityManager;
- this._holdStatus = Hold.NONE;
-
- this._signalsHandler = new Utils.GlobalSignalsHandler();
- this._timeoutsHandler = new Utils.TimeoutsHandler();
-
- this._intellihideChangedId = SETTINGS.connect('changed::intellihide', () => this._changeEnabledStatus());
- this._intellihideOnlySecondaryChangedId = SETTINGS.connect('changed::intellihide-only-secondary', () => this._changeEnabledStatus());
-
- this.enabled = false;
- this._changeEnabledStatus();
- }
-
- enable() {
- this.enabled = true;
- this._monitor = this._dtpPanel.monitor;
- this._animationDestination = -1;
- this._pendingUpdate = false;
- this._hoveredOut = false;
- this._windowOverlap = false;
- this._translationProp = 'translation_' + (this._dtpPanel.checkIfVertical() ? 'x' : 'y');
-
- this._panelBox.translation_y = 0;
- this._panelBox.translation_x = 0;
-
- this._setTrackPanel(true);
- this._bindGeneralSignals();
-
- if (SETTINGS.get_boolean('intellihide-hide-from-windows')) {
- this._proximityWatchId = this._proximityManager.createWatch(
- this._panelBox.get_parent(),
- this._dtpPanel.monitor.index,
- Proximity.Mode[SETTINGS.get_string('intellihide-behaviour')],
- 0, 0,
- overlap => {
- this._windowOverlap = overlap;
- this._queueUpdatePanelPosition();
- }
- );
- }
-
- this._setRevealMechanism();
- this._queueUpdatePanelPosition();
- }
-
- disable(reset) {
- if (this._proximityWatchId) {
- this._proximityManager.removeWatch(this._proximityWatchId);
- }
-
- this._setTrackPanel(false);
-
- this._signalsHandler.destroy();
- this._timeoutsHandler.destroy();
-
- this._removeRevealMechanism();
-
- this._revealPanel(!reset);
-
- this.enabled = false;
- }
-
- destroy() {
- SETTINGS.disconnect(this._intellihideChangedId);
- SETTINGS.disconnect(this._intellihideOnlySecondaryChangedId);
-
- if (this.enabled) {
- this.disable();
- }
- }
-
- toggle() {
- this[this._holdStatus & Hold.PERMANENT ? 'release' : 'revealAndHold'](Hold.PERMANENT);
- }
-
- revealAndHold(holdStatus) {
- if (this.enabled && !this._holdStatus) {
- this._revealPanel();
- }
-
- this._holdStatus |= holdStatus;
- }
-
- release(holdStatus) {
- this._holdStatus -= holdStatus;
-
- if (this.enabled && !this._holdStatus) {
- this._queueUpdatePanelPosition();
- }
- }
-
- reset() {
- this.disable(true);
- this.enable();
- }
-
- _changeEnabledStatus() {
- let intellihide = SETTINGS.get_boolean('intellihide');
- let onlySecondary = SETTINGS.get_boolean('intellihide-only-secondary');
- let enabled = intellihide && !(this._dtpPanel.isPrimary && onlySecondary);
-
- if (this.enabled !== enabled) {
- this[enabled ? 'enable' : 'disable']();
- }
- }
-
- _bindGeneralSignals() {
- this._signalsHandler.add(
- [
- this._dtpPanel.taskbar,
- ['menu-closed', 'end-drag'],
- () => {
- this._panelBox.sync_hover();
- this._onHoverChanged();
- }
- ],
- [
- SETTINGS,
- [
- 'changed::intellihide-use-pressure',
- 'changed::intellihide-hide-from-windows',
- 'changed::intellihide-behaviour'
- ],
- () => this.reset()
- ],
- [
- this._panelBox,
- 'notify::hover',
- () => this._onHoverChanged()
- ],
- [
- this._dtpPanel.taskbar.previewMenu,
- 'open-state-changed',
- () => this._queueUpdatePanelPosition()
- ],
- [
- Main.overview,
- [
- 'showing',
- 'hiding'
- ],
- () => this._queueUpdatePanelPosition()
- ]
- );
-
- if (Meta.is_wayland_compositor()) {
- this._signalsHandler.add([
- this._panelBox,
- 'notify::visible',
- () => Utils.setDisplayUnredirect(!this._panelBox.visible)
- ]);
- }
- }
-
- _onHoverChanged() {
- this._hoveredOut = !this._panelBox.hover;
- this._queueUpdatePanelPosition();
- }
-
- _setTrackPanel(enable) {
- let actorData = Utils.getTrackedActorData(this._panelBox)
-
- actorData.affectsStruts = !enable;
- actorData.trackFullscreen = !enable;
-
- this._panelBox.track_hover = enable;
- this._panelBox.reactive = enable;
- this._panelBox.visible = enable ? enable : this._panelBox.visible;
-
- Main.layoutManager._queueUpdateRegions();
- }
-
- _setRevealMechanism() {
- let barriers = Meta.BackendCapabilities.BARRIERS
-
- if ((global.backend.capabilities & barriers) === barriers && SETTINGS.get_boolean('intellihide-use-pressure')) {
- this._edgeBarrier = this._createBarrier();
- this._pressureBarrier = new Layout.PressureBarrier(
- 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 SETTINGS.get_boolean('intellihide-show-in-fullscreen');
- }
-
- return !mouseBtnIsPressed;
- }
-
- if (!SETTINGS.get_boolean('intellihide-hide-from-windows')) {
- return this._panelBox.hover;
- }
-
- return !this._windowOverlap;
- }
-
- _checkIfGrab() {
- let isGrab
-
- if (GrabHelper._grabHelperStack)
- // gnome-shell < 42
- isGrab = GrabHelper._grabHelperStack.some(gh => gh._owner == this._dtpPanel.panel)
- else if (global.stage.get_grab_actor) {
- // gnome-shell >= 42
- let grabActor = global.stage.get_grab_actor()
- let sourceActor = grabActor?._sourceActor || grabActor
-
- isGrab = sourceActor &&
- (sourceActor == Main.layoutManager.dummyCursor ||
- this._dtpPanel.statusArea.quickSettings?.menu.actor.contains(sourceActor) ||
- this._dtpPanel.panel.contains(sourceActor))
- }
-
- if (isGrab)
- //there currently is a grab on a child of the panel, check again soon to catch its release
- this._timeoutsHandler.add([T1, CHECK_GRAB_MS, () => this._queueUpdatePanelPosition()]);
-
- return isGrab;
- }
-
- _revealPanel(immediate) {
- if (!this._panelBox.visible) {
- this._panelBox.visible = true;
- this._dtpPanel.taskbar._shownInitially = false;
- }
-
- this._animatePanel(0, immediate);
- }
-
- _hidePanel(immediate) {
- let position = this._dtpPanel.geom.position;
- let size = this._panelBox[position == St.Side.LEFT || position == St.Side.RIGHT ? 'width' : 'height'];
- let coefficient = position == St.Side.TOP || position == St.Side.LEFT ? -1 : 1;
-
- this._animatePanel(size * coefficient, immediate);
- }
-
- _animatePanel(destination, immediate) {
- let animating = Utils.isAnimating(this._panelBox, this._translationProp);
-
- if (!((animating && destination === this._animationDestination) ||
- (!animating && destination === this._panelBox[this._translationProp]))) {
- //the panel isn't already at, or animating to the asked destination
- if (animating) {
- Utils.stopAnimations(this._panelBox);
- }
-
- this._animationDestination = destination;
-
- if (immediate) {
- this._panelBox[this._translationProp] = destination;
- this._panelBox.visible = !destination;
- } else {
- let tweenOpts = {
- //when entering/leaving the overview, use its animation time instead of the one from the settings
- time: Main.overview.visible ?
- SIDE_CONTROLS_ANIMATION_TIME :
- 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;
- }
-}
diff --git a/metadata.json b/metadata.json
index 0eef43e..358e6d7 100644
--- a/metadata.json
+++ b/metadata.json
@@ -3,7 +3,7 @@
"uuid": "zorin-taskbar@zorinos.com",
"name": "Zorin Taskbar",
"description": "A taskbar extension for the Zorin OS desktop.",
- "shell-version": [ "46", "47" ],
+ "shell-version": [ "46", "47", "48" ],
"gettext-domain": "zorin-taskbar",
- "version": 65
+ "version": 68
}
diff --git a/overview.js b/overview.js
deleted file mode 100644
index 2e3c20d..0000000
--- a/overview.js
+++ /dev/null
@@ -1,455 +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 .
- *
- * 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_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';
-
-export const Overview = class {
-
- constructor() {
- this._injectionManager = new InjectionManager();
- this._numHotkeys = 10;
- }
-
- enable (primaryPanel) {
- this._panel = primaryPanel;
- this.taskbar = primaryPanel.taskbar;
-
- this._injectionsHandler = new Utils.InjectionsHandler();
- this._signalsHandler = new Utils.GlobalSignalsHandler();
- this._timeoutsHandler = new Utils.TimeoutsHandler();
-
- this._optionalWorkspaceIsolation();
- this._optionalHotKeys();
- this._optionalNumberOverlay();
-
- this.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.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
- }
-
- originalAllocate.call(overviewControls, box)
- }
- );
- }
-
- /**
- * Isolate overview to open new windows for inactive apps
- */
- _optionalWorkspaceIsolation() {
- let label = 'optionalWorkspaceIsolation';
-
- let enable = () => {
- this._injectionsHandler.removeWithLabel(label);
-
- this._injectionsHandler.addWithLabel(label, [
- Shell.App.prototype,
- 'activate',
- IsolatedOverview
- ]);
-
- this._signalsHandler.removeWithLabel(label);
-
- this._signalsHandler.addWithLabel(label, [
- global.window_manager,
- 'switch-workspace',
- () => this._panel.panelManager.allPanels.forEach(p => p.taskbar.handleIsolatedWorkspaceSwitch())
- ]);
- }
-
- let disable = () => {
- this._signalsHandler.removeWithLabel(label);
- this._injectionsHandler.removeWithLabel(label);
- }
-
- function IsolatedOverview() {
- // These lines take care of Nautilus for icons on Desktop
- let activeWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace();
- let windows = this.get_windows().filter(w => w.get_workspace().index() == activeWorkspace.index());
-
- if (windows.length > 0 &&
- (!(windows.length == 1 && windows[0].skip_taskbar) ||
- this.is_on_workspace(activeWorkspace)))
- return Main.activateWindow(windows[0]);
-
- return this.open_new_window(-1);
- }
-
- this._signalsHandler.add([
- SETTINGS,
- 'changed::isolate-workspaces',
- () => {
- this._panel.panelManager.allPanels.forEach(p => p.taskbar.resetAppIcons());
-
- if (SETTINGS.get_boolean('isolate-workspaces'))
- enable();
- else
- disable();
- }
- ]);
-
- if (SETTINGS.get_boolean('isolate-workspaces'))
- enable();
- }
-
- // Hotkeys
- _activateApp(appIndex, modifiers) {
- let seenApps = {};
- let apps = [];
-
- this.taskbar._getAppIcons().forEach(appIcon => {
- if (!seenApps[appIcon.app] || this.taskbar.allowSplitApps) {
- apps.push(appIcon);
- }
-
- seenApps[appIcon.app] = (seenApps[appIcon.app] || 0) + 1;
- });
-
- this._showOverlay();
-
- if (appIndex < apps.length) {
- let appIcon = apps[appIndex];
- let seenAppCount = seenApps[appIcon.app];
- let windowCount = appIcon.window || appIcon._hotkeysCycle ? seenAppCount : appIcon._nWindows;
-
- if (SETTINGS.get_boolean('shortcut-previews') && windowCount > 1 &&
- !(modifiers & ~(Clutter.ModifierType.MOD1_MASK | Clutter.ModifierType.SUPER_MASK))) { //ignore the alt (MOD1_MASK) and super key (SUPER_MASK)
- if (this._hotkeyPreviewCycleInfo && this._hotkeyPreviewCycleInfo.appIcon != appIcon) {
- this._endHotkeyPreviewCycle();
- }
-
- if (!this._hotkeyPreviewCycleInfo) {
- this._hotkeyPreviewCycleInfo = {
- appIcon: appIcon,
- currentWindow: appIcon.window,
- keyFocusOutId: appIcon.connect('key-focus-out', () => appIcon.grab_key_focus()),
- capturedEventId: global.stage.connect('captured-event', (actor, e) => {
- if (e.type() == Clutter.EventType.KEY_RELEASE && e.get_key_symbol() == (Clutter.KEY_Super_L || Clutter.Super_L)) {
- this._endHotkeyPreviewCycle(true);
- }
-
- return Clutter.EVENT_PROPAGATE;
- })
- };
-
- appIcon._hotkeysCycle = appIcon.window;
- appIcon.window = null;
- appIcon._previewMenu.open(appIcon, true);
- appIcon.grab_key_focus();
- }
-
- appIcon._previewMenu.focusNext();
- } else {
- // Activate with button = 1, i.e. same as left click
- let button = 1;
- this._endHotkeyPreviewCycle();
- appIcon.activate(button, modifiers, !this.taskbar.allowSplitApps);
- }
- }
- }
-
- _endHotkeyPreviewCycle(focusWindow) {
- if (this._hotkeyPreviewCycleInfo) {
- global.stage.disconnect(this._hotkeyPreviewCycleInfo.capturedEventId);
- this._hotkeyPreviewCycleInfo.appIcon.disconnect(this._hotkeyPreviewCycleInfo.keyFocusOutId);
-
- if (focusWindow) {
- this._hotkeyPreviewCycleInfo.appIcon._previewMenu.activateFocused();
- } else
- this._hotkeyPreviewCycleInfo.appIcon._previewMenu.close()
-
- this._hotkeyPreviewCycleInfo.appIcon.window = this._hotkeyPreviewCycleInfo.currentWindow;
- delete this._hotkeyPreviewCycleInfo.appIcon._hotkeysCycle;
- this._hotkeyPreviewCycleInfo = 0;
- }
- }
-
- _optionalHotKeys() {
- this._hotKeysEnabled = false;
- if (SETTINGS.get_boolean('hot-keys'))
- this._enableHotKeys();
-
- this._signalsHandler.add([
- SETTINGS,
- 'changed::hot-keys',
- () => {
- if (SETTINGS.get_boolean('hot-keys'))
- this._enableHotKeys();
- else
- this._disableHotKeys();
- }
- ]);
- }
-
- _resetHotkeys() {
- this._disableHotKeys();
- this._enableHotKeys();
- }
-
- _enableHotKeys() {
- if (this._hotKeysEnabled)
- return;
-
- //3.32 introduced app hotkeys, disable them to prevent conflicts
- if (Main.wm._switchToApplication) {
- for (let i = 1; i < 10; ++i) {
- Utils.removeKeybinding(GS_HOTKEYS_KEY + i);
- }
- }
-
- // Setup keyboard bindings for taskbar elements
- let shortcutNumKeys = SETTINGS.get_string('shortcut-num-keys');
- let bothNumKeys = shortcutNumKeys == 'BOTH';
- let keys = [];
- let prefixModifiers = Clutter.ModifierType.SUPER_MASK
-
- if (SETTINGS.get_string('hotkey-prefix-text') == 'SuperAlt')
- prefixModifiers |= Clutter.ModifierType.MOD1_MASK
-
- if (bothNumKeys || shortcutNumKeys == 'NUM_ROW') {
- keys.push('app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-'); // Regular numbers
- }
-
- if (bothNumKeys || shortcutNumKeys == 'NUM_KEYPAD') {
- keys.push('app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-'); // Key-pad numbers
- }
-
- keys.forEach( function(key) {
- let modifiers = prefixModifiers
-
- // for some reason, in gnome-shell >= 40 Clutter.get_current_event() is now empty
- // for keyboard events. Create here the modifiers that are needed in appicon.activate
- modifiers |= (key.indexOf('-shift-') >= 0 ? Clutter.ModifierType.SHIFT_MASK : 0)
- modifiers |= (key.indexOf('-ctrl-') >= 0 ? Clutter.ModifierType.CONTROL_MASK : 0)
-
- for (let i = 0; i < this._numHotkeys; i++) {
- let appNum = i;
-
- Utils.addKeybinding(key + (i + 1), SETTINGS, () => this._activateApp(appNum, modifiers));
- }
- }, this);
-
- this._hotKeysEnabled = true;
-
- if (SETTINGS.get_string('hotkeys-overlay-combo') === 'ALWAYS')
- this.taskbar.toggleNumberOverlay(true);
- }
-
- _disableHotKeys() {
- if (!this._hotKeysEnabled)
- return;
-
- let keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-', // Regular numbers
- 'app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-']; // Key-pad numbers
- keys.forEach( function(key) {
- for (let i = 0; i < this._numHotkeys; i++) {
- Utils.removeKeybinding(key + (i + 1));
- }
- }, this);
-
- if (Main.wm._switchToApplication) {
- let gsSettings = new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA });
-
- for (let i = 1; i < 10; ++i) {
- Utils.addKeybinding(GS_HOTKEYS_KEY + i, gsSettings, Main.wm._switchToApplication.bind(Main.wm));
- }
- }
-
- this._hotKeysEnabled = false;
-
- this.taskbar.toggleNumberOverlay(false);
- }
-
- _optionalNumberOverlay() {
- // Enable extra shortcut
- if (SETTINGS.get_boolean('hot-keys'))
- this._enableExtraShortcut();
-
- this._signalsHandler.add([
- SETTINGS,
- 'changed::hot-keys',
- this._checkHotkeysOptions.bind(this)
- ], [
- SETTINGS,
- 'changed::hotkeys-overlay-combo',
- () => {
- if (SETTINGS.get_boolean('hot-keys') && SETTINGS.get_string('hotkeys-overlay-combo') === 'ALWAYS')
- this.taskbar.toggleNumberOverlay(true);
- else
- this.taskbar.toggleNumberOverlay(false);
- }
- ], [
- SETTINGS,
- 'changed::shortcut-num-keys',
- () => this._resetHotkeys()
- ]);
- }
-
- _checkHotkeysOptions() {
- if (SETTINGS.get_boolean('hot-keys'))
- this._enableExtraShortcut();
- else
- this._disableExtraShortcut();
- }
-
- _enableExtraShortcut() {
- Utils.addKeybinding('shortcut', SETTINGS, () => this._showOverlay(true));
- }
-
- _disableExtraShortcut() {
- Utils.removeKeybinding('shortcut');
- }
-
- _showOverlay(overlayFromShortcut) {
- //wait for intellihide timeout initialization
- if (!this._panel.intellihide) {
- return;
- }
-
- // Restart the counting if the shortcut is pressed again
- let hotkey_option = SETTINGS.get_string('hotkeys-overlay-combo');
-
- if (hotkey_option === 'NEVER')
- return;
-
- if (hotkey_option === 'TEMPORARILY' || overlayFromShortcut)
- this.taskbar.toggleNumberOverlay(true);
-
- this._panel.intellihide.revealAndHold(Intellihide.Hold.TEMPORARY);
-
- let timeout = 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;
- }
-
-}
diff --git a/panel.js b/panel.js
deleted file mode 100644
index b74e080..0000000
--- a/panel.js
+++ /dev/null
@@ -1,1257 +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 .
- *
- * 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.
- */
-
-import Clutter from 'gi://Clutter';
-import Gio from 'gi://Gio';
-import GObject from 'gi://GObject';
-import * as AppIcons from './appIcons.js';
-import * as Utils from './utils.js';
-import * as Taskbar from './taskbar.js';
-import * as TaskbarItemContainer from './taskbar.js';
-import * as Pos from './panelPositions.js';
-import * as PanelSettings from './panelSettings.js';
-import * as PanelStyle from './panelStyle.js';
-import * as Main from 'resource:///org/gnome/shell/ui/main.js';
-import * as Dash from 'resource:///org/gnome/shell/ui/dash.js';
-import * as CtrlAltTab from 'resource:///org/gnome/shell/ui/ctrlAltTab.js';
-import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
-import St from 'gi://St';
-import Meta from 'gi://Meta';
-import Pango from 'gi://Pango';
-import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
-import Shell from 'gi://Shell';
-import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
-import * as DateMenu from 'resource:///org/gnome/shell/ui/dateMenu.js';
-import * as Volume from 'resource:///org/gnome/shell/ui/status/volume.js';
-import * as Progress from './progress.js';
-
-import * as Intellihide from './intellihide.js';
-import * as Transparency from './transparency.js';
-import {SETTINGS, DESKTOPSETTINGS, PERSISTENTSTORAGE, EXTENSION_PATH} from './extension.js';
-import {gettext as _, InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
-
-let tracker = Shell.WindowTracker.get_default();
-export const panelBoxes = ['_leftBox', '_centerBox', '_rightBox'];
-
-//timeout names
-const T2 = 'startIntellihideTimeout';
-const T4 = 'showDesktopTimeout';
-const T5 = 'trackerFocusAppTimeout';
-const T6 = 'waitPanelBoxAllocation';
-
-const SHOW_SHOWDESKTOP_DELAY = 1000;
-const SHOW_SHOWDESKTOP_TIME = 200;
-
-const FLOATING_MARGIN = 8;
-
-export const Panel = GObject.registerClass({
-}, class Panel extends St.Widget {
-
- _init(panelManager, monitor, panelBox, isStandalone) {
- super._init({ layout_manager: new Clutter.BinLayout() });
-
- this._timeoutsHandler = new Utils.TimeoutsHandler();
- this._signalsHandler = new Utils.GlobalSignalsHandler();
- this._injectionManager = new InjectionManager();
-
- this.panelManager = panelManager;
- this.panelStyle = new PanelStyle.PanelStyle();
-
- this.monitor = monitor;
- this.panelBox = panelBox;
-
- // when the original gnome-shell top panel is kept, all panels are "standalone",
- // so in this case use isPrimary to get the panel on the primary dtp monitor, which
- // might be different from the system's primary monitor.
- this.isStandalone = isStandalone;
- this.isPrimary = !isStandalone || (SETTINGS.get_boolean('stockgs-keep-top-panel') &&
- monitor == panelManager.dtpPrimaryMonitor);
-
- this._sessionStyle = null;
- this._unmappedButtons = [];
- this._elementGroups = [];
-
- let systemMenuInfo = Utils.getSystemMenuInfo();
-
- if (isStandalone) {
- this.panel = new SecondaryPanel({ name: 'panel', reactive: true });
- this.statusArea = this.panel.statusArea = {};
-
- //next 3 functions are needed by other extensions to add elements to the secondary panel
- this.panel.addToStatusArea = function(role, indicator, position, box) {
- return Main.panel.addToStatusArea.call(this, role, indicator, position, box);
- };
-
- this.panel._addToPanelBox = function(role, indicator, position, box) {
- Main.panel._addToPanelBox.call(this, role, indicator, position, box);
- };
-
- this.panel._onMenuSet = function(indicator) {
- Main.panel._onMenuSet.call(this, indicator);
- };
-
- this._leftBox = this.panel._leftBox = new St.BoxLayout({ name: 'panelLeft' });
- this._centerBox = this.panel._centerBox = new St.BoxLayout({ name: 'panelCenter' });
- this._rightBox = this.panel._rightBox = new St.BoxLayout({ name: 'panelRight' });
-
- this.menuManager = this.panel.menuManager = new PopupMenu.PopupMenuManager(this.panel);
-
- this._setPanelMenu(systemMenuInfo.name, systemMenuInfo.constructor, this.panel);
- this._setPanelMenu('dateMenu', DateMenu.DateMenuButton, this.panel);
- this._setPanelMenu('activities', Main.panel.statusArea.activities.constructor, this.panel);
-
- this.panel.add_child(this._leftBox);
- this.panel.add_child(this._centerBox);
- this.panel.add_child(this._rightBox);
- } else {
- this.panel = Main.panel;
- this.statusArea = Main.panel.statusArea;
- this.menuManager = Main.panel.menuManager;
-
- panelBoxes.forEach(p => this[p] = Main.panel[p]);
-
- ['activities', systemMenuInfo.name, 'dateMenu'].forEach(b => {
- let container = this.statusArea[b].container;
- let parent = container.get_parent();
- let siblings = parent.get_children();
- let index = siblings.indexOf(container);
-
- container._dtpOriginalParent = parent;
- container._dtpOriginalIndex = index && index == siblings.length - 1 ? -1: index;
- parent ? parent.remove_child(container) : null;
- this.panel.add_child(container);
- });
- }
-
- // Create a wrapper around the real showAppsIcon in order to add a popupMenu. Most of
- // its behavior is handled by the taskbar, but its positioning is done at the panel level
- this.showAppsIconWrapper = new AppIcons.ShowAppsIconWrapper(this);
- this.panel.add_child(this.showAppsIconWrapper.realShowAppsIcon);
-
- this.panel._delegate = this;
-
- this.add_child(this.panel);
-
- if (Main.panel._onButtonPress || Main.panel._tryDragWindow) {
- this._signalsHandler.add([
- this.panel,
- [
- 'button-press-event',
- 'touch-event'
- ],
- this._onButtonPress.bind(this)
- ]);
- }
-
- if (Main.panel._onKeyPress) {
- this._signalsHandler.add([this.panel, 'key-press-event', Main.panel._onKeyPress.bind(this)]);
- }
-
- Main.ctrlAltTabManager.addGroup(this, _("Top Bar")+" "+ monitor.index, 'focus-top-bar-symbolic',
- { sortGroup: CtrlAltTab.SortGroup.TOP });
- }
-
- enable () {
- let { name: systemMenuName } = Utils.getSystemMenuInfo();
-
- if (this.statusArea[systemMenuName] && this.statusArea[systemMenuName]._volumeOutput) {
- Utils.getIndicators(this.statusArea[systemMenuName]._volumeOutput)._dtpIgnoreScroll = 1;
- }
-
- this._toggleFloatingRoundedTheme();
-
- this.geom = this.getGeometry();
-
- this._setPanelPosition();
-
- if (!this.isStandalone) {
- this._injectionManager.overrideMethod(Object.getPrototypeOf(this.panel), 'vfunc_allocate', () => (box) => this._mainPanelAllocate(box));
-
- // remove the extra space before the clock when the message-indicator is displayed
- if (DateMenu.IndicatorPad) {
- this._injectionManager.overrideMethod(DateMenu.IndicatorPad.prototype, 'vfunc_get_preferred_width', () => () => [0,0]);
- this._injectionManager.overrideMethod(DateMenu.IndicatorPad.prototype, 'vfunc_get_preferred_height', () => () => [0,0]);
- }
- }
-
- if (!DateMenu.IndicatorPad && this.statusArea.dateMenu) {
- //3.36 switched to a size constraint applied on an anonymous child
- let indicatorPad = this.statusArea.dateMenu.get_first_child().get_first_child();
-
- this._dateMenuIndicatorPadContraints = indicatorPad.get_constraints();
- indicatorPad.clear_constraints();
- }
-
- this.menuManager._oldChangeMenu = this.menuManager._changeMenu;
- this.menuManager._changeMenu = (menu) => {
- if (!SETTINGS.get_boolean('stockgs-panelbtn-click-only')) {
- this.menuManager._oldChangeMenu(menu);
- }
- };
-
- this.dynamicTransparency = new Transparency.DynamicTransparency(this);
-
- this.taskbar = new Taskbar.Taskbar(this);
-
- this.panel.add_child(this.taskbar.actor);
-
- this._setShowDesktopButton(true);
-
- this._setAllocationMap();
-
- this.panel.add_style_class_name('zorintaskbarMainPanel ' + this.getOrientation());
-
- this._timeoutsHandler.add([T2, Intellihide.INTELLIHIDE_ENABLE_START_DELAY, () => this.intellihide = new Intellihide.Intellihide(this)]);
-
- this._signalsHandler.add(
- // this is to catch changes to the theme or window scale factor
- [
- Utils.getStageTheme(),
- 'changed',
- () => (this._resetGeometry(), this._setShowDesktopButtonStyle()),
- ],
- [
- // sync hover after a popupmenu is closed
- this.taskbar,
- 'menu-closed',
- () => this.panel.sync_hover()
- ],
- [
- Main.overview,
- [
- 'showing',
- 'hiding'
- ],
- () => this._adjustForOverview()
- ],
- [
- Main.overview,
- 'hidden',
- () => {
- if (this.isPrimary) {
- //reset the primary monitor when exiting the overview
- this.panelManager.setFocusedMonitor(this.monitor);
- }
- }
- ],
- [
- this.statusArea.activities,
- 'captured-event',
- (actor, e) => {
- if (e.type() == Clutter.EventType.BUTTON_PRESS || e.type() == Clutter.EventType.TOUCH_BEGIN) {
- //temporarily use as primary the monitor on which the activities btn was clicked
- this.panelManager.setFocusedMonitor(this.monitor);
- }
- }
- ],
- [
- this._centerBox,
- 'child-added',
- () => this._onBoxActorAdded(this._centerBox)
- ],
- [
- this._rightBox,
- 'child-added',
- () => this._onBoxActorAdded(this._rightBox)
- ],
- [
- Main.layoutManager,
- 'startup-complete',
- () => this._resetGeometry()
- ]
- );
-
- this._bindSettingsChanges();
-
- this.panelStyle.enable(this);
-
- if (this.checkIfVertical()) {
- this._signalsHandler.add([
- this.panelBox,
- 'notify::visible',
- () => {
- if (this.panelBox.visible) {
- this._refreshVerticalAlloc();
- }
- }
- ]);
-
- if (this.statusArea.dateMenu) {
- this._formatVerticalClock();
-
- this._signalsHandler.add([
- this.statusArea.dateMenu._clock,
- 'notify::clock',
- () => this._formatVerticalClock()
- ]);
- }
- }
-
- // Since we are usually visible but not usually changing, make sure
- // most repaint requests don't actually require us to repaint anything.
- // This saves significant CPU when repainting the screen.
- this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
-
- this._initProgressManager();
- }
-
- disable() {
- this.panelStyle.disable();
-
- this._timeoutsHandler.destroy();
- this._signalsHandler.destroy();
-
- this.panel.remove_child(this.taskbar.actor);
-
- if (this.intellihide) {
- this.intellihide.destroy();
- }
-
- this.dynamicTransparency.destroy();
-
- this.progressManager.destroy();
-
- this.taskbar.destroy();
- this.showAppsIconWrapper.destroy();
-
- this.menuManager._changeMenu = this.menuManager._oldChangeMenu;
-
- this._unmappedButtons.forEach(a => this._disconnectVisibleId(a));
-
- if (this.statusArea.dateMenu) {
- this.statusArea.dateMenu._clockDisplay.text = this.statusArea.dateMenu._clock.clock;
- this.statusArea.dateMenu._clockDisplay.clutter_text.set_width(-1);
-
- if (this._dateMenuIndicatorPadContraints) {
- let indicatorPad = this.statusArea.dateMenu.get_first_child().get_first_child();
-
- this._dateMenuIndicatorPadContraints.forEach(c => indicatorPad.add_constraint(c));
- }
- }
-
- this._setVertical(this.panel, false);
- this._setVertical(this._centerBox, false);
- this._setVertical(this._rightBox, false);
-
- let { name: systemMenuName } = Utils.getSystemMenuInfo();
-
- if (!this.isStandalone) {
- ['vertical', 'horizontal', 'zorintaskbarMainPanel'].forEach(c => this.panel.remove_style_class_name(c));
-
- if (!Main.sessionMode.isLocked) {
- ['activities', systemMenuName, 'dateMenu'].forEach(b => {
- let container = this.statusArea[b].container;
- let originalParent = container._dtpOriginalParent;
-
- this.panel.remove_child(container);
-
- originalParent && originalParent.insert_child_at_index(
- container,
- Math.min(container._dtpOriginalIndex, originalParent.get_children().length - 1)
- );
-
- delete container._dtpOriginalParent;
- delete container._dtpOriginalIndex;
- });
- }
-
- this._setShowDesktopButton(false);
-
- delete Utils.getIndicators(this.statusArea[systemMenuName]._volumeOutput)._dtpIgnoreScroll;
-
- this._injectionManager.clear();
-
- this.panel._delegate = this.panel;
- } else {
- this._removePanelMenu('dateMenu');
- this._removePanelMenu(systemMenuName);
- this._removePanelMenu('activities');
- }
-
- Main.ctrlAltTabManager.removeGroup(this);
- }
-
- getPosition() {
- let position = PanelSettings.getPanelPosition(SETTINGS, this.monitor.index);
-
- if (position == Pos.TOP) {
- return St.Side.TOP;
- } else if (position == Pos.RIGHT) {
- return St.Side.RIGHT;
- } else if (position == Pos.BOTTOM) {
- return St.Side.BOTTOM;
- }
-
- return St.Side.LEFT;
- }
-
- checkIfVertical() {
- let position = this.getPosition();
-
- return (position == St.Side.LEFT || position == St.Side.RIGHT);
- }
-
- getOrientation() {
- return (this.checkIfVertical() ? 'vertical' : 'horizontal');
- }
-
- updateElementPositions() {
- let panelPositions = this.panelManager.panelsElementPositions[this.monitor.index] || Pos.defaults;
-
- this._updateGroupedElements(panelPositions);
-
- this.panel.hide();
- this.panel.show();
- }
-
- _updateGroupedElements(panelPositions) {
- let previousPosition = 0;
- let previousCenteredPosition = 0;
- let currentGroup = -1;
-
- this._elementGroups = [];
-
- panelPositions.forEach(pos => {
- let allocationMap = this.allocationMap[pos.element];
-
- if (allocationMap.actor) {
- allocationMap.actor.visible = pos.visible;
-
- if (!pos.visible) {
- return;
- }
-
- let currentPosition = pos.position;
- let isCentered = Pos.checkIfCentered(currentPosition);
-
- if (currentPosition == Pos.STACKED_TL && previousPosition == Pos.STACKED_BR) {
- currentPosition = Pos.STACKED_BR;
- }
-
- if (!previousPosition ||
- (previousPosition == Pos.STACKED_TL && currentPosition != Pos.STACKED_TL) ||
- (previousPosition != Pos.STACKED_BR && currentPosition == Pos.STACKED_BR) ||
- (isCentered && previousPosition != currentPosition && previousPosition != Pos.STACKED_BR)) {
- this._elementGroups[++currentGroup] = { elements: [], index: this._elementGroups.length, expandableIndex: -1 };
- previousCenteredPosition = 0;
- }
-
- if (pos.element == Pos.TASKBAR) {
- this._elementGroups[currentGroup].expandableIndex = this._elementGroups[currentGroup].elements.length;
- }
-
- if (isCentered && !this._elementGroups[currentGroup].isCentered) {
- this._elementGroups[currentGroup].isCentered = 1;
- previousCenteredPosition = currentPosition;
- }
-
- this._elementGroups[currentGroup].position = previousCenteredPosition || currentPosition;
- this._elementGroups[currentGroup].elements.push(allocationMap);
-
- allocationMap.position = currentPosition;
- previousPosition = currentPosition;
- }
- });
- }
-
- _bindSettingsChanges() {
- let isVertical = this.checkIfVertical();
-
- this._signalsHandler.add(
- [
- SETTINGS,
- [
- 'changed::panel-sizes',
- 'changed::group-apps'
- ],
- () => this._resetGeometry()
- ],
- [
- SETTINGS,
- [
- 'changed::showdesktop-button-width',
- 'changed::show-showdesktop-icon'
- ],
- () => this._setShowDesktopButtonStyle()
- ],
- [
- SETTINGS,
- 'changed::floating-rounded-theme',
- () => {
- this._resetGeometry();
- }
- ],
- [
- DESKTOPSETTINGS,
- 'changed::clock-format',
- () => {
- this._clockFormat = null;
-
- if (isVertical) {
- this._formatVerticalClock();
- }
- }
- ],
- [
- SETTINGS,
- 'changed::progress-show-bar',
- () => this._initProgressManager()
- ],
- [
- SETTINGS,
- 'changed::progress-show-count',
- () => this._initProgressManager()
- ]
- );
-
- if (isVertical) {
- this._signalsHandler.add([SETTINGS, 'changed::group-apps-label-max-width', () => this._resetGeometry()]);
- }
- }
-
- _setPanelMenu(propName, constr, container) {
- if (!this.statusArea[propName]) {
- this.statusArea[propName] = this._getPanelMenu(propName, constr);
- this.menuManager.addMenu(this.statusArea[propName].menu);
- container.insert_child_at_index(this.statusArea[propName].container, 0);
- }
- }
-
- _removePanelMenu(propName) {
- if (this.statusArea[propName]) {
- let parent = this.statusArea[propName].container.get_parent();
-
- if (parent) {
- parent.remove_child(this.statusArea[propName].container);
- }
-
- //calling this.statusArea[propName].destroy(); is buggy for now, gnome-shell never
- //destroys those panel menus...
- //since we can't destroy the menu (hence properly disconnect its signals), let's
- //store it so the next time a panel needs one of its kind, we can reuse it instead
- //of creating a new one
- let panelMenu = this.statusArea[propName];
-
- this.menuManager.removeMenu(panelMenu.menu);
- PERSISTENTSTORAGE[propName].push(panelMenu);
- this.statusArea[propName] = null;
- }
- }
-
- _getPanelMenu(propName, constr) {
- PERSISTENTSTORAGE[propName] = PERSISTENTSTORAGE[propName] || [];
-
- if (!PERSISTENTSTORAGE[propName].length) {
- PERSISTENTSTORAGE[propName].push(new constr());
- }
-
- return PERSISTENTSTORAGE[propName].pop();
- }
-
- _adjustForOverview() {
- let isFocusedMonitor = this.panelManager.checkIfFocusedMonitor(this.monitor);
- let isOverview = !!Main.overview.visibleTarget;
- let isOverviewFocusedMonitor = isOverview && isFocusedMonitor;
- let isShown = !isOverview || isOverviewFocusedMonitor;
- let actorData = Utils.getTrackedActorData(this.panelBox)
-
- // prevent the "chrome" to update the panelbox visibility while in overview
- actorData.trackFullscreen = !isOverview
-
- this.panelBox[isShown ? 'show' : 'hide']();
- }
-
- _toggleFloatingRoundedTheme() {
- if (this.panelBox.has_style_class_name('top')) {
- this.panelBox.remove_style_class_name('top');
- } else if (this.panelBox.has_style_class_name('left')) {
- this.panelBox.remove_style_class_name('left');
- } else if (this.panelBox.has_style_class_name('right')) {
- this.panelBox.remove_style_class_name('right');
- } else if (this.panelBox.has_style_class_name('bottom')) {
- this.panelBox.remove_style_class_name('bottom');
- }
-
- if (SETTINGS.get_boolean('floating-rounded-theme')) {
- if (!this.panelBox.has_style_class_name('floating')) {
- this.panelBox.add_style_class_name('floating');
- }
-
- let position = this.getPosition();
- if (position == St.Side.TOP) {
- this.panelBox.add_style_class_name('top');
- } else if (position == St.Side.RIGHT) {
- this.panelBox.add_style_class_name('right');
- } else if (position == St.Side.BOTTOM) {
- this.panelBox.add_style_class_name('bottom');
- } else {
- this.panelBox.add_style_class_name('left');
- }
- } else {
- if (this.panelBox.has_style_class_name('floating'))
- this.panelBox.remove_style_class_name('floating');
- }
- }
-
- _resetGeometry() {
- this._toggleFloatingRoundedTheme()
- this.geom = this.getGeometry();
- this._setPanelPosition();
- this.taskbar.resetAppIcons(true);
- this.dynamicTransparency.updateExternalStyle();
-
- if (this.intellihide && this.intellihide.enabled) {
- this.intellihide.reset();
- }
-
- if (this.checkIfVertical()) {
- this.showAppsIconWrapper.realShowAppsIcon.toggleButton.set_width(this.geom.w);
- this._refreshVerticalAlloc();
- }
- }
-
- getGeometry() {
- let scaleFactor = Utils.getScaleFactor();
- let panelBoxTheme = this.panelBox.get_theme_node();
- let lrPadding = panelBoxTheme.get_padding(St.Side.RIGHT) + panelBoxTheme.get_padding(St.Side.LEFT);
- let topPadding = panelBoxTheme.get_padding(St.Side.TOP);
- let tbPadding = topPadding + panelBoxTheme.get_padding(St.Side.BOTTOM);
- let position = this.getPosition();
- let length = PanelSettings.getPanelLength(SETTINGS, this.monitor.index) / 100;
- let anchor = PanelSettings.getPanelAnchor(SETTINGS, this.monitor.index);
- let anchorPlaceOnMonitor = 0;
- let gsTopPanelOffset = 0;
- let x = 0, y = 0;
- let w = 0, h = 0;
-
- const panelSize = PanelSettings.getPanelSize(SETTINGS, this.monitor.index);
- this.dtpSize = panelSize * scaleFactor;
-
- if (SETTINGS.get_boolean('stockgs-keep-top-panel') && Main.layoutManager.primaryMonitor == this.monitor) {
- gsTopPanelOffset = Main.layoutManager.panelBox.height - topPadding;
- }
-
- if (this.checkIfVertical()) {
- if (!SETTINGS.get_boolean('group-apps')) {
- // add window title width and side padding of _dtpIconContainer when vertical
- this.dtpSize += SETTINGS.get_int('group-apps-label-max-width') + AppIcons.DEFAULT_PADDING_SIZE * 2 / scaleFactor;
- }
-
- this.sizeFunc = 'get_preferred_height',
- this.fixedCoord = { c1: 'x1', c2: 'x2' }
- this.varCoord = { c1: 'y1', c2: 'y2' };
-
- w = this.dtpSize;
- h = this.monitor.height * length - tbPadding - gsTopPanelOffset;
- } else {
- this.sizeFunc = 'get_preferred_width';
- this.fixedCoord = { c1: 'y1', c2: 'y2' };
- this.varCoord = { c1: 'x1', c2: 'x2' };
-
- w = this.monitor.width * length - lrPadding;
- h = this.dtpSize;
- }
-
- if (position == St.Side.TOP || position == St.Side.LEFT) {
- x = this.monitor.x;
- y = this.monitor.y + gsTopPanelOffset;
- } else if (position == St.Side.RIGHT) {
- x = this.monitor.x + this.monitor.width - this.dtpSize - lrPadding;
- y = this.monitor.y + gsTopPanelOffset;
- } else { //BOTTOM
- x = this.monitor.x;
- y = this.monitor.y + this.monitor.height - this.dtpSize - tbPadding;
- }
-
- if (this.checkIfVertical()) {
- let viewHeight = this.monitor.height - gsTopPanelOffset;
-
- if (anchor === Pos.MIDDLE) {
- anchorPlaceOnMonitor = (viewHeight - h) / 2;
- } else if (anchor === Pos.END) {
- anchorPlaceOnMonitor = viewHeight - h;
- } else { // Pos.START
- anchorPlaceOnMonitor = 0;
- }
- y = y + anchorPlaceOnMonitor;
- } else {
- if (anchor === Pos.MIDDLE) {
- anchorPlaceOnMonitor = (this.monitor.width - w) / 2;
- } else if (anchor === Pos.END) {
- anchorPlaceOnMonitor = this.monitor.width - w;
- } else { // Pos.START
- anchorPlaceOnMonitor = 0;
- }
- x = x + anchorPlaceOnMonitor;
- }
-
- if (SETTINGS.get_boolean('floating-rounded-theme')) {
- if (position == St.Side.BOTTOM || position == St.Side.TOP) {
- x -= FLOATING_MARGIN;
- } else { // LEFT or RIGHT
- y -= FLOATING_MARGIN;
- }
- }
-
- return {
- x, y,
- w, h,
- lrPadding,
- tbPadding,
- position
- };
- }
-
- _setAllocationMap() {
- this.allocationMap = {};
- let setMap = (name, actor) => this.allocationMap[name] = {
- actor: actor,
- box: new Clutter.ActorBox()
- };
-
- setMap(Pos.SHOW_APPS_BTN, this.showAppsIconWrapper.realShowAppsIcon);
- setMap(Pos.ACTIVITIES_BTN, this.statusArea.activities ? this.statusArea.activities.container : 0);
- setMap(Pos.LEFT_BOX, this._leftBox);
- setMap(Pos.TASKBAR, this.taskbar.actor);
- setMap(Pos.CENTER_BOX, this._centerBox);
- setMap(Pos.DATE_MENU, this.statusArea.dateMenu.container);
- setMap(Pos.SYSTEM_MENU, this.statusArea[Utils.getSystemMenuInfo().name].container);
- setMap(Pos.RIGHT_BOX, this._rightBox);
- setMap(Pos.DESKTOP_BTN, this._showDesktopButton);
- }
-
- _mainPanelAllocate(box) {
- this.panel.set_allocation(box);
- }
-
- vfunc_allocate(box) {
- this.set_allocation(box);
-
- let fixed = 0;
- let centeredMonitorGroup;
- let panelAlloc = new Clutter.ActorBox({ x1: 0, y1: 0, x2: this.geom.w, y2: this.geom.h });
- let assignGroupSize = (group, update) => {
- group.size = 0;
- group.tlOffset = 0;
- group.brOffset = 0;
-
- group.elements.forEach(element => {
- if (!update) {
- element.box[this.fixedCoord.c1] = panelAlloc[this.fixedCoord.c1];
- element.box[this.fixedCoord.c2] = panelAlloc[this.fixedCoord.c2];
- element.natSize = element.actor[this.sizeFunc](-1)[1];
- }
-
- if (!group.isCentered || Pos.checkIfCentered(element.position)) {
- group.size += element.natSize;
- } else if (element.position == Pos.STACKED_TL) {
- group.tlOffset += element.natSize;
- } else { // Pos.STACKED_BR
- group.brOffset += element.natSize;
- }
- });
-
- if (group.isCentered) {
- group.size += Math.max(group.tlOffset, group.brOffset) * 2;
- group.tlOffset = Math.max(group.tlOffset - group.brOffset, 0);
- }
- };
- let allocateGroup = (group, tlLimit, brLimit) => {
- let startPosition = tlLimit;
- let currentPosition = 0;
-
- if (group.expandableIndex >= 0) {
- let availableSize = brLimit - tlLimit;
- let expandable = group.elements[group.expandableIndex];
- let i = 0;
- let l = this._elementGroups.length;
- let tlSize = 0;
- let brSize = 0;
-
- if (centeredMonitorGroup && (centeredMonitorGroup != group || expandable.position != Pos.CENTERED_MONITOR)) {
- if (centeredMonitorGroup.index < group.index || (centeredMonitorGroup == group && expandable.position == Pos.STACKED_TL)) {
- i = centeredMonitorGroup.index;
- } else {
- l = centeredMonitorGroup.index;
- }
- }
-
- for (; i < l; ++i) {
- let refGroup = this._elementGroups[i];
-
- if (i < group.index && (!refGroup.fixed || refGroup[this.varCoord.c2] > tlLimit)) {
- tlSize += refGroup.size;
- } else if (i > group.index && (!refGroup.fixed || refGroup[this.varCoord.c1] < brLimit)) {
- brSize += refGroup.size;
- }
- }
-
- if (group.isCentered) {
- availableSize -= Math.max(tlSize, brSize) * 2;
- } else {
- availableSize -= tlSize + brSize;
- }
-
- if (availableSize < group.size) {
- expandable.natSize -= (group.size - availableSize) * (group.isCentered && !Pos.checkIfCentered(expandable.position) ? .5 : 1);
- assignGroupSize(group, true);
- }
- }
-
- if (group.isCentered) {
- startPosition = tlLimit + (brLimit - tlLimit - group.size) * .5;
- } else if (group.position == Pos.STACKED_BR) {
- startPosition = brLimit - group.size;
- }
-
- currentPosition = group.tlOffset + startPosition;
-
- group.elements.forEach(element => {
- element.box[this.varCoord.c1] = Math.round(currentPosition);
- element.box[this.varCoord.c2] = Math.round((currentPosition += element.natSize));
-
- element.actor.allocate(element.box);
- });
-
- group[this.varCoord.c1] = startPosition;
- group[this.varCoord.c2] = currentPosition;
- group.fixed = 1;
- ++fixed;
- };
-
- this.panel.allocate(panelAlloc);
-
- this._elementGroups.forEach(group => {
- group.fixed = 0;
-
- assignGroupSize(group);
-
- if (group.position == Pos.CENTERED_MONITOR) {
- centeredMonitorGroup = group;
- }
- });
-
- if (centeredMonitorGroup) {
- allocateGroup(centeredMonitorGroup, panelAlloc[this.varCoord.c1], panelAlloc[this.varCoord.c2]);
- }
-
- let iterations = 0; //failsafe
- while (fixed < this._elementGroups.length && ++iterations < 10) {
- for (let i = 0, l = this._elementGroups.length; i < l; ++i) {
- let group = this._elementGroups[i];
-
- if (group.fixed) {
- continue;
- }
-
- let prevGroup = this._elementGroups[i - 1];
- let nextGroup = this._elementGroups[i + 1];
- let prevLimit = prevGroup && prevGroup.fixed ? prevGroup[this.varCoord.c2] :
- centeredMonitorGroup && group.index > centeredMonitorGroup.index ? centeredMonitorGroup[this.varCoord.c2] : panelAlloc[this.varCoord.c1];
- let nextLimit = nextGroup && nextGroup.fixed ? nextGroup[this.varCoord.c1] :
- centeredMonitorGroup && group.index < centeredMonitorGroup.index ? centeredMonitorGroup[this.varCoord.c1] : panelAlloc[this.varCoord.c2];
-
- if (group.position == Pos.STACKED_TL) {
- allocateGroup(group, panelAlloc[this.varCoord.c1], nextLimit);
- } else if (group.position == Pos.STACKED_BR) {
- allocateGroup(group, prevLimit, panelAlloc[this.varCoord.c2]);
- } else if ((!prevGroup || prevGroup.fixed) && (!nextGroup || nextGroup.fixed)) { // CENTERED
- allocateGroup(group, prevLimit, nextLimit);
- }
- }
- }
- }
-
- _setPanelPosition() {
- let clipContainer = this.panelBox.get_parent();
-
- this.set_size(this.geom.w, this.geom.h);
- clipContainer.set_position(this.geom.x, this.geom.y);
-
- this._setVertical(this.panel, this.checkIfVertical());
-
- // styles for theming
- Object.keys(St.Side).forEach(p => {
- let cssName = 'zorintaskbar' + p.charAt(0) + p.slice(1).toLowerCase();
-
- this.panel[(St.Side[p] == this.geom.position ? 'add' : 'remove') + '_style_class_name'](cssName);
- });
-
- this._setPanelClip(clipContainer);
-
- Main.layoutManager._updateHotCorners();
- Main.layoutManager._updatePanelBarrier(this);
- }
-
- _setPanelClip(clipContainer) {
- clipContainer = clipContainer || this.panelBox.get_parent();
- this._timeoutsHandler.add([T6, 0, () => Utils.setClip(clipContainer, clipContainer.x, clipContainer.y, this.panelBox.width, this.panelBox.height)]);
- }
-
- _onButtonPress(actor, event) {
- let type = event.type();
- let isPress = type == Clutter.EventType.BUTTON_PRESS;
- let button = isPress ? event.get_button() : -1;
- let [stageX, stageY] = event.get_coords();
-
- if (button == 3 && global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, stageX, stageY) == this.panel) {
- //right click on an empty part of the panel, temporarily borrow and display the showapps context menu
- Main.layoutManager.setDummyCursorGeometry(stageX, stageY, 0, 0);
-
- this.showAppsIconWrapper.createMenu();
- this.showAppsIconWrapper.popupMenu(Main.layoutManager.dummyCursor);
-
- return Clutter.EVENT_STOP;
- } else {
- const targetActor = global.stage.get_event_actor(event);
-
- if (Main.modalCount > 0 || targetActor != actor ||
- (!isPress && type != Clutter.EventType.TOUCH_BEGIN) ||
- (isPress && button != 1)) {
- return Clutter.EVENT_PROPAGATE;
- }
- }
-
- let params = this.checkIfVertical() ? [stageY, 'y', 'height'] : [stageX, 'x', 'width'];
- let dragWindow = this._getDraggableWindowForPosition.apply(this, params.concat(['maximized_' + this.getOrientation() + 'ly']));
-
- if (!dragWindow)
- return Clutter.EVENT_PROPAGATE;
-
- global.display.begin_grab_op(dragWindow,
- Meta.GrabOp.MOVING,
- false, /* pointer grab */
- true, /* frame action */
- button,
- event.get_state(),
- event.get_time(),
- stageX, stageY);
-
- return Clutter.EVENT_STOP;
- }
-
- _getDraggableWindowForPosition(stageCoord, coord, dimension, maximizedProp) {
- let workspace = Utils.getCurrentWorkspace();
- let allWindowsByStacking = global.display.sort_windows_by_stacking(
- workspace.list_windows()
- ).reverse();
-
- return Utils.find(allWindowsByStacking, metaWindow => {
- let rect = metaWindow.get_frame_rect();
-
- return metaWindow.get_monitor() == this.monitor.index &&
- metaWindow.showing_on_its_workspace() &&
- metaWindow.get_window_type() != Meta.WindowType.DESKTOP &&
- metaWindow[maximizedProp] &&
- stageCoord > rect[coord] && stageCoord < rect[coord] + rect[dimension];
- });
- }
-
- _onBoxActorAdded(box) {
- if (this.checkIfVertical()) {
- this._setVertical(box, true);
- }
- }
-
- _refreshVerticalAlloc() {
- this._setVertical(this._centerBox, true);
- this._setVertical(this._rightBox, true);
- this._formatVerticalClock();
- }
-
- _setVertical(actor, isVertical) {
- let _set = (actor, isVertical) => {
- if (!actor || actor instanceof Dash.DashItemContainer || actor instanceof TaskbarItemContainer.TaskbarItemContainer) {
- return;
- }
-
- if (actor instanceof St.BoxLayout) {
- actor.vertical = isVertical;
- } else if (
- actor != this.statusArea.appMenu &&
- ((actor._delegate || actor) instanceof PanelMenu.ButtonBox || actor == this.statusArea.quickSettings)
- ) {
- let child = actor.get_first_child();
-
- if (isVertical && !actor.visible && !actor._dtpVisibleId) {
- this._unmappedButtons.push(actor);
- actor._dtpVisibleId = actor.connect('notify::visible', () => {
- this._disconnectVisibleId(actor);
- this._refreshVerticalAlloc();
- });
- actor._dtpDestroyId = actor.connect('destroy', () => this._disconnectVisibleId(actor));
- }
-
- if (child) {
- let [, natWidth] = actor.get_preferred_width(-1);
-
- child.x_align = Clutter.ActorAlign[isVertical ? 'CENTER' : 'START'];
- actor.set_width(isVertical ? this.dtpSize : -1);
- isVertical = isVertical && (natWidth > this.dtpSize);
- actor[(isVertical ? 'add' : 'remove') + '_style_class_name']('vertical');
- }
- }
-
- actor.get_children().forEach(c => _set(c, isVertical));
- };
-
- _set(actor, false);
-
- if (isVertical)
- _set(actor, isVertical);
- }
-
- _disconnectVisibleId(actor) {
- actor.disconnect(actor._dtpVisibleId);
- actor.disconnect(actor._dtpDestroyId);
-
- delete actor._dtpVisibleId;
- delete actor._dtpDestroyId;
-
- this._unmappedButtons.splice(this._unmappedButtons.indexOf(actor), 1);
- }
-
- _formatVerticalClock() {
- // https://github.com/GNOME/gnome-desktop/blob/master/libgnome-desktop/gnome-wall-clock.c#L310
- if (this.statusArea.dateMenu) {
- let datetime = this.statusArea.dateMenu._clock.clock;
- let datetimeParts = datetime.split(' ');
- let time = datetimeParts[1];
- let clockText = this.statusArea.dateMenu._clockDisplay.clutter_text;
- let setClockText = (text, useTimeSeparator) => {
- let stacks = text instanceof Array;
- let separator = `\n ${useTimeSeparator ? '‧‧' : '—' } \n`;
-
- clockText.set_text((stacks ? text.join(separator) : text).trim());
- clockText.set_use_markup(stacks);
- clockText.get_allocation_box();
-
- return !clockText.get_layout().is_ellipsized();
- };
-
- if (clockText.ellipsize == Pango.EllipsizeMode.NONE) {
- //on gnome-shell 3.36.4, the clockdisplay isn't ellipsize anymore, so set it back
- clockText.ellipsize = Pango.EllipsizeMode.END;
- }
-
- clockText.natural_width = this.dtpSize;
-
- if (!time) {
- datetimeParts = datetime.split(' ');
- time = datetimeParts.pop();
- datetimeParts = [datetimeParts.join(' '), time];
- }
-
- if (!setClockText(datetime) &&
- !setClockText(datetimeParts) &&
- !setClockText(time)) {
- let timeParts = time.split('∶');
-
- if (!this._clockFormat) {
- this._clockFormat = DESKTOPSETTINGS.get_string('clock-format');
- }
-
- if (this._clockFormat == '12h') {
- timeParts.push.apply(timeParts, timeParts.pop().split(' '));
- }
-
- setClockText(timeParts, true);
- }
- }
- }
-
- _setShowDesktopButton(add) {
- if (add) {
- if(this._showDesktopButton)
- return;
-
- this._showDesktopButton = new St.Bin({ style_class: 'panel-button',
- reactive: true,
- can_focus: true,
- // x_fill: true,
- // y_fill: true,
- track_hover: true });
-
- this._showDesktopButton.icon = new St.Icon({ gicon: Gio.icon_new_for_string(`${EXTENSION_PATH}/img/show-desktop-symbolic.svg`), style_class: 'system-status-icon' });
-
- this._setShowDesktopButtonStyle();
-
- this._showDesktopButton.connect('touch-event', (actor, event) => {
- if (event.type() == Clutter.EventType.TOUCH_BEGIN) {
- this._onShowDesktopButtonPress();
- }
- });
- this._showDesktopButton.connect('button-press-event', () => this._onShowDesktopButtonPress());
- this._showDesktopButton.connect('enter-event', () => {
- if (SETTINGS.get_boolean('show-showdesktop-hover')) {
- this._timeoutsHandler.add([T4, SHOW_SHOWDESKTOP_DELAY, () => {
- this._hiddenDesktopWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace();
- this._toggleWorkspaceWindows(true, this._hiddenDesktopWorkspace);
- }]);
- }
- });
-
- this._showDesktopButton.connect('leave-event', () => {
- if (SETTINGS.get_boolean('show-showdesktop-hover')) {
- if (this._timeoutsHandler.getId(T4)) {
- this._timeoutsHandler.remove(T4);
- } else if (this._hiddenDesktopWorkspace) {
- this._toggleWorkspaceWindows(false, this._hiddenDesktopWorkspace);
- }
- }
- });
-
- this.panel.add_child(this._showDesktopButton);
- } else {
- if(!this._showDesktopButton)
- return;
-
- this.panel.remove_child(this._showDesktopButton);
- this._showDesktopButton.destroy();
- this._showDesktopButton = null;
- }
- }
-
- _setShowDesktopButtonStyle() {
- let rgb = this._getBackgroundBrightness() ? "rgba(55, 55, 55, .2)" : "rgba(200, 200, 200, .2)";
-
- for (let i = 0; i < this._showDesktopButton.get_children().length; i++) {
- if (this._showDesktopButton.get_children()[i] == this._showDesktopButton.icon) {
- this._showDesktopButton.remove_child(this._showDesktopButton.icon);
- }
- }
-
- if (this._showDesktopButton) {
- if (SETTINGS.get_boolean('show-showdesktop-icon')) {
- this._showDesktopButton.add_child(this._showDesktopButton.icon);
-
- let buttonSize = SETTINGS.get_int('showdesktop-button-width') + 'px';
- let isVertical = this.checkIfVertical();
- let buttonPadding = isVertical ? buttonSize + ' 0;' : '0 ' + buttonSize + ';';
-
- this._showDesktopButton.set_style('padding: ' + buttonPadding);
- } else {
- let buttonSize = SETTINGS.get_int('showdesktop-button-width') + 'px;';
- let isVertical = this.checkIfVertical();
-
- let style = "border: 0 solid " + rgb + "; padding: 0;";
- style += isVertical ? 'border-top-width:1px;height:' + buttonSize : 'border-left-width:1px;width:' + buttonSize;
-
- this._showDesktopButton.set_style(style);
- this._showDesktopButton[(isVertical ? 'x' : 'y') + '_expand'] = true;
- }
- }
- }
-
- // _getBackgroundBrightness: return true if panel has a bright background color
- _getBackgroundBrightness() {
- return Utils.checkIfColorIsBright(this.dynamicTransparency.backgroundColorRgb);
- }
-
- _toggleWorkspaceWindows(hide, workspace) {
- let time = SHOW_SHOWDESKTOP_TIME * .001;
-
- workspace.list_windows().forEach(w => {
- if (!w.minimized && !w.customJS_ding && w.window_type != Meta.WindowType.DESKTOP) {
- let tweenOpts = {
- opacity: hide ? 0 : 255,
- time: time,
- transition: 'easeOutQuad'
- };
-
- Utils.animateWindowOpacity(w.get_compositor_private(), tweenOpts);
- }
- });
- }
-
- _onShowDesktopButtonPress() {
- let label = 'trackerFocusApp';
-
- this._signalsHandler.removeWithLabel(label);
- this._timeoutsHandler.remove(T5);
-
- if(this._restoreWindowList && this._restoreWindowList.length) {
- this._timeoutsHandler.remove(T4);
-
- let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace();
- let windows = current_workspace.list_windows();
- this._restoreWindowList.forEach(function(w) {
- if(windows.indexOf(w) > -1)
- Main.activateWindow(w);
- });
- this._restoreWindowList = null;
- } else {
- let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace();
- let windows = current_workspace.list_windows().filter(function (w) {
- return w.showing_on_its_workspace() && !w.skip_taskbar;
- });
- windows = global.display.sort_windows_by_stacking(windows);
-
- windows.forEach(function(w) {
- w.minimize();
- });
-
- this._restoreWindowList = windows;
-
- this._timeoutsHandler.add([T5, 20, () => this._signalsHandler.addWithLabel(
- label,
- [
- tracker,
- 'notify::focus-app',
- () => this._restoreWindowList = null
- ]
- )]);
- }
-
- Main.overview.hide();
- }
-
- _initProgressManager() {
- const progressVisible = SETTINGS.get_boolean('progress-show-bar');
- const countVisible = SETTINGS.get_boolean('progress-show-count');
- const pm = this.progressManager;
-
- if(!pm && (progressVisible || countVisible))
- this.progressManager = new Progress.ProgressManager();
- else if (pm)
- Object.keys(pm._entriesByDBusName).forEach((k) => pm._entriesByDBusName[k].setCountVisible(countVisible));
- }
-});
-
-export const SecondaryPanel = GObject.registerClass({
-}, class SecondaryPanel extends St.Widget {
-
- _init(params) {
- super._init(params);
- }
-
- vfunc_allocate(box) {
- this.set_allocation(box);
- }
-});
diff --git a/panelManager.js b/panelManager.js
deleted file mode 100644
index 5a08c43..0000000
--- a/panelManager.js
+++ /dev/null
@@ -1,756 +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 .
- *
- * 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.
- */
-
-import * as Overview from './overview.js';
-import * as Panel from './panel.js';
-import * as PanelSettings from './panelSettings.js';
-import * as Proximity from './proximity.js';
-import * as Utils from './utils.js';
-import * as DesktopIconsIntegration from './desktopIconsIntegration.js';
-
-import GLib from 'gi://GLib';
-import GObject from 'gi://GObject';
-import Clutter from 'gi://Clutter';
-import Meta from 'gi://Meta';
-import Shell from 'gi://Shell';
-import St from 'gi://St';
-
-import * as BoxPointer from 'resource:///org/gnome/shell/ui/boxpointer.js';
-import * as LookingGlass from 'resource:///org/gnome/shell/ui/lookingGlass.js';
-import * as Main from 'resource:///org/gnome/shell/ui/main.js';
-import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
-import * as Layout from 'resource:///org/gnome/shell/ui/layout.js';
-import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
-import {SETTINGS} from './extension.js';
-import {SecondaryMonitorDisplay, WorkspacesView} from 'resource:///org/gnome/shell/ui/workspacesView.js';
-
-
-export const PanelManager = class {
-
- constructor() {
- this.overview = new Overview.Overview();
- this.panelsElementPositions = {};
- this._injectionManager = new InjectionManager();
-
- this._saveMonitors();
- }
-
- enable(reset) {
- 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, SETTINGS.get_boolean('stockgs-keep-top-panel'));
- this.allPanels.push(this.primaryPanel);
- this.overview.enable(this.primaryPanel);
-
- this.setFocusedMonitor(this.dtpPrimaryMonitor);
- }
-
- if (SETTINGS.get_boolean('multi-monitors')) {
- Main.layoutManager.monitors.filter(m => m != this.dtpPrimaryMonitor).forEach(m => {
- this.allPanels.push(this._createPanel(m, true));
- });
- }
-
- global.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;
-
- this._injectionManager.overrideMethod(BoxPointer.BoxPointer.prototype, 'vfunc_get_preferred_height', () => function(forWidth) {
- let alloc = { min_size: 0, natural_size: 0 };
-
- [alloc.min_size, alloc.natural_size] = this.vfunc_get_preferred_height(forWidth);
-
- return panelManager._getBoxPointerPreferredHeight(this, alloc);
- });
- }
-
- this._updatePanelElementPositions();
-
- if (reset) return;
-
- this._desktopIconsUsableArea = new DesktopIconsIntegration.DesktopIconsUsableAreaClass();
-
- this._oldUpdatePanelBarrier = Main.layoutManager._updatePanelBarrier;
- Main.layoutManager._updatePanelBarrier = (panel) => {
- let panelUpdates = panel ? [panel] : this.allPanels;
-
- panelUpdates.forEach(p => newUpdatePanelBarrier.call(Main.layoutManager, p));
- };
- Main.layoutManager._updatePanelBarrier();
-
- this._oldUpdateHotCorners = Main.layoutManager._updateHotCorners;
- Main.layoutManager._updateHotCorners = newUpdateHotCorners.bind(Main.layoutManager);
- Main.layoutManager._updateHotCorners();
-
- if (Main.layoutManager._interfaceSettings) {
- this._enableHotCornersId = Main.layoutManager._interfaceSettings.connect('changed::enable-hot-corners', () => Main.layoutManager._updateHotCorners());
- }
-
- this._oldUpdateWorkspacesViews = Main.overview._overview._controls._workspacesDisplay._updateWorkspacesViews;
- Main.overview._overview._controls._workspacesDisplay._updateWorkspacesViews = this._newUpdateWorkspacesViews.bind(Main.overview._overview._controls._workspacesDisplay);
-
- this._oldSetPrimaryWorkspaceVisible = Main.overview._overview._controls._workspacesDisplay.setPrimaryWorkspaceVisible
- Main.overview._overview._controls._workspacesDisplay.setPrimaryWorkspaceVisible = this._newSetPrimaryWorkspaceVisible.bind(Main.overview._overview._controls._workspacesDisplay);
-
- LookingGlass.LookingGlass.prototype._oldResize = LookingGlass.LookingGlass.prototype._resize;
- LookingGlass.LookingGlass.prototype._resize = _newLookingGlassResize;
-
- LookingGlass.LookingGlass.prototype._oldOpen = LookingGlass.LookingGlass.prototype.open;
- LookingGlass.LookingGlass.prototype.open = _newLookingGlassOpen;
-
- this._signalsHandler = new Utils.GlobalSignalsHandler();
-
- //listen settings
- this._signalsHandler.add(
- [
- SETTINGS,
- [
- 'changed::multi-monitors',
- 'changed::isolate-monitors',
- 'changed::panel-positions',
- 'changed::panel-lengths',
- 'changed::panel-anchors',
- 'changed::stockgs-keep-top-panel'
- ],
- () => this._reset()
- ],
- [
- SETTINGS,
- 'changed::panel-element-positions',
- () => this._updatePanelElementPositions()
- ],
- [
- SETTINGS,
- 'changed::intellihide-key-toggle-text',
- () => this._setKeyBindings(true)
- ],
- [
- SETTINGS,
- 'changed::panel-sizes',
- () => {
- GLib.idle_add(GLib.PRIORITY_LOW, () => {
- this._setDesktopIconsMargins();
- return GLib.SOURCE_REMOVE;
- });
- }
- ],
- [
- Utils.DisplayWrapper.getMonitorManager(),
- 'monitors-changed',
- () => {
- if (Main.layoutManager.primaryMonitor) {
- this._saveMonitors();
- this._reset();
- }
- }
- ]
- );
-
- Panel.panelBoxes.forEach(c => this._signalsHandler.add(
- [
- Main.panel[c],
- 'child-added',
- (parent, child) => {
- this.primaryPanel &&
- child instanceof St.Bin &&
- this._adjustPanelMenuButton(this._getPanelMenuButton(child.get_first_child()), this.primaryPanel.monitor, this.primaryPanel.getPosition())
- }
- ]
- ));
-
- this._setKeyBindings(true);
-
- // keep GS overview.js from blowing away custom panel styles
- if(!SETTINGS.get_boolean('stockgs-keep-top-panel'))
- Object.defineProperty(Main.panel, "style", {configurable: true, set(v) {}});
- }
-
- disable(reset) {
- this.primaryPanel && this.overview.disable();
- this.proximityManager.destroy();
-
- this.allPanels.forEach(p => {
- p.taskbar.iconAnimator.pause();
-
- this._findPanelMenuButtons(p.panelBox).forEach(pmb => {
- if (pmb.menu._boxPointer._dtpGetPreferredHeightId) {
- pmb.menu._boxPointer._container.disconnect(pmb.menu._boxPointer._dtpGetPreferredHeightId);
- }
-
- pmb.menu._boxPointer.sourceActor = pmb.menu._boxPointer._dtpSourceActor;
- delete pmb.menu._boxPointer._dtpSourceActor;
- pmb.menu._boxPointer._userArrowSide = St.Side.TOP;
- })
-
- this._removePanelBarriers(p);
-
- p.disable();
-
- let clipContainer = p.panelBox.get_parent();
-
- Main.layoutManager._untrackActor(p.panelBox);
- Main.layoutManager.removeChrome(clipContainer);
-
- if (p.isStandalone) {
- p.panelBox.destroy();
- } else {
- p.panelBox.remove_child(p);
- p.remove_child(p.panel);
- p.panelBox.add_child(p.panel);
-
- p.panelBox.set_position(clipContainer.x, clipContainer.y);
-
- clipContainer.remove_child(p.panelBox);
- Main.layoutManager.addChrome(p.panelBox, { affectsStruts: true, trackFullscreen: true });
- }
- });
-
- this._injectionManager.clear();
-
- if (Main.layoutManager.primaryMonitor) {
- Main.layoutManager.panelBox.set_position(Main.layoutManager.primaryMonitor.x, Main.layoutManager.primaryMonitor.y);
- Main.layoutManager.panelBox.set_size(Main.layoutManager.primaryMonitor.width, -1);
- }
-
- if (reset) return;
-
- this._setKeyBindings(false);
-
- this._signalsHandler.destroy();
-
- Main.layoutManager._updateHotCorners = this._oldUpdateHotCorners;
- Main.layoutManager._updateHotCorners();
-
- 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;
- }
-
- toggleDash() {
- this.overview.toggleDash();
- }
-
- _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 SecondaryMonitorDisplay(i,
- this._controls,
- this._scrollAdjustment,
- this._fitModeAdjustment,
- this._overviewAdjustment);
- Main.layoutManager.overviewGroup.add_child(view);
- }
-
- this._workspacesViews.push(view);
- }
- }
-
- _saveMonitors() {
- //Mutter meta_monitor_manager_get_primary_monitor (global.display.get_primary_monitor()) doesn't return the same
- //monitor as GDK gdk_screen_get_primary_monitor (imports.gi.Gdk.Screen.get_default().get_primary_monitor()).
- //Since the Mutter function is what's used in gnome-shell and we can't access it from the settings dialog, store
- //the monitors information in a setting so we can use the same monitor indexes as the ones in gnome-shell
- let keyMonitors = 'available-monitors';
- let primaryIndex = Main.layoutManager.primaryIndex;
- let newMonitors = [primaryIndex];
-
- Main.layoutManager.monitors.filter(m => m.index != primaryIndex).forEach(m => newMonitors.push(m.index));
-
- SETTINGS.set_value(keyMonitors, new GLib.Variant('ai', newMonitors));
- }
-
- checkIfFocusedMonitor(monitor) {
- return Main.overview._overview._controls._workspacesDisplay._primaryIndex == monitor.index;
- }
-
- _createPanel(monitor, isStandalone) {
- let panelBox;
- let panel;
- let clipContainer = new Clutter.Actor();
-
- if (isStandalone) {
- panelBox = new St.BoxLayout({ name: 'panelBox' });
- } else {
- panelBox = Main.layoutManager.panelBox;
- Main.layoutManager._untrackActor(panelBox);
- panelBox.remove_child(Main.panel);
- Main.layoutManager.removeChrome(panelBox);
- }
-
- Main.layoutManager.addChrome(clipContainer, { affectsInputRegion: false });
- clipContainer.add_child(panelBox);
- Main.layoutManager.trackChrome(panelBox, { trackFullscreen: true, affectsStruts: true, affectsInputRegion: true });
-
- panel = new Panel.Panel(this, monitor, panelBox, isStandalone);
- panelBox.add_child(panel);
- panel.enable();
-
- panelBox.visible = true;
- if (monitor.inFullscreen) {
- panelBox.hide();
- }
- panelBox.set_position(0, 0);
-
- return panel;
- }
-
- _reset() {
- this.disable(true);
- this.allPanels = [];
- this.enable(true);
- }
-
- _updatePanelElementPositions() {
- this.panelsElementPositions = PanelSettings.getSettingsJson(SETTINGS, 'panel-element-positions');
- this.allPanels.forEach(p => p.updateElementPositions());
- }
-
- _adjustPanelMenuButton(button, monitor, arrowSide) {
- if (button) {
- button.menu._boxPointer._dtpSourceActor = button.menu._boxPointer.sourceActor;
- button.menu._boxPointer.sourceActor = button;
- button.menu._boxPointer._userArrowSide = arrowSide;
- button.menu._boxPointer._dtpInPanel = 1;
-
- if (!button.menu._boxPointer.vfunc_get_preferred_height) {
- button.menu._boxPointer._dtpGetPreferredHeightId = button.menu._boxPointer._container.connect('get-preferred-height', (actor, forWidth, alloc) => {
- this._getBoxPointerPreferredHeight(button.menu._boxPointer, alloc, monitor);
- });
- }
- }
- }
-
- _getBoxPointerPreferredHeight(boxPointer, alloc, monitor) {
- if (boxPointer._dtpInPanel && boxPointer.sourceActor && SETTINGS.get_boolean('intellihide')) {
- monitor = monitor || Main.layoutManager.findMonitorForActor(boxPointer.sourceActor);
- let panel = Utils.find(global.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, SETTINGS, keys[k], Shell.ActionMode.NORMAL);
- }
- });
- }
-
-};
-
-// This class drives long-running icon animations, to keep them running in sync
-// with each other.
-export const IconAnimator = class {
-
- constructor(actor) {
- this._count = 0;
- this._started = false;
- this._animations = {
- dance: [],
- };
- this._timeline = new Clutter.Timeline({
- duration: 3000,
- repeat_count: -1,
- });
-
- /* Just use the construction property when no need to support 3.36 */
- if (this._timeline.set_actor)
- this._timeline.set_actor(actor);
-
- this._timeline.connect('new-frame', () => {
- const progress = this._timeline.get_progress();
- const danceRotation = progress < 1/6 ? 15*Math.sin(progress*24*Math.PI) : 0;
- const dancers = this._animations.dance;
- for (let i = 0, iMax = dancers.length; i < iMax; i++) {
- dancers[i].target.rotation_angle_z = danceRotation;
- }
- });
- }
-
- destroy() {
- this._timeline.stop();
- this._timeline = null;
- for (let name in this._animations) {
- const pairs = this._animations[name];
- for (let i = 0, iMax = pairs.length; i < iMax; i++) {
- const pair = pairs[i];
- pair.target.disconnect(pair.targetDestroyId);
- }
- }
- this._animations = null;
- }
-
- pause() {
- if (this._started && this._count > 0) {
- this._timeline.stop();
- }
- this._started = false;
- }
-
- start() {
- if (!this._started && this._count > 0) {
- this._timeline.start();
- }
- this._started = true;
- }
-
- addAnimation(target, name) {
- const targetDestroyId = target.connect('destroy', () => this.removeAnimation(target, name));
- this._animations[name].push({ target: target, targetDestroyId: targetDestroyId });
- if (this._started && this._count === 0) {
- this._timeline.start();
- }
- this._count++;
- }
-
- removeAnimation(target, name) {
- const pairs = this._animations[name];
- for (let i = 0, iMax = pairs.length; i < iMax; i++) {
- const pair = pairs[i];
- if (pair.target === target) {
- target.disconnect(pair.targetDestroyId);
- pairs.splice(i, 1);
- this._count--;
- if (this._started && this._count === 0) {
- this._timeline.stop();
- }
- return;
- }
- }
- }
-};
-
-function newUpdateHotCorners() {
- // destroy old hot corners
- this.hotCorners.forEach(function(corner) {
- if (corner)
- corner.destroy();
- });
- this.hotCorners = [];
-
- //global.settings is ubuntu specific setting to disable the hot corner (Tweak tool > Top Bar > Activities Overview Hot Corner)
- //this._interfaceSettings is for the setting to disable the hot corner introduced in gnome-shell 3.34
- if ((global.settings.list_keys().indexOf('enable-hot-corners') >= 0 && !global.settings.get_boolean('enable-hot-corners')) ||
- (this._interfaceSettings && !this._interfaceSettings.get_boolean('enable-hot-corners'))) {
- this.emit('hot-corners-changed');
- return;
- }
-
- // build new hot corners
- for (let i = 0; i < this.monitors.length; i++) {
- let panel = Utils.find(global.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();
-}
diff --git a/panelPositions.js b/panelPositions.js
deleted file mode 100644
index 6a4c79a..0000000
--- a/panelPositions.js
+++ /dev/null
@@ -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 .
- *
- * 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: 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 },
-];
-
-export const optionDialogFunctions = {};
-
-optionDialogFunctions[DATE_MENU] = '_showDateMenuOptions';
-optionDialogFunctions[DESKTOP_BTN] = '_showDesktopButtonOptions';
-
-export function checkIfCentered(position) {
- return position == CENTERED || position == CENTERED_MONITOR;
-}
diff --git a/panelSettings.js b/panelSettings.js
deleted file mode 100644
index d00af83..0000000
--- a/panelSettings.js
+++ /dev/null
@@ -1,111 +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 .
- */
-
-import * as Pos from './panelPositions.js';
-
-/** Return object representing a settings value that is stored as JSON. */
-export function getSettingsJson(settings, setting) {
- try {
- return JSON.parse(settings.get_string(setting));
- } catch(e) {
- log('Error parsing positions: ' + e.message);
- }
-}
-/** Write value object as JSON to setting in settings. */
-export function setSettingsJson(settings, setting, value) {
- try {
- const json = JSON.stringify(value);
- settings.set_string(setting, json);
- } catch(e) {
- log('Error serializing setting: ' + e.message);
- }
-}
-
-/** Returns size of panel on a specific monitor, in pixels. */
-export function getPanelSize(settings, monitorIndex) {
- const sizes = getSettingsJson(settings, 'panel-sizes');
- // Pull in deprecated setting if panel-sizes does not have setting for monitor.
- const fallbackSize = settings.get_int('panel-size');
- const theDefault = 48;
- return sizes[monitorIndex] || fallbackSize || theDefault;
-}
-
-export function setPanelSize(settings, monitorIndex, value) {
- if (!(Number.isInteger(value) && value <= 128 && value >= 16)) {
- log('Not setting invalid panel size: ' + value);
- return;
- }
- let sizes = getSettingsJson(settings, 'panel-sizes');
- sizes[monitorIndex] = value;
- setSettingsJson(settings, 'panel-sizes', sizes);
-}
-
-/**
- * Returns length of panel on a specific monitor, as a whole number percent,
- * from settings. e.g. 100
- */
-export function getPanelLength(settings, monitorIndex) {
- const lengths = getSettingsJson(settings, 'panel-lengths');
- const theDefault = 100;
- return lengths[monitorIndex] || theDefault;
-}
-
-export function setPanelLength(settings, monitorIndex, value) {
- if (!(Number.isInteger(value) && value <= 100 && value >= 0)) {
- log('Not setting invalid panel length: ' + value);
- return;
- }
- let lengths = getSettingsJson(settings, 'panel-lengths');
- lengths[monitorIndex] = value;
- setSettingsJson(settings, 'panel-lengths', lengths);
-}
-
-/** Returns position of panel on a specific monitor. */
-export function getPanelPosition(settings, monitorIndex) {
- const positions = getSettingsJson(settings, 'panel-positions');
- const fallbackPosition = settings.get_string('panel-position');
- const theDefault = Pos.BOTTOM;
- return positions[monitorIndex] || fallbackPosition || theDefault;
-}
-
-export function setPanelPosition(settings, monitorIndex, value) {
- if (!(value === Pos.TOP || value === Pos.BOTTOM || value === Pos.LEFT
- || value === Pos.RIGHT)) {
- log('Not setting invalid panel position: ' + value);
- return;
- }
- const positions = getSettingsJson(settings, 'panel-positions');
- positions[monitorIndex] = value;
- setSettingsJson(settings, 'panel-positions', positions);
-}
-
-/** Returns anchor location of panel on a specific monitor. */
-export function getPanelAnchor(settings, monitorIndex) {
- const anchors = getSettingsJson(settings, 'panel-anchors');
- const theDefault = Pos.MIDDLE;
- return anchors[monitorIndex] || theDefault;
-}
-
-export function setPanelAnchor(settings, monitorIndex, value) {
- if (!(value === Pos.START || value === Pos.MIDDLE || value === Pos.END)) {
- log('Not setting invalid panel anchor: ' + value);
- return;
- }
- const anchors = getSettingsJson(settings, 'panel-anchors');
- anchors[monitorIndex] = value;
- setSettingsJson(settings, 'panel-anchors', anchors);
-}
diff --git a/panelStyle.js b/panelStyle.js
deleted file mode 100644
index 8b1b33f..0000000
--- a/panelStyle.js
+++ /dev/null
@@ -1,161 +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 .
- *
- * 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);
- }
- }
-
-}
diff --git a/po/af.po b/po/af.po
index 6353ad4..a13b23b 100644
--- a/po/af.po
+++ b/po/af.po
@@ -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"
diff --git a/po/ar.po b/po/ar.po
index 9a6a5a0..bb4805b 100644
--- a/po/ar.po
+++ b/po/ar.po
@@ -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 "عزل مساحات العمل والشاشات في إعدادات تبديل التطبيقات"
diff --git a/po/be.po b/po/be.po
index c185a70..3cb2c86 100644
--- a/po/be.po
+++ b/po/be.po
@@ -21,6 +21,3 @@ msgstr "Паказаць значок працоўнага стала"
msgid "Show Desktop button padding (px)"
msgstr "Пракладка Паказаць кнопку працоўнага стала (px)"
-
-msgid "Floating rounded theme"
-msgstr "Плаваючая круглявая тэма"
diff --git a/po/bg.po b/po/bg.po
index 179f7a7..79a588b 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -21,6 +21,3 @@ msgstr "Показване на икона на работния плот"
msgid "Show Desktop button padding (px)"
msgstr "Бутон Покажи работния плот - подложка (px)"
-
-msgid "Floating rounded theme"
-msgstr "Плаваща заоблена тема"
diff --git a/po/bn.po b/po/bn.po
index 3da79f3..f771f8f 100644
--- a/po/bn.po
+++ b/po/bn.po
@@ -18,6 +18,3 @@ msgstr "ডেস্কটপ আইকন দেখান"
msgid "Show Desktop button padding (px)"
msgstr "Show Desktop button প্যাডিং (px আকারে)"
-
-msgid "Floating rounded theme"
-msgstr "ভাসমান বৃত্তাকার থিম"
diff --git a/po/ca.po b/po/ca.po
index b629d33..00aae2d 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -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"
diff --git a/po/cs.po b/po/cs.po
index 94e3c78..9b9dc22 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -1412,9 +1412,6 @@ msgstr "Zobrazit ikonu plochy"
msgid "Show Desktop button padding (px)"
msgstr "vybarvení tlačítka Zobraz plochu"
-msgid "Floating rounded theme"
-msgstr "Plovoucí zaoblený vzhled"
-
#~ msgid "Top, with plugin icons collapsed to bottom"
#~ msgstr "Nahoře, ikony dole"
diff --git a/po/da.po b/po/da.po
index 11aaffc..bb612c3 100644
--- a/po/da.po
+++ b/po/da.po
@@ -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"
diff --git a/po/de.po b/po/de.po
index 3fe146c..3b7a541 100644
--- a/po/de.po
+++ b/po/de.po
@@ -1479,9 +1479,6 @@ msgstr "Desktop-Symbol anzeigen"
msgid "Show Desktop button padding (px)"
msgstr "Padding (px) für Desktop-Symbol anzeigen"
-msgid "Floating rounded theme"
-msgstr "Schwebendes abgerundetes Thema"
-
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Isolieren Sie Arbeitsbereiche und Monitore in den Anwendungswechseleinstellungen"
diff --git a/po/el.po b/po/el.po
index ba3ee8f..b02cd6e 100644
--- a/po/el.po
+++ b/po/el.po
@@ -21,6 +21,3 @@ msgstr "Εμφάνιση επιφάνειας εργασίας"
msgid "Show Desktop button padding (px)"
msgstr "Εμφάνισε διαχωριστικό"
-
-msgid "Floating rounded theme"
-msgstr "Κυμαινόμενο στρογγυλεμένο θέμα"
diff --git a/po/es.po b/po/es.po
index 20b7d2b..a2441fa 100644
--- a/po/es.po
+++ b/po/es.po
@@ -1507,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"
diff --git a/po/et.po b/po/et.po
index 339ed56..36b3692 100644
--- a/po/et.po
+++ b/po/et.po
@@ -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"
diff --git a/po/fa.po b/po/fa.po
index a7268ec..9991070 100644
--- a/po/fa.po
+++ b/po/fa.po
@@ -1466,9 +1466,6 @@ msgstr "نمایش آیکون دسکتاپ"
msgid "Show Desktop button padding (px)"
msgstr "حاشیهی دکمهی نمایش دسکتاپ (px)"
-msgid "Floating rounded theme"
-msgstr "تم گرد و شناور"
-
#~ msgid "Show Details"
#~ msgstr "نمایش جزییات"
diff --git a/po/fi.po b/po/fi.po
index da51cc9..8a87468 100644
--- a/po/fi.po
+++ b/po/fi.po
@@ -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"
diff --git a/po/fr.po b/po/fr.po
index 12caeef..3903c2f 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -3,22 +3,22 @@
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR , YEAR.
# Laurent Tréguier , 2019.
-# Charles Gagnon , 2019-2023.
+# Charles Gagnon , 2019-2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: DAsh To PAnel\n"
+"Project-Id-Version: Dash To Panel\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-09-29 15:58+0200\n"
-"PO-Revision-Date: 2024-09-29 16:02+0200\n"
-"Last-Translator: Delphin PETER\n"
+"POT-Creation-Date: 2025-03-09 23:44-0400\n"
+"PO-Revision-Date: 2025-03-09 23:48-0400\n"
+"Last-Translator: Charles Gagnon \n"
"Language-Team: French\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Generator: Poedit 3.4.2\n"
+"X-Generator: Gtranslator 47.1\n"
"X-Poedit-Basepath: ..\n"
"X-Poedit-SearchPath-0: ui\n"
"X-Poedit-SearchPath-1: windowPreview.js\n"
@@ -39,498 +39,510 @@ msgstr ""
"X-Poedit-SearchPath-16: desktopIconsIntegration.js\n"
"X-Poedit-SearchPath-17: appIcons.js\n"
-#: appIcons.js:1485 appIcons.js:1495 ui/BoxMiddleClickOptions.ui:32
-#: ui/BoxMiddleClickOptions.ui:60 ui/BoxMiddleClickOptions.ui:88
-msgid "Quit"
-msgstr "Quitter"
+#: src/extension.js:96
+msgid "Dash to Panel has been updated!"
+msgstr "Dash to Panel a été mis à jour!"
-#: appIcons.js:1497
-#, javascript-format
-msgid "Quit %d Window"
-msgid_plural "Quit %d Windows"
-msgstr[0] "Fermer %d fenêtre"
-msgstr[1] "Fermer %d fenêtres"
+#: src/extension.js:97
+msgid "You are now running version"
+msgstr "Vous utilisez maintenant la version"
-#: appIcons.js:1772
-msgid "Power options"
-msgstr "Options d'alimentation"
+#: src/extension.js:103
+msgid "See what's new"
+msgstr "Voir les nouveautés"
-#: appIcons.js:1777
-msgid "Event logs"
-msgstr "Journaux d'évènements"
-
-#: appIcons.js:1782
-msgid "System"
-msgstr "Système"
-
-#: appIcons.js:1787
-msgid "Device Management"
-msgstr "Gestionnaire de périphériques"
-
-#: appIcons.js:1792
-msgid "Disk Management"
-msgstr "Gestionnaire de disques"
-
-#: appIcons.js:1805
-msgid "Terminal"
-msgstr "Terminal"
-
-#: appIcons.js:1810
-msgid "System Monitor"
-msgstr "Moniteur système"
-
-#: appIcons.js:1815
-msgid "Files"
-msgstr "Fichiers"
-
-#: appIcons.js:1820
-msgid "Extensions"
-msgstr "Extensions"
-
-#: appIcons.js:1825
-msgid "Settings"
-msgstr "Paramètres"
-
-#: appIcons.js:1836
-msgid "Unlock taskbar"
-msgstr "Déverrouiller la barre des tâches"
-
-#: appIcons.js:1836
-msgid "Lock taskbar"
-msgstr "Verrouiller la barre des tâches"
-
-#: appIcons.js:1841
-msgid "Taskbar Settings"
-msgstr "Paramètres de la barre des tâches"
-
-#: appIcons.js:1846
-msgid "Restore Windows"
-msgstr "Restaurer les fenêtres"
-
-#: appIcons.js:1846
-msgid "Show Desktop"
-msgstr "Afficher le bureau"
-
-#: panel.js:171
-msgid "Top Bar"
-msgstr "Panneau du haut"
-
-#: prefs.js:246
+#: src/prefs.js:275
msgid "Show Desktop button height (px)"
msgstr "Hauteur du bouton Afficher le Bureau (px)"
-#: prefs.js:246
+#: src/prefs.js:276
msgid "Show Desktop button width (px)"
msgstr "Longueur du bouton Afficher le Bureau (px)"
-#: prefs.js:258
-msgid "Unavailable when gnome-shell top panel is present"
-msgstr "Indisponible quand le panneau de gnome-shell est présent"
-
-#: prefs.js:316 ui/SettingsPosition.ui:148 ui/SettingsStyle.ui:149
+#: src/prefs.js:348 ui/SettingsPosition.ui.h:13 ui/SettingsStyle.ui.h:19
msgid "Left"
msgstr "Gauche"
-#: prefs.js:317
+#: src/prefs.js:349
msgid "Center"
msgstr "Centre"
-#: prefs.js:318 ui/SettingsPosition.ui:157 ui/SettingsStyle.ui:157
+#: src/prefs.js:350 ui/SettingsPosition.ui.h:14 ui/SettingsStyle.ui.h:20
msgid "Right"
msgstr "Droit"
-#: prefs.js:320 ui/BoxWindowPreviewOptions.ui:330 ui/SettingsPosition.ui:139
-#: ui/SettingsStyle.ui:141
+#: src/prefs.js:352 ui/BoxWindowPreviewOptions.ui.h:38
+#: ui/SettingsPosition.ui.h:12 ui/SettingsStyle.ui.h:18
msgid "Top"
msgstr "Haut"
-#: prefs.js:321 prefs.js:326 ui/SettingsPosition.ui:210
+#: src/prefs.js:353 src/prefs.js:358 ui/SettingsPosition.ui.h:22
msgid "Middle"
msgstr "Milieu"
-#: prefs.js:322 ui/BoxWindowPreviewOptions.ui:321 ui/SettingsPosition.ui:130
-#: ui/SettingsStyle.ui:134
+#: src/prefs.js:354 ui/BoxWindowPreviewOptions.ui.h:37
+#: ui/SettingsPosition.ui.h:11 ui/SettingsStyle.ui.h:17
msgid "Bottom"
msgstr "Bas"
-#: prefs.js:325 ui/SettingsPosition.ui:209
+#: src/prefs.js:357 ui/SettingsPosition.ui.h:21
msgid "Start"
msgstr "Début"
-#: prefs.js:327 ui/SettingsPosition.ui:211
+#: src/prefs.js:359 ui/SettingsPosition.ui.h:23
msgid "End"
msgstr "Fin"
-#: prefs.js:412
+#: src/prefs.js:484
msgid "Show Applications button"
msgstr "Bouton Afficher les Applications"
-#: prefs.js:413
+#: src/prefs.js:485
msgid "Activities button"
msgstr "Bouton Activités"
-#: prefs.js:414
+#: src/prefs.js:486
msgid "Taskbar"
msgstr "Barre des tâches"
-#: prefs.js:415
+#: src/prefs.js:487
msgid "Date menu"
msgstr "Horloge"
-#: prefs.js:416
+#: src/prefs.js:488
msgid "System menu"
msgstr "Menu système"
-#: prefs.js:417
+#: src/prefs.js:489
msgid "Left box"
msgstr "Zone gauche"
-#: prefs.js:418
+#: src/prefs.js:490
msgid "Center box"
msgstr "Zone centre"
-#: prefs.js:419
+#: src/prefs.js:491
msgid "Right box"
msgstr "Zone droite"
-#: prefs.js:420
+#: src/prefs.js:492
msgid "Desktop button"
msgstr "Bouton Afficher le Bureau"
-#: prefs.js:426
+#: src/prefs.js:502 src/prefs.js:2788
msgid "Move up"
msgstr "Déplacer vers le haut"
-#: prefs.js:428
+#: src/prefs.js:504 src/prefs.js:2796
msgid "Move down"
msgstr "Déplacer vers le bas"
-#: prefs.js:430
+#: src/prefs.js:510
msgid "Visible"
msgstr "Visible"
-#: prefs.js:431
+#: src/prefs.js:514
msgid "Select element position"
msgstr "Sélectionner la position de l'élément"
-#: prefs.js:442
+#: src/prefs.js:528
msgid "Stacked to top"
msgstr "Empilé en haut"
-#: prefs.js:442
+#: src/prefs.js:528
msgid "Stacked to left"
msgstr "Empilé à gauche"
-#: prefs.js:443
+#: src/prefs.js:532
msgid "Stacked to bottom"
msgstr "Empilé en bas"
-#: prefs.js:443
+#: src/prefs.js:532
msgid "Stacked to right"
msgstr "Empilé à droite"
-#: prefs.js:444
+#: src/prefs.js:534
msgid "Centered"
msgstr "Centré"
-#: prefs.js:445
+#: src/prefs.js:535
msgid "Monitor Center"
msgstr "Centre de l'écran "
-#: prefs.js:464
+#: src/prefs.js:562
msgid "More options"
msgstr "Plus d'options"
-#: prefs.js:496
+#: src/prefs.js:597
msgid "Reset to defaults"
msgstr "Restaurer les paramètres par défaut"
-#: prefs.js:519
+#: src/prefs.js:620
msgid "Show Applications options"
msgstr "Options du bouton Afficher les Applications"
-#: prefs.js:529
+#: src/prefs.js:643
msgid "Open icon"
msgstr "Choisir l'icône"
-#: prefs.js:576
+#: src/prefs.js:708
msgid "Show Desktop options"
msgstr "Options du bouton Afficher le Bureau"
-#: prefs.js:660
+#: src/prefs.js:800
+msgid "Primary monitor"
+msgstr "Écran principal"
+
+#: src/prefs.js:801
+msgid "Monitor "
+msgstr "Écran "
+
+#: src/prefs.js:928
+msgid "Running Indicator Options"
+msgstr "Options de l'indicateur d'activité"
+
+#: src/prefs.js:1461
+msgid "Dynamic opacity options"
+msgstr "Options d'opacité dynamique"
+
+#: src/prefs.js:1710
+msgid "Intellihide options"
+msgstr "Options du masquage intelligent"
+
+#: src/prefs.js:1916
+msgid "Window preview options"
+msgstr "Options de la prévisualisation"
+
+#: src/prefs.js:2467
+msgid "Ungrouped application options"
+msgstr "Options des applications dégroupées"
+
+#: src/prefs.js:2634
+msgid "Customize middle-click behavior"
+msgstr "Modifier l'action du clic de la molette"
+
+#: src/prefs.js:2763
+msgid "Text"
+msgstr "Texte"
+
+#: src/prefs.js:2772
+msgid "Command"
+msgstr "Commande"
+
+#: src/prefs.js:2804
+msgid "Remove"
+msgstr "Retirer"
+
+#: src/prefs.js:2832
+msgid "Customize panel scroll behavior"
+msgstr "Modifier l'action du défilement de la souris sur le panneau"
+
+#: src/prefs.js:2878
+msgid "Customize icon scroll behavior"
+msgstr "Modifier l'action du défilement de la souris sur une application"
+
+#: src/prefs.js:3002
+msgid "Advanced hotkeys options"
+msgstr "Raccourcis avancés"
+
+#: src/prefs.js:3030
+msgid "Secondary Menu Options"
+msgstr "Options du menu secondaire"
+
+#: src/prefs.js:3230
#, javascript-format
msgid "%d ms"
msgstr "%d ms"
-#: prefs.js:665
+#: src/prefs.js:3236
#, javascript-format
msgid "%d °"
msgstr "%d °"
-#: prefs.js:670 prefs.js:675
+#: src/prefs.js:3242 src/prefs.js:3248
#, javascript-format
msgid "%d %%"
msgstr "%d %%"
-#: prefs.js:680
+#: src/prefs.js:3254
#, javascript-format
msgid "%.1f"
msgstr "%.1f"
-#: prefs.js:685
+#: src/prefs.js:3260
#, javascript-format
msgid "%d icon"
msgid_plural "%d icons"
msgstr[0] "%d icône"
msgstr[1] "%d icônes"
-#: prefs.js:787
-msgid "Running Indicator Options"
-msgstr "Options de l'indicateur d'activité"
-
-#: prefs.js:933
-msgid "Primary monitor"
-msgstr "Écran principal"
-
-#: prefs.js:933
-msgid "Monitor "
-msgstr "Écran "
-
-#: prefs.js:1127
-msgid "Dynamic opacity options"
-msgstr "Options d'opacité dynamique"
-
-#: prefs.js:1260
-msgid "Intellihide options"
-msgstr "Options du masquage intelligent"
-
-#: prefs.js:1366
-msgid "Window preview options"
-msgstr "Options de la prévisualisation"
-
-#: prefs.js:1642
-msgid "Ungrouped application options"
-msgstr "Options des applications dégroupées"
-
-#: prefs.js:1721
-msgid "Customize middle-click behavior"
-msgstr "Modifier l'action du clic de la molette"
-
-#: prefs.js:1771
-msgid "Customize panel scroll behavior"
-msgstr "Modifier l'action du défilement de la souris sur le panneau"
-
-#: prefs.js:1799
-msgid "Customize icon scroll behavior"
-msgstr "Modifier l'action du défilement de la souris sur une application"
-
-#: prefs.js:1880
-msgid "Advanced hotkeys options"
-msgstr "Raccourcis avancés"
-
-#: prefs.js:1898
-msgid "Secondary Menu Options"
-msgstr "Options du menu secondaire"
-
-#: prefs.js:1925 ui/SettingsFineTune.ui:268
-msgid "Advanced Options"
-msgstr "Options avancées"
-
-#: prefs.js:2041
+#: src/prefs.js:3387
msgid "App icon animation options"
msgstr "Options d'animation des icônes d'application"
-#: prefs.js:2089
+#: src/prefs.js:3510
+msgid "App icon highlight options"
+msgstr "Options d'animation du surlignement des icônes d'application"
+
+#: src/prefs.js:3599
msgid "Export settings"
msgstr "Exporter les paramètres"
-#: prefs.js:2105
+#: src/prefs.js:3620
msgid "Import settings"
msgstr "Importer des paramètres"
-#: ui/BoxAdvancedOptions.ui:19
-msgid "Nothing yet!"
-msgstr "Rien pour l'instant !"
+#: src/appIcons.js:1911 src/appIcons.js:1928 ui/BoxMiddleClickOptions.ui.h:11
+msgid "Quit"
+msgstr "Quitter"
-#: ui/BoxAdvancedOptions.ui:20
-msgid "For real..."
-msgstr "Pour vrai..."
+#: src/appIcons.js:1931
+#, javascript-format
+msgid "Quit %d Window"
+msgid_plural "Quit %d Windows"
+msgstr[0] "Fermer %d fenêtre"
+msgstr[1] "Fermer %d fenêtres"
-#: ui/BoxAnimateAppIconHoverOptions.ui:62
+#: src/appIcons.js:2253
+msgid "Power options"
+msgstr "Options d'alimentation"
+
+#: src/appIcons.js:2258
+msgid "Event logs"
+msgstr "Journaux d'évènements"
+
+#: src/appIcons.js:2263
+msgid "System"
+msgstr "Système"
+
+#: src/appIcons.js:2268
+msgid "Device Management"
+msgstr "Gestionnaire de périphériques"
+
+#: src/appIcons.js:2273
+msgid "Disk Management"
+msgstr "Gestionnaire de disques"
+
+msgid "System Monitor"
+msgstr "Moniteur système"
+
+msgid "Files"
+msgstr "Fichiers"
+
+msgid "Settings"
+msgstr "Paramètres"
+
+#: src/appIcons.js:2304
+msgid "Unlock taskbar"
+msgstr "Déverrouiller la barre des tâches"
+
+#: src/appIcons.js:2305
+msgid "Lock taskbar"
+msgstr "Verrouiller la barre des tâches"
+
+#: src/appIcons.js:2315
+msgid "Gnome Settings"
+msgstr "Paramètres Gnome"
+
+#: src/appIcons.js:2319
+msgid "Taskbar Settings"
+msgstr "Paramètres de la barre des tâches"
+
+#: src/appIcons.js:2326
+msgid "Restore Windows"
+msgstr "Restaurer les fenêtres"
+
+#: src/appIcons.js:2327
+msgid "Show Desktop"
+msgstr "Afficher le bureau"
+
+#: src/taskbar.js:66
+msgid "Hide and donation options"
+msgstr "Cacher et options de don"
+
+#: src/taskbar.js:79
+msgid "Thank you!"
+msgstr "Merci!"
+
+#: src/taskbar.js:79
+msgid "Please donate :)"
+msgstr "Merci de faire un don :)"
+
+#: ui/BoxAnimateAppIconHoverOptions.ui.h:1
msgid "Animation type"
msgstr "Type d'animation"
-#: ui/BoxAnimateAppIconHoverOptions.ui:67
+#: ui/BoxAnimateAppIconHoverOptions.ui.h:2
msgid "Simple"
msgstr "Simple"
-#: ui/BoxAnimateAppIconHoverOptions.ui:68
+#: ui/BoxAnimateAppIconHoverOptions.ui.h:3
msgid "Ripple"
msgstr "Ondulation"
-#: ui/BoxAnimateAppIconHoverOptions.ui:69
+#: ui/BoxAnimateAppIconHoverOptions.ui.h:4
msgid "Plank"
msgstr "Planche"
-#: ui/BoxAnimateAppIconHoverOptions.ui:84
+#: ui/BoxAnimateAppIconHoverOptions.ui.h:5
msgid "Duration"
msgstr "Durée"
-#: ui/BoxAnimateAppIconHoverOptions.ui:101
+#: ui/BoxAnimateAppIconHoverOptions.ui.h:6
msgid "Rotation"
msgstr "Rotation"
-#: ui/BoxAnimateAppIconHoverOptions.ui:118
+#: ui/BoxAnimateAppIconHoverOptions.ui.h:7
msgid "Travel"
msgstr "Déplacement"
-#: ui/BoxAnimateAppIconHoverOptions.ui:135
+#: ui/BoxAnimateAppIconHoverOptions.ui.h:8
msgid "Zoom"
msgstr "Zoom"
-#: ui/BoxAnimateAppIconHoverOptions.ui:152
+#: ui/BoxAnimateAppIconHoverOptions.ui.h:9
msgid "Convexity"
msgstr "Convexité"
-#: ui/BoxAnimateAppIconHoverOptions.ui:169
+#: ui/BoxAnimateAppIconHoverOptions.ui.h:10
msgid "Extent"
msgstr "Étendue"
-#: ui/BoxDotOptions.ui:37
+#: ui/BoxDotOptions.ui.h:1
msgid "Highlight focused application"
msgstr "Surligner l'application active"
-#: ui/BoxDotOptions.ui:54
+#: ui/BoxDotOptions.ui.h:2
msgid "Icon dominant color"
msgstr "Couleur d'icône dominante"
-#: ui/BoxDotOptions.ui:65
+#: ui/BoxDotOptions.ui.h:3
msgid "Custom color"
msgstr "Couleur personnalisée"
-#: ui/BoxDotOptions.ui:76
+#: ui/BoxDotOptions.ui.h:4
msgid "Highlight opacity"
msgstr "Opacité du surlignement"
-#: ui/BoxDotOptions.ui:96
+#: ui/BoxDotOptions.ui.h:5
msgid "Indicator size (px)"
msgstr "Taille de l'indicateur (px)"
-#: ui/BoxDotOptions.ui:109
+#: ui/BoxDotOptions.ui.h:6
msgid "Indicator color - Icon Dominant"
msgstr "Couleur de l'indicateur - Icône dominante"
-#: ui/BoxDotOptions.ui:126
+#: ui/BoxDotOptions.ui.h:7
msgid "Indicator color - Override Theme"
msgstr "Couleur de l'indicateur - Remplacer le thème"
-#: ui/BoxDotOptions.ui:142 ui/BoxDotOptions.ui:215
+#: ui/BoxDotOptions.ui.h:8
msgid "1 window open (or ungrouped)"
msgstr "1 fenêtre ouverte (ou dégroupée)"
-#: ui/BoxDotOptions.ui:146 ui/BoxDotOptions.ui:219
+#: ui/BoxDotOptions.ui.h:9
msgid "Apply to all"
msgstr "Appliquer à tout"
-#: ui/BoxDotOptions.ui:159 ui/BoxDotOptions.ui:232
+#: ui/BoxDotOptions.ui.h:10
msgid "2 windows open"
msgstr "2 fenêtres ouvertes"
-#: ui/BoxDotOptions.ui:170 ui/BoxDotOptions.ui:243
+#: ui/BoxDotOptions.ui.h:11
msgid "3 windows open"
msgstr "3 fenêtres ouvertes"
-#: ui/BoxDotOptions.ui:181 ui/BoxDotOptions.ui:254
+#: ui/BoxDotOptions.ui.h:12
msgid "4+ windows open"
msgstr "4+ fenêtres ouvertes"
-#: ui/BoxDotOptions.ui:198
+#: ui/BoxDotOptions.ui.h:13
msgid "Use different for unfocused"
msgstr "Style différent pour les applications inactives"
-#: ui/BoxDynamicOpacityOptions.ui:37
+#: ui/BoxDynamicOpacityOptions.ui.h:1
msgid "The panel background opacity is affected by"
msgstr "L'opacité de l'arrière-plan du panneau est affectée par"
-#: ui/BoxDynamicOpacityOptions.ui:42 ui/BoxIntellihideOptions.ui:69
+#: ui/BoxDynamicOpacityOptions.ui.h:2 ui/BoxIntellihideOptions.ui.h:3
msgid "All windows"
msgstr "Toutes les fenêtres"
-#: ui/BoxDynamicOpacityOptions.ui:43 ui/BoxIntellihideOptions.ui:70
+#: ui/BoxDynamicOpacityOptions.ui.h:3 ui/BoxIntellihideOptions.ui.h:4
msgid "Focused windows"
msgstr "Fenêtres au premier plan"
-#: ui/BoxDynamicOpacityOptions.ui:44 ui/BoxIntellihideOptions.ui:71
+#: ui/BoxDynamicOpacityOptions.ui.h:4 ui/BoxIntellihideOptions.ui.h:5
msgid "Maximized windows"
msgstr "Fenêtres maximisées"
-#: ui/BoxDynamicOpacityOptions.ui:53
+#: ui/BoxDynamicOpacityOptions.ui.h:5
msgid "Change opacity when a window gets closer than (px)"
msgstr "Changer l'opacité lorsqu'une fenêtre est plus proche que (px)"
-#: ui/BoxDynamicOpacityOptions.ui:69
+#: ui/BoxDynamicOpacityOptions.ui.h:7
+#, no-c-format
msgid "Change opacity to (%)"
msgstr "Changer l'opacité à (%)"
-#: ui/BoxDynamicOpacityOptions.ui:72 ui/BoxShowApplicationsOptions.ui:64
-#: ui/BoxWindowPreviewOptions.ui:468 ui/SettingsStyle.ui:266
-#: ui/SettingsStyle.ui:329 ui/SettingsStyle.ui:348
+#: ui/BoxDynamicOpacityOptions.ui.h:8 ui/BoxShowApplicationsOptions.ui.h:3
+#: ui/BoxWindowPreviewOptions.ui.h:57 ui/SettingsStyle.ui.h:40
msgid "0"
msgstr "0"
-#: ui/BoxDynamicOpacityOptions.ui:82
+#: ui/BoxDynamicOpacityOptions.ui.h:9
msgid "Opacity change animation duration (ms)"
msgstr "Durée de l'animation de changement d'opacité (ms)"
-#: ui/BoxGroupAppsOptions.ui:32
+#: ui/BoxGroupAppsOptions.ui.h:1
msgid "Font size (px) of the application titles (default is 14)"
msgstr "Taille (px) du texte des titres d'application (défaut: 14)"
-#: ui/BoxGroupAppsOptions.ui:47
+#: ui/BoxGroupAppsOptions.ui.h:2
msgid "Font weight of application titles"
msgstr "Épaisseur de la police du texte des titres d'application"
-#: ui/BoxGroupAppsOptions.ui:52 ui/BoxWindowPreviewOptions.ui:402
+#: ui/BoxGroupAppsOptions.ui.h:3 ui/BoxWindowPreviewOptions.ui.h:44
msgid "inherit from theme"
msgstr "hériter du thème"
-#: ui/BoxGroupAppsOptions.ui:53 ui/BoxWindowPreviewOptions.ui:403
+#: ui/BoxGroupAppsOptions.ui.h:4 ui/BoxWindowPreviewOptions.ui.h:45
msgid "normal"
msgstr "normale"
-#: ui/BoxGroupAppsOptions.ui:54 ui/BoxWindowPreviewOptions.ui:404
+#: ui/BoxGroupAppsOptions.ui.h:5 ui/BoxWindowPreviewOptions.ui.h:46
msgid "lighter"
msgstr "plus légere"
-#: ui/BoxGroupAppsOptions.ui:55 ui/BoxWindowPreviewOptions.ui:405
+#: ui/BoxGroupAppsOptions.ui.h:6 ui/BoxWindowPreviewOptions.ui.h:47
msgid "bold"
msgstr "gras"
-#: ui/BoxGroupAppsOptions.ui:56 ui/BoxWindowPreviewOptions.ui:406
+#: ui/BoxGroupAppsOptions.ui.h:7 ui/BoxWindowPreviewOptions.ui.h:48
msgid "bolder"
msgstr "plus gras"
-#: ui/BoxGroupAppsOptions.ui:65
+#: ui/BoxGroupAppsOptions.ui.h:8
msgid "Font color of the application titles"
msgstr "Couleur du texte des titres d'application"
-#: ui/BoxGroupAppsOptions.ui:77
+#: ui/BoxGroupAppsOptions.ui.h:9
msgid "Font color of the minimized application titles"
msgstr "Couleur du texte des titres d'application de fenêtres minimisées"
-#: ui/BoxGroupAppsOptions.ui:95
+#: ui/BoxGroupAppsOptions.ui.h:10
msgid "Maximum width (px) of the application titles"
msgstr "Longueur maximum (px) des titres d'application"
-#: ui/BoxGroupAppsOptions.ui:96
+#: ui/BoxGroupAppsOptions.ui.h:11
msgid "(default is 160)"
msgstr "(la valeur par défaut est 160)"
-#: ui/BoxGroupAppsOptions.ui:111
+#: ui/BoxGroupAppsOptions.ui.h:12
msgid "Use a fixed width for the application titles"
msgstr "Utiliser une largeur fixe pour les titres d'application"
-#: ui/BoxGroupAppsOptions.ui:112
+#: ui/BoxGroupAppsOptions.ui.h:13
msgid ""
"The application titles all have the same width, even if their texts are "
"shorter than the maximum width. The maximum width value is used as the fixed "
@@ -540,75 +552,107 @@ msgstr ""
"plus petit que la taille maximum. La valeur maximale de longueur est "
"utilisée comme longueur fixe."
-#: ui/BoxGroupAppsOptions.ui:129
+#: ui/BoxGroupAppsOptions.ui.h:14
msgid "Display running indicators on unfocused applications"
msgstr "Afficher des indicateurs sur les applications an arrière-plan"
-#: ui/BoxGroupAppsOptions.ui:140
+#: ui/BoxGroupAppsOptions.ui.h:15
msgid "Use the favorite icons as application launchers"
msgstr "Utiliser les applications favorites comme lanceurs"
-#: ui/BoxIntellihideOptions.ui:53
+#: ui/BoxHighlightAppIconHoverOptions.ui.h:1
+msgid "Highlight AppIcon color"
+msgstr "Couleur de surlignement"
+
+#: ui/BoxHighlightAppIconHoverOptions.ui.h:2
+msgid "Pressed AppIcon color"
+msgstr "Couleur des icônes d'application enfoncées"
+
+#: ui/BoxHighlightAppIconHoverOptions.ui.h:3
+msgid "Highlight AppIcon border radius"
+msgstr "Coins arrondis du surlignement des icônes"
+
+#: ui/BoxHighlightAppIconHoverOptions.ui.h:4
+msgid "Overrides global border radius (default is 0)"
+msgstr "Remplace l'option globale des coins arrondis"
+
+#: ui/BoxIntellihideOptions.ui.h:1
msgid "Only hide the panel when it is obstructed by windows"
msgstr "Ne cacher le panneau que lorsqu'il est au-dessus d'une fenêtre"
-#: ui/BoxIntellihideOptions.ui:64
+#: ui/BoxIntellihideOptions.ui.h:2
msgid "The panel hides from"
msgstr "Le panneau se cache de"
-#: ui/BoxIntellihideOptions.ui:86
+#: ui/BoxIntellihideOptions.ui.h:6
msgid "Require pressure at the edge of the screen to reveal the panel"
msgstr "Requérir une pression sur le bord de l'écran pour afficher le panneau"
-#: ui/BoxIntellihideOptions.ui:97
+#: ui/BoxIntellihideOptions.ui.h:7
msgid "Required pressure threshold (px)"
msgstr "Seuil d'activation (px)"
-#: ui/BoxIntellihideOptions.ui:112
+#: ui/BoxIntellihideOptions.ui.h:8
msgid "Required pressure timeout (ms)"
msgstr "Délai d'activation (ms)"
-#: ui/BoxIntellihideOptions.ui:133
+#: ui/BoxIntellihideOptions.ui.h:9
msgid "Allow the panel to be revealed while in fullscreen mode"
msgstr "Permettre au panneau d'être affiché en mode plein écran"
-#: ui/BoxIntellihideOptions.ui:144
-msgid "Only hide secondary panels"
-msgstr "Ne cacher que les panneaux secondaires"
-
-#: ui/BoxIntellihideOptions.ui:145
+#: ui/BoxIntellihideOptions.ui.h:10
msgid "(requires multi-monitors option)"
msgstr "(requiert l'option multi-écran)"
-#: ui/BoxIntellihideOptions.ui:156
-msgid "Keyboard shortcut to reveal and hold the panel"
-msgstr "Raccourci clavier pour révéler et maintenir le panneau"
+#: ui/BoxIntellihideOptions.ui.h:11
+msgid "Only hide secondary panels"
+msgstr "Ne cacher que les panneaux secondaires"
-#: ui/BoxIntellihideOptions.ui:157 ui/BoxOverlayShortcut.ui:71
+#: ui/BoxIntellihideOptions.ui.h:12 ui/BoxOverlayShortcut.ui.h:11
msgid "Syntax: <Shift>, <Ctrl>, <Alt>, <Super>"
msgstr "Syntaxe: <Shift>, <Ctrl>, <Alt>, <Super>"
-#: ui/BoxIntellihideOptions.ui:162
+#: ui/BoxIntellihideOptions.ui.h:13
+msgid "Keyboard shortcut to reveal and hold the panel"
+msgstr "Raccourci clavier pour révéler et maintenir le panneau"
+
+#: ui/BoxIntellihideOptions.ui.h:14
msgid "e.g. i"
msgstr "e.g. i"
-#: ui/BoxIntellihideOptions.ui:176
+#: ui/BoxIntellihideOptions.ui.h:15
+msgid "Persist state across restarts"
+msgstr "Conserver l'état lors des redémarrages"
+
+#: ui/BoxIntellihideOptions.ui.h:16
+msgid ""
+"(respects \"Do Not Disturb\" and requires show notification counter "
+"badge option)"
+msgstr ""
+"(respecte \"Ne pas déranger\" et requiert afficher le nombre de "
+"notifications)"
+
+#: ui/BoxIntellihideOptions.ui.h:17
+msgid "Reveal and hold the panel on notification"
+msgstr "Révéler le panneau à la réception d'une notification"
+
+#: ui/BoxIntellihideOptions.ui.h:18
msgid "Hide and reveal animation duration (ms)"
msgstr "Durée des animations d'affichage (ms)"
-#: ui/BoxIntellihideOptions.ui:191
+#: ui/BoxIntellihideOptions.ui.h:19
msgid "Delay before hiding the panel (ms)"
msgstr "Délai avant le masquage du panneau (ms)"
-#: ui/BoxIntellihideOptions.ui:207
+#: ui/BoxIntellihideOptions.ui.h:20
msgid "Delay before enabling intellihide on start (ms)"
msgstr "Délai avant l'activation du masquage intelligent (ms)"
-#: ui/BoxMiddleClickOptions.ui:19
+#: ui/BoxMiddleClickOptions.ui.h:1
msgid "Shift+Click action"
msgstr "Action Maj+Clic"
-#: ui/BoxMiddleClickOptions.ui:20
+#: ui/BoxMiddleClickOptions.ui.h:2
msgid ""
"When set to minimize, double clicking minimizes all the windows of the "
"application."
@@ -616,78 +660,71 @@ msgstr ""
"Quand minimiser est sélectionné, un double-clic réduit toutes les fenêtres "
"de l'application."
-#: ui/BoxMiddleClickOptions.ui:25 ui/BoxMiddleClickOptions.ui:53
-#: ui/BoxMiddleClickOptions.ui:81 ui/SettingsAction.ui:41
+#: ui/BoxMiddleClickOptions.ui.h:3 ui/SettingsAction.ui.h:10
msgid "Raise windows"
msgstr "Montrer les fenêtres"
-#: ui/BoxMiddleClickOptions.ui:26 ui/BoxMiddleClickOptions.ui:54
-#: ui/BoxMiddleClickOptions.ui:82
+#: ui/BoxMiddleClickOptions.ui.h:4
msgid "Minimize window"
msgstr "Réduire la fenêtre"
-#: ui/BoxMiddleClickOptions.ui:27 ui/BoxMiddleClickOptions.ui:55
-#: ui/BoxMiddleClickOptions.ui:83 ui/SettingsAction.ui:42
+#: ui/BoxMiddleClickOptions.ui.h:5 ui/SettingsAction.ui.h:11
msgid "Launch new instance"
msgstr "Lancer une nouvelle instance"
-#: ui/BoxMiddleClickOptions.ui:28 ui/BoxMiddleClickOptions.ui:56
-#: ui/BoxMiddleClickOptions.ui:84 ui/SettingsAction.ui:37
+#: ui/BoxMiddleClickOptions.ui.h:6 ui/SettingsAction.ui.h:5
msgid "Cycle through windows"
msgstr "Cycler sur les fenêtres"
-#: ui/BoxMiddleClickOptions.ui:29 ui/BoxMiddleClickOptions.ui:57
-#: ui/BoxMiddleClickOptions.ui:85 ui/SettingsAction.ui:36
+#: ui/BoxMiddleClickOptions.ui.h:7 ui/SettingsAction.ui.h:4
msgid "Cycle windows + minimize"
msgstr "Cycler sur les fenêtres + réduire"
-#: ui/BoxMiddleClickOptions.ui:30 ui/BoxMiddleClickOptions.ui:58
-#: ui/BoxMiddleClickOptions.ui:86 ui/SettingsAction.ui:38
+#: ui/BoxMiddleClickOptions.ui.h:8 ui/SettingsAction.ui.h:6
msgid "Toggle single / Preview multiple"
msgstr "Prévisualisation simple / multiple"
-#: ui/BoxMiddleClickOptions.ui:31 ui/BoxMiddleClickOptions.ui:59
-#: ui/BoxMiddleClickOptions.ui:87 ui/SettingsAction.ui:39
+#: ui/BoxMiddleClickOptions.ui.h:9 ui/SettingsAction.ui.h:7
msgid "Toggle single / Cycle multiple"
msgstr "Prévisualisation simple / cycle multiple"
-#: ui/BoxMiddleClickOptions.ui:47
+#: ui/BoxMiddleClickOptions.ui.h:10 ui/SettingsAction.ui.h:8
+msgid "Toggle single / Spread multiple"
+msgstr "Prévisualisation simple / diffusion de l'application"
+
+#: ui/BoxMiddleClickOptions.ui.h:12
msgid "Middle-Click action"
msgstr "Action clic molette"
-#: ui/BoxMiddleClickOptions.ui:48
+#: ui/BoxMiddleClickOptions.ui.h:13
msgid "Behavior for Middle-Click."
msgstr "Comportement du clic molette."
-#: ui/BoxMiddleClickOptions.ui:75
+#: ui/BoxMiddleClickOptions.ui.h:14
msgid "Shift+Middle-Click action"
msgstr "Action de Maj+Clic molette"
-#: ui/BoxMiddleClickOptions.ui:76
+#: ui/BoxMiddleClickOptions.ui.h:15
msgid "Behavior for Shift+Middle-Click."
msgstr "Comportement pour Maj+Clic molette."
-#: ui/BoxOverlayShortcut.ui:25
-msgid "Hotkeys prefix"
-msgstr "Préfixe raccourcis"
-
-#: ui/BoxOverlayShortcut.ui:26
+#: ui/BoxOverlayShortcut.ui.h:1
msgid "Hotkeys will either be Super+Number or Super+Alt+Num"
msgstr "Les raccourcis seront soit Super+Numéro soit Super+Alt+Numéro"
-#: ui/BoxOverlayShortcut.ui:31
+#: ui/BoxOverlayShortcut.ui.h:2
+msgid "Hotkeys prefix"
+msgstr "Préfixe raccourcis"
+
+#: ui/BoxOverlayShortcut.ui.h:3
msgid "Super"
msgstr "Super"
-#: ui/BoxOverlayShortcut.ui:32
+#: ui/BoxOverlayShortcut.ui.h:4
msgid "Super + Alt"
msgstr "Super + Alt"
-#: ui/BoxOverlayShortcut.ui:41
-msgid "Number overlay"
-msgstr "Superposition des nombres"
-
-#: ui/BoxOverlayShortcut.ui:42
+#: ui/BoxOverlayShortcut.ui.h:5
msgid ""
"Temporarily show the application numbers over the icons when using the "
"hotkeys."
@@ -695,294 +732,314 @@ msgstr ""
"Afficher temporairement les numéros des applications par dessus les icônes "
"lors de l'utilisation des raccourcis."
-#: ui/BoxOverlayShortcut.ui:47
+#: ui/BoxOverlayShortcut.ui.h:6
+msgid "Number overlay"
+msgstr "Superposition des nombres"
+
+#: ui/BoxOverlayShortcut.ui.h:7
msgid "Never"
msgstr "Jamais"
-#: ui/BoxOverlayShortcut.ui:48
+#: ui/BoxOverlayShortcut.ui.h:8
msgid "Show temporarily"
msgstr "Afficher temporairement"
-#: ui/BoxOverlayShortcut.ui:49
+#: ui/BoxOverlayShortcut.ui.h:9
msgid "Always visible"
msgstr "Toujours visible"
-#: ui/BoxOverlayShortcut.ui:58
+#: ui/BoxOverlayShortcut.ui.h:10
msgid "Hide timeout (ms)"
msgstr "Délai avant de cacher (ms)"
-#: ui/BoxOverlayShortcut.ui:70
+#: ui/BoxOverlayShortcut.ui.h:12
msgid "Shortcut to show the overlay for 2 seconds"
msgstr "Raccourci pour afficher la superposition pendant 2 secondes"
-#: ui/BoxOverlayShortcut.ui:76
+#: ui/BoxOverlayShortcut.ui.h:13
msgid "e.g. q"
msgstr "e.g. q"
-#: ui/BoxOverlayShortcut.ui:84
-msgid "Show window previews on hotkey"
-msgstr "Afficher les aperçus des fenêtres lors de l'utilisation d'un raccourci"
+#: ui/BoxOverlayShortcut.ui.h:14
+msgid ""
+"On secondary monitors, show the overlay on icons matching the primary monitor"
+msgstr ""
+"Sur les panneaux secondaires, afficher la superposition sur les icônes "
+"correspondantes au panneau principal"
-#: ui/BoxOverlayShortcut.ui:85
+#: ui/BoxOverlayShortcut.ui.h:15
+msgid "Show the overlay on all monitors"
+msgstr "Afficher la superposition sur tous les écrans"
+
+#: ui/BoxOverlayShortcut.ui.h:16
msgid "Show previews when the application have multiple instances"
msgstr ""
"Afficher les aperçus lorsque les applications possèdent plusieurs fenêtres"
-#: ui/BoxOverlayShortcut.ui:96
-msgid "Hotkeys are activated with"
-msgstr "Les raccourcis sont activés par"
+#: ui/BoxOverlayShortcut.ui.h:17
+msgid "Show window previews on hotkey"
+msgstr "Afficher les aperçus des fenêtres lors de l'utilisation d'un raccourci"
-#: ui/BoxOverlayShortcut.ui:97
+#: ui/BoxOverlayShortcut.ui.h:18
msgid "Select which keyboard number keys are used to activate the hotkeys"
msgstr ""
"Sélectionner quelles touches numériques sont utilisées pour activer les "
"raccourcis"
-#: ui/BoxOverlayShortcut.ui:102
+#: ui/BoxOverlayShortcut.ui.h:19
+msgid "Hotkeys are activated with"
+msgstr "Les raccourcis sont activés par"
+
+#: ui/BoxOverlayShortcut.ui.h:20
msgid "Number row"
msgstr "Rangée des chiffres"
-#: ui/BoxOverlayShortcut.ui:103
+#: ui/BoxOverlayShortcut.ui.h:21
msgid "Numeric keypad"
msgstr "Pavé numérique"
-#: ui/BoxOverlayShortcut.ui:104
+#: ui/BoxOverlayShortcut.ui.h:22
msgid "Both"
msgstr "Les deux"
-#: ui/BoxScrollIconOptions.ui:25 ui/BoxScrollPanelOptions.ui:25
+#: ui/BoxScrollIconOptions.ui.h:1 ui/BoxScrollPanelOptions.ui.h:1
msgid "Delay between mouse scroll events (ms)"
msgstr "Délai entre les évènements de défilement de la souris (ms)"
-#: ui/BoxScrollIconOptions.ui:26 ui/BoxScrollPanelOptions.ui:26
+#: ui/BoxScrollIconOptions.ui.h:2 ui/BoxScrollPanelOptions.ui.h:2
msgid "Use this value to limit the number of captured mouse scroll events."
msgstr ""
"Utiliser cette valeur pour limiter le nombre d'évènements de défilement de "
"la souris (ms)"
-#: ui/BoxScrollPanelOptions.ui:42
+#: ui/BoxScrollPanelOptions.ui.h:3
msgid "Show popup when changing workspace"
msgstr "Afficher l'indicateur de changement d'espace de travail"
-#: ui/BoxScrollPanelOptions.ui:43
+#: ui/BoxScrollPanelOptions.ui.h:4
msgid "This affects workspace popup when scrolling on the panel only."
msgstr ""
"Affecte uniquement l'indicateur de changement d'espace de travail au "
"défilement de la souris sur le panneau."
-#: ui/BoxSecondaryMenuOptions.ui:19
+#: ui/BoxSecondaryMenuOptions.ui.h:1
msgid "Integrate AppMenu items"
msgstr "Intégrer les actions du Menu d'applications"
-#: ui/BoxSecondaryMenuOptions.ui:30
-msgid "Show Details menu item"
-msgstr "Menu Afficher les détails"
+#: ui/BoxSecondaryMenuOptions.ui.h:2
+msgid "App Details menu item"
+msgstr "Menu Détails de l’application"
-#: ui/BoxShowApplicationsOptions.ui:25
+#: ui/BoxSecondaryMenuOptions.ui.h:3
+msgid "App Details is only available when Gnome Software is installed"
+msgstr ""
+"Détails de l’application est uniquement disponible lorsque Gnome "
+"Software est installé"
+
+#: ui/BoxShowApplicationsOptions.ui.h:1
msgid "Show Applications icon"
msgstr "Bouton Afficher les Applications"
-#: ui/BoxShowApplicationsOptions.ui:60
+#: ui/BoxShowApplicationsOptions.ui.h:2
msgid "Show Applications icon side padding (px)"
-msgstr "Marge interne du bouton \"Afficher les Applications\""
+msgstr "Remplissage du bouton \"Afficher les Applications\""
-#: ui/BoxShowApplicationsOptions.ui:73
+#: ui/BoxShowApplicationsOptions.ui.h:4
msgid "Override escape key and return to desktop"
msgstr ""
"Remplacer l'action de la touche d'échappement et retourner sur le bureau"
-#: ui/BoxShowDesktopOptions.ui:53
+#: ui/BoxShowDesktopOptions.ui.h:1
msgid "Override Show Desktop line color"
msgstr "Remplacer la couleur de la ligne du bouton Afficher le Bureau"
-#: ui/BoxShowDesktopOptions.ui:77
+#: ui/BoxShowDesktopOptions.ui.h:2
msgid "Reveal the desktop when hovering the Show Desktop button"
msgstr "Révéler le bureau lors du survol du bouton Afficher le Bureau"
-#: ui/BoxShowDesktopOptions.ui:90
+#: ui/BoxShowDesktopOptions.ui.h:3
msgid "Delay before revealing the desktop (ms)"
msgstr "Délai avant affichage du bureau (ms)"
-#: ui/BoxShowDesktopOptions.ui:106
+#: ui/BoxShowDesktopOptions.ui.h:4
msgid "Fade duration (ms)"
msgstr "Durée du fondu (ms)"
-#: ui/BoxWindowPreviewOptions.ui:89
+#: ui/BoxWindowPreviewOptions.ui.h:1
msgid "Time (ms) before showing"
msgstr "Temps (ms) avant d'afficher"
-#: ui/BoxWindowPreviewOptions.ui:90
+#: ui/BoxWindowPreviewOptions.ui.h:2
msgid "(400 is default)"
msgstr "(400 par défaut)"
-#: ui/BoxWindowPreviewOptions.ui:105
+#: ui/BoxWindowPreviewOptions.ui.h:3
msgid "Time (ms) before hiding"
msgstr "Temps (ms) avant de cacher"
-#: ui/BoxWindowPreviewOptions.ui:106
+#: ui/BoxWindowPreviewOptions.ui.h:4
msgid "(100 is default)"
msgstr "(100 par défaut)"
-#: ui/BoxWindowPreviewOptions.ui:113
+#: ui/BoxWindowPreviewOptions.ui.h:5
msgid "Immediate on application icon click"
msgstr "Immédiat au clic d'application"
-#: ui/BoxWindowPreviewOptions.ui:134
+#: ui/BoxWindowPreviewOptions.ui.h:6
msgid "Animation time (ms)"
msgstr "Durée d'animation (ms)"
-#: ui/BoxWindowPreviewOptions.ui:155
+#: ui/BoxWindowPreviewOptions.ui.h:7
msgid "Middle click on the preview to close the window"
msgstr "Cliquez avec la molette sur la prévisualisation pour fermer la fenêtre"
-#: ui/BoxWindowPreviewOptions.ui:172
+#: ui/BoxWindowPreviewOptions.ui.h:8
msgid "Window previews preferred size (px)"
msgstr "Taille des prévisualisations de fenêtres (px)"
-#: ui/BoxWindowPreviewOptions.ui:188
+#: ui/BoxWindowPreviewOptions.ui.h:9
msgid "Window previews aspect ratio X (width)"
msgstr "Ratio d'aspect des prévisualisations (largeur)"
-#: ui/BoxWindowPreviewOptions.ui:193 ui/BoxWindowPreviewOptions.ui:234
+#: ui/BoxWindowPreviewOptions.ui.h:10
msgid "1"
msgstr "1"
-#: ui/BoxWindowPreviewOptions.ui:194 ui/BoxWindowPreviewOptions.ui:235
+#: ui/BoxWindowPreviewOptions.ui.h:11
msgid "2"
msgstr "2"
-#: ui/BoxWindowPreviewOptions.ui:195 ui/BoxWindowPreviewOptions.ui:236
+#: ui/BoxWindowPreviewOptions.ui.h:12
msgid "3"
msgstr "3"
-#: ui/BoxWindowPreviewOptions.ui:196 ui/BoxWindowPreviewOptions.ui:237
+#: ui/BoxWindowPreviewOptions.ui.h:13
msgid "4"
msgstr "4"
-#: ui/BoxWindowPreviewOptions.ui:197 ui/BoxWindowPreviewOptions.ui:238
-#: ui/BoxWindowPreviewOptions.ui:302
+#: ui/BoxWindowPreviewOptions.ui.h:14
msgid "5"
msgstr "5"
-#: ui/BoxWindowPreviewOptions.ui:198 ui/BoxWindowPreviewOptions.ui:239
+#: ui/BoxWindowPreviewOptions.ui.h:15
msgid "6"
msgstr "6"
-#: ui/BoxWindowPreviewOptions.ui:199 ui/BoxWindowPreviewOptions.ui:240
+#: ui/BoxWindowPreviewOptions.ui.h:16
msgid "7"
msgstr "7"
-#: ui/BoxWindowPreviewOptions.ui:200 ui/BoxWindowPreviewOptions.ui:241
+#: ui/BoxWindowPreviewOptions.ui.h:17
msgid "8"
msgstr "8"
-#: ui/BoxWindowPreviewOptions.ui:201 ui/BoxWindowPreviewOptions.ui:242
+#: ui/BoxWindowPreviewOptions.ui.h:18
msgid "9"
msgstr "9"
-#: ui/BoxWindowPreviewOptions.ui:202 ui/BoxWindowPreviewOptions.ui:243
+#: ui/BoxWindowPreviewOptions.ui.h:19
msgid "10"
msgstr "10"
-#: ui/BoxWindowPreviewOptions.ui:203 ui/BoxWindowPreviewOptions.ui:244
+#: ui/BoxWindowPreviewOptions.ui.h:20
msgid "11"
msgstr "11"
-#: ui/BoxWindowPreviewOptions.ui:204 ui/BoxWindowPreviewOptions.ui:245
+#: ui/BoxWindowPreviewOptions.ui.h:21
msgid "12"
msgstr "12"
-#: ui/BoxWindowPreviewOptions.ui:205 ui/BoxWindowPreviewOptions.ui:246
+#: ui/BoxWindowPreviewOptions.ui.h:22
msgid "13"
msgstr "13"
-#: ui/BoxWindowPreviewOptions.ui:206 ui/BoxWindowPreviewOptions.ui:247
+#: ui/BoxWindowPreviewOptions.ui.h:23
msgid "14"
msgstr "14"
-#: ui/BoxWindowPreviewOptions.ui:207 ui/BoxWindowPreviewOptions.ui:248
+#: ui/BoxWindowPreviewOptions.ui.h:24
msgid "15"
msgstr "15"
-#: ui/BoxWindowPreviewOptions.ui:208 ui/BoxWindowPreviewOptions.ui:249
+#: ui/BoxWindowPreviewOptions.ui.h:25
msgid "16"
msgstr "16"
-#: ui/BoxWindowPreviewOptions.ui:209 ui/BoxWindowPreviewOptions.ui:250
+#: ui/BoxWindowPreviewOptions.ui.h:26
msgid "17"
msgstr "17"
-#: ui/BoxWindowPreviewOptions.ui:210 ui/BoxWindowPreviewOptions.ui:251
+#: ui/BoxWindowPreviewOptions.ui.h:27
msgid "18"
msgstr "18"
-#: ui/BoxWindowPreviewOptions.ui:211 ui/BoxWindowPreviewOptions.ui:252
+#: ui/BoxWindowPreviewOptions.ui.h:28
msgid "19"
msgstr "19"
-#: ui/BoxWindowPreviewOptions.ui:212 ui/BoxWindowPreviewOptions.ui:253
+#: ui/BoxWindowPreviewOptions.ui.h:29
msgid "20"
msgstr "20"
-#: ui/BoxWindowPreviewOptions.ui:213 ui/BoxWindowPreviewOptions.ui:254
+#: ui/BoxWindowPreviewOptions.ui.h:30
msgid "21"
msgstr "21"
-#: ui/BoxWindowPreviewOptions.ui:219 ui/BoxWindowPreviewOptions.ui:260
+#: ui/BoxWindowPreviewOptions.ui.h:31
msgid "Fixed"
msgstr "Fixé"
-#: ui/BoxWindowPreviewOptions.ui:229
+#: ui/BoxWindowPreviewOptions.ui.h:32
msgid "Window previews aspect ratio Y (height)"
msgstr "Ratio d'aspect des prévisualisations (hauteur)"
-#: ui/BoxWindowPreviewOptions.ui:270
+#: ui/BoxWindowPreviewOptions.ui.h:33
msgid "Window previews padding (px)"
-msgstr "Marge intérieure des prévisualisations (px)"
+msgstr "Remplissage des prévisualisations (px)"
-#: ui/BoxWindowPreviewOptions.ui:292
+#: ui/BoxWindowPreviewOptions.ui.h:34
msgid "Use custom opacity for the previews background"
msgstr "Opacité personnalisée pour l'arrière plan des prévisualisations"
-#: ui/BoxWindowPreviewOptions.ui:293
+#: ui/BoxWindowPreviewOptions.ui.h:35
msgid ""
"If disabled, the previews background have the same opacity as the panel."
msgstr ""
"Si désactivé, les prévisualisations ont la même opacité que le panneau."
-#: ui/BoxWindowPreviewOptions.ui:318
+#: ui/BoxWindowPreviewOptions.ui.h:36
msgid "Close button and header position"
msgstr "Bouton de fermeture et position de l'en-tête"
-#: ui/BoxWindowPreviewOptions.ui:348
+#: ui/BoxWindowPreviewOptions.ui.h:39
msgid "Display window preview headers"
msgstr "Afficher le titre de la fenêtre dans la prévisualisation."
-#: ui/BoxWindowPreviewOptions.ui:359
+#: ui/BoxWindowPreviewOptions.ui.h:40
msgid "Icon size (px) of the window preview"
msgstr "Taille (px) de l'icône des prévisualisations"
-#: ui/BoxWindowPreviewOptions.ui:360
+#: ui/BoxWindowPreviewOptions.ui.h:41
msgid "If disabled, the previews icon size will be based on headerbar size"
msgstr "Si désactivé, la taille de l'icône est basée sur celle de l'en-tête"
-#: ui/BoxWindowPreviewOptions.ui:381
+#: ui/BoxWindowPreviewOptions.ui.h:42
msgid "Font size (px) of the preview titles"
msgstr "Taille (px) du texte des prévisualisations"
-#: ui/BoxWindowPreviewOptions.ui:397
+#: ui/BoxWindowPreviewOptions.ui.h:43
msgid "Font weight of the preview titles"
msgstr "Épaisseur du texte des titres pendant la prévisualisation"
-#: ui/BoxWindowPreviewOptions.ui:415
+#: ui/BoxWindowPreviewOptions.ui.h:49
msgid "Font color of the preview titles"
msgstr "Couleur du texte des titres pendant la prévisualisation"
-#: ui/BoxWindowPreviewOptions.ui:433
+#: ui/BoxWindowPreviewOptions.ui.h:50
msgid "Enable window peeking"
msgstr "Activer la vue de fenêtre"
-#: ui/BoxWindowPreviewOptions.ui:434
+#: ui/BoxWindowPreviewOptions.ui.h:51
msgid ""
"When hovering over a window preview for some time, the window gets "
"distinguished."
@@ -990,11 +1047,11 @@ msgstr ""
"Le survol sur la prévisualisation de la fenêtre, pendant un certain temps, "
"la met en avant."
-#: ui/BoxWindowPreviewOptions.ui:445
+#: ui/BoxWindowPreviewOptions.ui.h:52
msgid "Enter window peeking mode timeout (ms)"
msgstr "Temps d'attente avant activation de la vue fenêtre"
-#: ui/BoxWindowPreviewOptions.ui:446
+#: ui/BoxWindowPreviewOptions.ui.h:53
msgid ""
"Time of inactivity while hovering over a window preview needed to enter the "
"window peeking mode."
@@ -1002,15 +1059,15 @@ msgstr ""
"Temps d'inactivité pendant le survol de la prévisualisation d'une fenêtre "
"nécessaire pour activer la vue de la fenêtre."
-#: ui/BoxWindowPreviewOptions.ui:451
+#: ui/BoxWindowPreviewOptions.ui.h:54
msgid "50"
msgstr "50"
-#: ui/BoxWindowPreviewOptions.ui:462
+#: ui/BoxWindowPreviewOptions.ui.h:55
msgid "Window peeking mode opacity"
msgstr "Opacité de la vue de fenêtre"
-#: ui/BoxWindowPreviewOptions.ui:463
+#: ui/BoxWindowPreviewOptions.ui.h:56
msgid ""
"All windows except for the peeked one have their opacity set to the same "
"value."
@@ -1018,35 +1075,31 @@ msgstr ""
"Toutes les fenêtres, mis à part celle prévisualisée, ont leur opacité mise à "
"la même valeur."
-#: ui/SettingsAbout.ui:6
+#: ui/SettingsAbout.ui.h:1
msgid "About"
msgstr "À propos"
-#: ui/SettingsAbout.ui:12
+#: ui/SettingsAbout.ui.h:2
msgid "Info"
msgstr "Information"
-#: ui/SettingsAbout.ui:16
+#: ui/SettingsAbout.ui.h:3
msgid "Version"
msgstr "Version"
-#: ui/SettingsAbout.ui:27
+#: ui/SettingsAbout.ui.h:4
msgid "Source"
msgstr "Source"
-#: ui/SettingsAbout.ui:30
+#: ui/SettingsAbout.ui.h:5
msgid "GitHub"
msgstr "GitHub"
-#: ui/SettingsAbout.ui:45
+#: ui/SettingsAbout.ui.h:6
msgid "Export and Import"
msgstr "Import et export"
-#: ui/SettingsAbout.ui:49
-msgid "Export and import settings"
-msgstr "Import et export de paramètres"
-
-#: ui/SettingsAbout.ui:50
+#: ui/SettingsAbout.ui.h:7
msgid ""
"Use the buttons below to create a settings file from your current "
"preferences that can be imported on a different machine."
@@ -1054,90 +1107,91 @@ msgstr ""
"Utiliser les boutons ci-dessous pour créer un fichier de paramètres à partir "
"de vos préférences actuelles qui pourra être importé sur une autre machine."
-#: ui/SettingsAbout.ui:66
+#: ui/SettingsAbout.ui.h:8
+msgid "Export and import settings"
+msgstr "Import et export de paramètres"
+
+#: ui/SettingsAbout.ui.h:9
msgid "Export to file"
msgstr "Exporter vers un fichier"
-#: ui/SettingsAbout.ui:72
+#: ui/SettingsAbout.ui.h:10
msgid "Import from file"
msgstr "Importer à partir d'un fichier"
-#: ui/SettingsAbout.ui:89
+#: ui/SettingsAbout.ui.h:11
msgid ""
"This program comes with ABSOLUTELY NO WARRANTY.\n"
-"See the GNU General Public License, version 2 or later for details."
+"See the GNU General Public License, version 2 or later for "
+"details."
msgstr ""
"Ce programme est fourni SANS AUCUNE GARANTIE.\n"
"Pour plus de détails, visitez la Licence publique générale GNU, version 2 ou "
"ultérieure"
-#: ui/SettingsAction.ui:6
+#: ui/SettingsAction.ui.h:1
msgid "Action"
msgstr "Action"
-#: ui/SettingsAction.ui:12 ui/SettingsAction.ui:16
+#: ui/SettingsAction.ui.h:2
msgid "Click action"
msgstr "Action du clic"
-#: ui/SettingsAction.ui:17
+#: ui/SettingsAction.ui.h:3
msgid "Behaviour when clicking on the icon of a running application."
msgstr "Comportement lors du clic sur l'icône d'une application lancée."
-#: ui/SettingsAction.ui:40
+#: ui/SettingsAction.ui.h:9
msgid "Toggle windows"
msgstr "Basculer les fenêtres"
-#: ui/SettingsAction.ui:55
+#: ui/SettingsAction.ui.h:12
msgid "Scroll action"
msgstr "Action du défilement de la souris"
-#: ui/SettingsAction.ui:59
-msgid "Scroll panel action"
-msgstr "Action du défilement de la souris sur le panneau"
-
-#: ui/SettingsAction.ui:60
+#: ui/SettingsAction.ui.h:13
msgid "Behavior when mouse scrolling over the panel."
msgstr "Comportement lors du défilement de la souris sur le panneau"
-#: ui/SettingsAction.ui:84 ui/SettingsAction.ui:118
+#: ui/SettingsAction.ui.h:14
+msgid "Scroll panel action"
+msgstr "Action du défilement de la souris sur le panneau"
+
+#: ui/SettingsAction.ui.h:15
msgid "Do nothing"
msgstr "Ne rien faire"
-#: ui/SettingsAction.ui:85
+#: ui/SettingsAction.ui.h:16
msgid "Switch workspace"
msgstr "Défiler les espaces de travail"
-#: ui/SettingsAction.ui:86 ui/SettingsAction.ui:119
+#: ui/SettingsAction.ui.h:17
msgid "Cycle windows"
msgstr "Défiler les fenêtres"
-#: ui/SettingsAction.ui:87
+#: ui/SettingsAction.ui.h:18
msgid "Change volume"
msgstr "Changer le volume"
-#: ui/SettingsAction.ui:96
-msgid "Scroll icon action"
-msgstr "Action du défilement de la souris sur une application"
-
-#: ui/SettingsAction.ui:97
+#: ui/SettingsAction.ui.h:19
msgid "Behavior when mouse scrolling over an application icon."
msgstr "Comportement lors du défilement de la souris sur une application"
-#: ui/SettingsAction.ui:120
+#: ui/SettingsAction.ui.h:20
+msgid "Scroll icon action"
+msgstr "Action du défilement de la souris sur une application"
+
+#: ui/SettingsAction.ui.h:21
msgid "Same as panel"
msgstr "Comme le panneau"
-#: ui/SettingsAction.ui:133
+#: ui/SettingsAction.ui.h:22
msgid "Hotkey overlay"
msgstr "Superposition des nombres"
-#: ui/SettingsAction.ui:137
-msgid "Use hotkeys to activate apps"
-msgstr "Utiliser des raccourcis pour lancer les applications"
-
-#: ui/SettingsAction.ui:138
+#: ui/SettingsAction.ui.h:23
msgid ""
"Enable Super+(0-9) as shortcuts to activate apps. It can also be used "
"together with Shift and Ctrl."
@@ -1145,347 +1199,401 @@ msgstr ""
"Activer Super+(0-9) comme raccourcis pour lancer les applications. Maj et "
"Ctrl peuvent aussi être utilisés."
-#: ui/SettingsBehavior.ui:5
-msgid "Behavior"
-msgstr "Comportement"
+#: ui/SettingsAction.ui.h:24
+msgid "Use hotkeys to activate apps"
+msgstr "Utiliser des raccourcis pour lancer les applications"
-#: ui/SettingsBehavior.ui:11
-msgid "Applications"
-msgstr "Applications"
+#: ui/SettingsAction.ui.h:25
+msgid "Application icons context menu"
+msgstr "Menu contextuel de l'application"
-#: ui/SettingsBehavior.ui:15
-msgid "Show favorite applications"
-msgstr "Afficher les applications favorites"
-
-#: ui/SettingsBehavior.ui:26
-msgid "Show favorite applications on secondary panels"
-msgstr "Afficher les applications favorites sur les panneaux secondaires"
-
-#: ui/SettingsBehavior.ui:37
-msgid "Show running applications"
-msgstr "Afficher les applications ouvertes"
-
-#: ui/SettingsBehavior.ui:48
-msgid "Ungroup applications"
-msgstr "Dégrouper les applications"
-
-#: ui/SettingsBehavior.ui:73
-msgid "Show notification counter badge"
-msgstr "Afficher le nombre de notifications"
-
-#: ui/SettingsBehavior.ui:90
-msgid "Hover"
-msgstr "Survol"
-
-#: ui/SettingsBehavior.ui:94
-msgid "Show window previews on hover"
-msgstr "Afficher les aperçus des fenêtres lors du survol"
-
-#: ui/SettingsBehavior.ui:119
-msgid "Show tooltip on hover"
-msgstr "Afficher les bulles d'info. lors du survol"
-
-#: ui/SettingsBehavior.ui:134
-msgid "Isolate"
-msgstr "Isolation"
-
-#: ui/SettingsBehavior.ui:138
-msgid "Isolate Workspaces"
-msgstr "Isoler les espaces de travail"
-
-#: ui/SettingsBehavior.ui:149
-msgid "Isolate monitors"
-msgstr "Isoler les écrans"
-
-#: ui/SettingsBehavior.ui:164
-msgid "Overview"
-msgstr "Activités"
-
-#: ui/SettingsBehavior.ui:168
-msgid "Click empty space to close overview"
-msgstr "Clic région vide pour fermer Activités"
-
-#: ui/SettingsBehavior.ui:179
-msgid "Disable show overview on startup"
-msgstr "Désactiver le démarrage en mode Activités"
-
-#: ui/SettingsFineTune.ui:41
-msgid "Fine-Tune"
-msgstr "Personnalisation"
-
-#: ui/SettingsFineTune.ui:47
-msgid "Font size"
-msgstr "Taille de la police"
-
-#: ui/SettingsFineTune.ui:51
-msgid "Tray Font Size"
-msgstr "Taille de la police des éléments de la barre d'état"
-
-#: ui/SettingsFineTune.ui:52 ui/SettingsFineTune.ui:70
-msgid "(0 = theme default)"
-msgstr "(0 = par défaut)"
-
-#: ui/SettingsFineTune.ui:69
-msgid "LeftBox Font Size"
-msgstr "Taille de la police de la zone de gauche"
-
-#: ui/SettingsFineTune.ui:91
-msgid "Padding"
-msgstr "Marge"
-
-#: ui/SettingsFineTune.ui:95
-msgid "Tray Item Padding"
-msgstr "Marge des éléments de la barre d'état"
-
-#: ui/SettingsFineTune.ui:96 ui/SettingsFineTune.ui:114
-#: ui/SettingsFineTune.ui:132
-msgid "(-1 = theme default)"
-msgstr "(-1 = par défaut)"
-
-#: ui/SettingsFineTune.ui:113
-msgid "Status Icon Padding"
-msgstr "Marge des icônes de statut"
-
-#: ui/SettingsFineTune.ui:131
-msgid "LeftBox Padding"
-msgstr "Marge de la zone de gauche"
-
-#: ui/SettingsFineTune.ui:153
-msgid "Animate"
-msgstr "Animation"
-
-#: ui/SettingsFineTune.ui:157
-msgid "Animate switching applications"
-msgstr "Animer le changement d'application"
-
-#: ui/SettingsFineTune.ui:168
-msgid "Animate launching new windows"
-msgstr "Animer le lancement de nouvelles fenêtres"
-
-#: ui/SettingsFineTune.ui:183
-msgid "Gnome functionality"
-msgstr "Fonctionnalités Gnome"
-
-#: ui/SettingsFineTune.ui:187
-msgid "Keep original gnome-shell dash"
-msgstr "Garder le lanceur d'origine de gnome-shell (Activités)"
-
-#: ui/SettingsFineTune.ui:188
-msgid "(overview)"
-msgstr "(activités)"
-
-#: ui/SettingsFineTune.ui:199
-msgid "Keep original gnome-shell top panel"
-msgstr "Garder le panneau d'origine de gnome-shell"
-
-#: ui/SettingsFineTune.ui:210
-msgid "Activate panel menu buttons on click only"
-msgstr "Activer les menus du panneau seulement au clic"
-
-#: ui/SettingsFineTune.ui:211
-msgid "(e.g. date menu)"
-msgstr "(exemple: horloge)"
-
-#: ui/SettingsFineTune.ui:222
-msgid "Force Activities hot corner on primary monitor"
-msgstr "Forcer le coin actif des Activités sur l'écran principal"
-
-#: ui/SettingsFineTune.ui:240
-msgid "App icon secondary menu"
-msgstr "Menu secondaire de l'application"
-
-#: ui/SettingsFineTune.ui:241
+#: ui/SettingsAction.ui.h:26
msgid "(right-click menu)"
msgstr "(clic droit)"
-#: ui/SettingsPosition.ui:19
+#: ui/SettingsAction.ui.h:27
+msgid "Secondary menu"
+msgstr "Options du menu secondaire"
+
+#: ui/SettingsAction.ui.h:28
+msgid "Panel context menu entries"
+msgstr "Entrées menu contextuel du panneau"
+
+#: ui/SettingsAction.ui.h:29
+msgid "Add entry"
+msgstr "Ajouter entrée"
+
+#: ui/SettingsBehavior.ui.h:1
+msgid "Behavior"
+msgstr "Comportement"
+
+#: ui/SettingsBehavior.ui.h:2
+msgid "Applications"
+msgstr "Applications"
+
+#: ui/SettingsBehavior.ui.h:3
+msgid "Show favorite applications"
+msgstr "Afficher les applications favorites"
+
+#: ui/SettingsBehavior.ui.h:4
+msgid "Show favorite applications on secondary panels"
+msgstr "Afficher les applications favorites sur les panneaux secondaires"
+
+#: ui/SettingsBehavior.ui.h:5
+msgid "Show running applications"
+msgstr "Afficher les applications ouvertes"
+
+#: ui/SettingsBehavior.ui.h:6
+msgid "Ungroup applications"
+msgstr "Dégrouper les applications"
+
+#: ui/SettingsBehavior.ui.h:7
+msgid "Show notification counter badge"
+msgstr "Afficher le nombre de notifications"
+
+#: ui/SettingsBehavior.ui.h:8
+msgid "Hover"
+msgstr "Survol"
+
+#: ui/SettingsBehavior.ui.h:9
+msgid "Show window previews on hover"
+msgstr "Afficher les aperçus des fenêtres lors du survol"
+
+#: ui/SettingsBehavior.ui.h:10
+msgid "Show tooltip on hover"
+msgstr "Afficher les bulles d'info. lors du survol"
+
+#: ui/SettingsBehavior.ui.h:11
+msgid "Isolate"
+msgstr "Isolation"
+
+#: ui/SettingsBehavior.ui.h:12
+msgid "Isolate Workspaces"
+msgstr "Isoler les espaces de travail"
+
+#: ui/SettingsBehavior.ui.h:13
+msgid "Isolate monitors"
+msgstr "Isoler les écrans"
+
+#: ui/SettingsBehavior.ui.h:14
+msgid "Overview"
+msgstr "Activités"
+
+#: ui/SettingsBehavior.ui.h:15
+msgid "Click empty space to close overview"
+msgstr "Clic région vide pour fermer Activités"
+
+#: ui/SettingsBehavior.ui.h:16
+msgid "Disable show overview on startup"
+msgstr "Désactiver le démarrage en mode Activités"
+
+#: ui/SettingsFineTune.ui.h:1
+msgid "Fine-Tune"
+msgstr "Personnalisation"
+
+#: ui/SettingsFineTune.ui.h:2
+msgid "Font size"
+msgstr "Taille de la police"
+
+#: ui/SettingsFineTune.ui.h:3
+msgid "(0 = theme default)"
+msgstr "(0 = par défaut)"
+
+#: ui/SettingsFineTune.ui.h:4
+msgid "Tray Font Size"
+msgstr "Taille de la police des éléments de la barre d'état"
+
+#: ui/SettingsFineTune.ui.h:5
+msgid "LeftBox Font Size"
+msgstr "Taille de la police de la zone de gauche"
+
+#: ui/SettingsFineTune.ui.h:6
+msgid "Padding"
+msgstr "Remplissage"
+
+#: ui/SettingsFineTune.ui.h:7
+msgid "(-1 = theme default)"
+msgstr "(-1 = par défaut)"
+
+#: ui/SettingsFineTune.ui.h:8
+msgid "Tray Item Padding"
+msgstr "Remplissage des éléments de la barre d'état"
+
+#: ui/SettingsFineTune.ui.h:9
+msgid "Status Icon Padding"
+msgstr "Remplissage des icônes de statut"
+
+#: ui/SettingsFineTune.ui.h:10
+msgid "LeftBox Padding"
+msgstr "Remplissage de la zone de gauche"
+
+#: ui/SettingsFineTune.ui.h:11
+msgid "Animate"
+msgstr "Animation"
+
+#: ui/SettingsFineTune.ui.h:12
+msgid "Animate switching applications"
+msgstr "Animer le changement d'application"
+
+#: ui/SettingsFineTune.ui.h:13
+msgid "Animate launching new windows"
+msgstr "Animer le lancement de nouvelles fenêtres"
+
+#: ui/SettingsFineTune.ui.h:14
+msgid "Gnome functionality"
+msgstr "Fonctionnalités Gnome"
+
+#: ui/SettingsFineTune.ui.h:15
+msgid "(overview)"
+msgstr "(activités)"
+
+#: ui/SettingsFineTune.ui.h:16
+msgid "Keep original gnome-shell dash"
+msgstr "Garder le lanceur d'origine de gnome-shell (Activités)"
+
+#: ui/SettingsFineTune.ui.h:17
+msgid "Keep original gnome-shell top panel"
+msgstr "Garder le panneau d'origine de gnome-shell"
+
+#: ui/SettingsFineTune.ui.h:18
+msgid "(e.g. date menu)"
+msgstr "(exemple: horloge)"
+
+#: ui/SettingsFineTune.ui.h:19
+msgid "Activate panel menu buttons on click only"
+msgstr "Activer les menus du panneau seulement au clic"
+
+#: ui/SettingsFineTune.ui.h:20
+msgid "Force Activities hot corner on primary monitor"
+msgstr "Forcer le coin actif des Activités sur l'écran principal"
+
+#: ui/SettingsPosition.ui.h:1
msgid "Position"
msgstr "Position"
-#: ui/SettingsPosition.ui:25
+#: ui/SettingsPosition.ui.h:2
msgid "Panel"
msgstr "Panneau"
-#: ui/SettingsPosition.ui:29
+#: ui/SettingsPosition.ui.h:3
msgid "Display the main panel on"
msgstr "Afficher le panneau principal sur"
-#: ui/SettingsPosition.ui:40
+#: ui/SettingsPosition.ui.h:4
msgid "Display panels on all monitors"
msgstr "Afficher le panneau principal sur tous les écrans"
-#: ui/SettingsPosition.ui:56
-msgid "Panel Intellihide"
-msgstr "Masquage intelligent du panneau"
-
-#: ui/SettingsPosition.ui:57
+#: ui/SettingsPosition.ui.h:5
msgid "Hide and reveal the panel according to preferences"
msgstr "Afficher/Cacher le panneau selon les préférences"
-#: ui/SettingsPosition.ui:86
+#: ui/SettingsPosition.ui.h:6
+msgid "Panel Intellihide"
+msgstr "Masquage intelligent du panneau"
+
+#: ui/SettingsPosition.ui.h:7
msgid "Order and Position on monitors"
msgstr "Ordre et positions de l'écran"
-#: ui/SettingsPosition.ui:91
+#: ui/SettingsPosition.ui.h:8
msgid "Monitor"
msgstr "Écran"
-#: ui/SettingsPosition.ui:100
+#: ui/SettingsPosition.ui.h:9
msgid "Apply changes to all monitors"
msgstr "Appliquer les changements sur tous les écrans"
-#: ui/SettingsPosition.ui:127
+#: ui/SettingsPosition.ui.h:10
msgid "Panel screen position"
msgstr "Position du panneau"
-#: ui/SettingsPosition.ui:169
-msgid "Panel thickness"
-msgstr "Taille du panneau"
-
-#: ui/SettingsPosition.ui:170
+#: ui/SettingsPosition.ui.h:15
msgid "(default is 48)"
msgstr "(la valeur par défaut est 48)"
-#: ui/SettingsPosition.ui:187
-msgid "Panel length (%)"
-msgstr "Longueur du panneau (%)"
+#: ui/SettingsPosition.ui.h:16
+msgid "Panel thickness"
+msgstr "Taille du panneau"
-#: ui/SettingsPosition.ui:188
+#: ui/SettingsPosition.ui.h:17
msgid "(default is 100)"
msgstr "(la valeur par défaut est 100)"
-#: ui/SettingsPosition.ui:204
+#: ui/SettingsPosition.ui.h:18
+msgid "Panel length"
+msgstr "Longueur du panneau"
+
+#: ui/SettingsPosition.ui.h:19
+msgid "Dynamic"
+msgstr "Dynamique"
+
+#: ui/SettingsPosition.ui.h:20
msgid "Anchor"
msgstr "Ancrage"
-#: ui/SettingsPosition.ui:227
+#: ui/SettingsPosition.ui.h:24
msgid "Taskbar Display"
msgstr "Affichage de la barre des tâches"
-#: ui/SettingsStyle.ui:38
+#: ui/SettingsStyle.ui.h:1
msgid "Style"
msgstr "Style"
-#: ui/SettingsStyle.ui:44
+#: ui/SettingsStyle.ui.h:2
+msgid "Global style"
+msgstr "Style global"
+
+#: ui/SettingsStyle.ui.h:3
+msgid "Border radius"
+msgstr "Coins arrondis"
+
+#: ui/SettingsStyle.ui.h:4
msgid "AppIcon style"
msgstr "Style des icônes d'application"
-#: ui/SettingsStyle.ui:48
-msgid "App Icon Margin"
-msgstr "Marge ext. de l'icône d'application"
-
-#: ui/SettingsStyle.ui:49
+#: ui/SettingsStyle.ui.h:5
msgid "(default is 8)"
msgstr "(la valeur par défaut est 8)"
-#: ui/SettingsStyle.ui:66
-msgid "App Icon Padding"
-msgstr "Marge int. de l'icône d'application"
+#: ui/SettingsStyle.ui.h:6
+msgid "App Icon Margin"
+msgstr "Marge de l'icône d'application"
-#: ui/SettingsStyle.ui:67
+#: ui/SettingsStyle.ui.h:7
msgid "(default is 4)"
msgstr "(la valeur par défaut est 4)"
-#: ui/SettingsStyle.ui:84
+#: ui/SettingsStyle.ui.h:8
+msgid "App Icon Padding"
+msgstr "Remplissage de l'icône d'application"
+
+#: ui/SettingsStyle.ui.h:9
msgid "Animate hovering app icons"
msgstr "Animer le survol des icônes d'application"
-#: ui/SettingsStyle.ui:109
+#: ui/SettingsStyle.ui.h:10
+msgid "Highlight hovering app icons"
+msgstr "Animer le survol des icônes d'application"
+
+#: ui/SettingsStyle.ui.h:11
msgid "Icon style"
msgstr "Style d'icône"
-#: ui/SettingsStyle.ui:114
+#: ui/SettingsStyle.ui.h:12
msgid "Normal"
msgstr "Normal"
-#: ui/SettingsStyle.ui:115
+#: ui/SettingsStyle.ui.h:13
msgid "Symbolic"
msgstr "Symbolique"
-#: ui/SettingsStyle.ui:127
+#: ui/SettingsStyle.ui.h:14
+msgid "Grayscale"
+msgstr "Niveaux de gris"
+
+#: ui/SettingsStyle.ui.h:15
msgid "Running indicator"
msgstr "Position de l'indicateur d'activité"
-#: ui/SettingsStyle.ui:131
+#: ui/SettingsStyle.ui.h:16
msgid "Running indicator position"
msgstr "Position de l'indicateur d'activité"
-#: ui/SettingsStyle.ui:168
+#: ui/SettingsStyle.ui.h:21
msgid "Running indicator style (Focused app)"
msgstr "Style de l'indicateur d'activité (Application active)"
-#: ui/SettingsStyle.ui:186 ui/SettingsStyle.ui:206
+#: ui/SettingsStyle.ui.h:22
msgid "Dots"
msgstr "Points"
-#: ui/SettingsStyle.ui:187 ui/SettingsStyle.ui:207
+#: ui/SettingsStyle.ui.h:23
msgid "Squares"
msgstr "Carrés"
-#: ui/SettingsStyle.ui:188 ui/SettingsStyle.ui:208
+#: ui/SettingsStyle.ui.h:24
msgid "Dashes"
msgstr "Traits"
-#: ui/SettingsStyle.ui:189 ui/SettingsStyle.ui:209
+#: ui/SettingsStyle.ui.h:25
msgid "Segmented"
msgstr "Segmenté"
-#: ui/SettingsStyle.ui:190 ui/SettingsStyle.ui:210
+#: ui/SettingsStyle.ui.h:26
msgid "Solid"
msgstr "Solide"
-#: ui/SettingsStyle.ui:191 ui/SettingsStyle.ui:211
+#: ui/SettingsStyle.ui.h:27
msgid "Ciliora"
msgstr "Ciliora"
-#: ui/SettingsStyle.ui:192 ui/SettingsStyle.ui:212
+#: ui/SettingsStyle.ui.h:28
msgid "Metro"
msgstr "Metro"
-#: ui/SettingsStyle.ui:201
+#: ui/SettingsStyle.ui.h:29
msgid "Running indicator style (Unfocused apps)"
msgstr "Style de l'indicateur d'activité (Applications inactives)"
-#: ui/SettingsStyle.ui:225
+#: ui/SettingsStyle.ui.h:30
msgid "Panel style"
msgstr "Style du panneau"
-#: ui/SettingsStyle.ui:229
+#: ui/SettingsStyle.ui.h:31
+msgid "(default is 0)"
+msgstr "(la valeur par défaut est 0)"
+
+#: ui/SettingsStyle.ui.h:32
+msgid "Side margins"
+msgstr "Marges latérales"
+
+#: ui/SettingsStyle.ui.h:33
+msgid "Top and bottom margins"
+msgstr "Marges supérieure et inférieure"
+
+#: ui/SettingsStyle.ui.h:34
+msgid "Side padding"
+msgstr "Remplissage latéral"
+
+#: ui/SettingsStyle.ui.h:35
+msgid "Top and bottom padding"
+msgstr "Remplissage supérieur et inférieur"
+
+#: ui/SettingsStyle.ui.h:36
msgid "Override panel theme background color"
msgstr "Remplacer la couleur de fond du thème du panneau"
-#: ui/SettingsStyle.ui:251
+#: ui/SettingsStyle.ui.h:37
msgid "Override panel theme background opacity"
msgstr "Remplacer l'opacité du thème du panneau"
-#: ui/SettingsStyle.ui:262
+#: ui/SettingsStyle.ui.h:39
+#, no-c-format
msgid "Panel background opacity (%)"
msgstr "Opacité du fond du panneau"
-#: ui/SettingsStyle.ui:275
-msgid "Dynamic background opacity"
-msgstr "Opacité de fond dynamique"
-
-#: ui/SettingsStyle.ui:276
+#: ui/SettingsStyle.ui.h:41
msgid "Change opacity when a window gets close to the panel"
msgstr "Changer l'opacité lorsqu'une fenêtre s'approche du panneau"
-#: ui/SettingsStyle.ui:308
+#: ui/SettingsStyle.ui.h:42
+msgid "Dynamic background opacity"
+msgstr "Opacité de fond dynamique"
+
+#: ui/SettingsStyle.ui.h:43
msgid "Override panel theme gradient"
msgstr "Remplacer le gradient du thème du panneau"
-#: ui/SettingsStyle.ui:319
+#: ui/SettingsStyle.ui.h:45
+#, no-c-format
msgid "Gradient top color and opacity (%)"
msgstr "Couleur et opacité (%) du haut du gradient"
-#: ui/SettingsStyle.ui:338
+#: ui/SettingsStyle.ui.h:47
+#, no-c-format
msgid "Gradient bottom color and opacity (%)"
msgstr "Couleur et opacité (%) du bas du gradient"
-#: windowPreview.js:938
-msgid "Move to current Workspace"
-msgstr "Déplacer vers l'espace de travail courrant"
-
msgid "Weekday"
msgstr "Jour de la semaine"
@@ -1501,12 +1609,36 @@ msgstr "Afficher le Bureau – icône"
msgid "Show Desktop button padding (px)"
msgstr "Afficher le Bureau - rembourrage du bouton (px)"
-msgid "Floating rounded theme"
-msgstr "Thème arrondi flottant"
-
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Isoler les espaces de travail et les moniteurs dans les paramètres de Bascule entre les applications"
+#~ msgid "Unavailable when gnome-shell top panel is present"
+#~ msgstr "Indisponible quand le panneau de gnome-shell est présent"
+
+#~ msgid "Unavailable when the panel on the primary monitor is at the top"
+#~ msgstr "Indisponible quand le panneau sur l'écran principal est au haut"
+
+#~ msgid "Nothing yet!"
+#~ msgstr "Rien pour l'instant !"
+
+#~ msgid "For real..."
+#~ msgstr "Pour vrai..."
+
+#~ msgid "Advanced Options"
+#~ msgstr "Options avancées"
+
+#~ msgid "Terminal"
+#~ msgstr "Terminal"
+
+#~ msgid "Extensions"
+#~ msgstr "Extensions"
+
+#~ msgid "Top Bar"
+#~ msgstr "Panneau du haut"
+
+#~ msgid "Move to current Workspace"
+#~ msgstr "Déplacer vers l'espace de travail courrant"
+
#~ msgid "Windows"
#~ msgstr "Fenêtres"
@@ -1659,9 +1791,6 @@ msgstr "Isoler les espaces de travail et les moniteurs dans les paramètres de B
#~ msgid "Display favorite applications on all monitors"
#~ msgstr "Afficher les applications favorites sur tous les écrans"
-#~ msgid "Display the clock on all monitors"
-#~ msgstr "Afficher l'horloge sur tous les écrans"
-
#~ msgid "Display the status menu on all monitors"
#~ msgstr "Afficher le menu système sur tous les écrans"
@@ -1674,9 +1803,6 @@ msgstr "Isoler les espaces de travail et les moniteurs dans les paramètres de B
#~ msgid "Show Applications icon"
#~ msgstr "Afficher l'icône Applications"
-#~ msgid "Highlight color"
-#~ msgstr "Couleur de surlignement"
-
#~ msgid "Preview timeout on icon leave (ms)"
#~ msgstr "Délai de l'aperçu lorsqu'on quitte l'icône (ms)"
diff --git a/po/ga.po b/po/ga.po
index d105904..dac8511 100644
--- a/po/ga.po
+++ b/po/ga.po
@@ -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"
diff --git a/po/gl.po b/po/gl.po
index 10485b9..445f6bc 100644
--- a/po/gl.po
+++ b/po/gl.po
@@ -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"
diff --git a/po/gu.po b/po/gu.po
index 560d76e..8070cb5 100644
--- a/po/gu.po
+++ b/po/gu.po
@@ -21,6 +21,3 @@ msgstr "ડેસ્કટ .પ ચિહ્ન બતાવો"
msgid "Show Desktop button padding (px)"
msgstr "ડેસ્કટtopપ બટન બતાવો પેડિંગ (પીએક્સ)"
-
-msgid "Floating rounded theme"
-msgstr "ફ્લોટિંગ ગોળાકાર થીમ"
diff --git a/po/he.po b/po/he.po
index e282b11..5afd434 100644
--- a/po/he.po
+++ b/po/he.po
@@ -21,6 +21,3 @@ msgstr "הצגת סמל שולחן העבודה"
msgid "Show Desktop button padding (px)"
msgstr "ריפוד הצגת כפתור שולחן עבודה (פיקסלים)"
-
-msgid "Floating rounded theme"
-msgstr "ערכת נושא מעוגלת עם ריחוף"
diff --git a/po/hi.po b/po/hi.po
index b1d1674..c33a6ba 100644
--- a/po/hi.po
+++ b/po/hi.po
@@ -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 "एप्लिकेशन स्विचिंग सेटिंग्स में कार्यस्थलों और मॉनिटर को अलग करें"
diff --git a/po/hr.po b/po/hr.po
index 159fa97..109af40 100644
--- a/po/hr.po
+++ b/po/hr.po
@@ -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"
diff --git a/po/hu.po b/po/hu.po
index f041c08..8accb64 100644
--- a/po/hu.po
+++ b/po/hu.po
@@ -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"
diff --git a/po/id.po b/po/id.po
index 3f35243..015faff 100644
--- a/po/id.po
+++ b/po/id.po
@@ -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"
diff --git a/po/is.po b/po/is.po
index af7e151..a376950 100644
--- a/po/is.po
+++ b/po/is.po
@@ -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"
diff --git a/po/it.po b/po/it.po
index 5dae0d7..380a642 100644
--- a/po/it.po
+++ b/po/it.po
@@ -1428,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"
diff --git a/po/ja.po b/po/ja.po
index c489804..b61434b 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -1492,9 +1492,6 @@ msgstr "デスクトップアイコンを表示"
msgid "Show Desktop button padding (px)"
msgstr "デスクトップボタンを表示 余白 (px)"
-msgid "Floating rounded theme"
-msgstr "フローティングラウンドテーマ"
-
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "アプリケーションの切り替え設定でワークスペースとモニターを分離する"
diff --git a/po/ka.po b/po/ka.po
index 12930b4..5df5faa 100644
--- a/po/ka.po
+++ b/po/ka.po
@@ -15,6 +15,3 @@ msgstr "აჩვენე დესკტოპის იკონები"
msgid "Show Desktop button padding (px)"
msgstr "ღილაკი აჩვენე დესკტოპი"
-
-msgid "Floating rounded theme"
-msgstr "მოფარფატე მომრგვალო თემა"
diff --git a/po/kn.po b/po/kn.po
index 5bd07f0..a8d0dc9 100644
--- a/po/kn.po
+++ b/po/kn.po
@@ -21,6 +21,3 @@ msgstr "ಡೆಸ್ಕ್ಟಾಪ್ ಐಕಾನ್ ತೋರಿಸಿ"
msgid "Show Desktop button padding (px)"
msgstr "ಡೆಸ್ಕ್ಟಾಪ್ ಬಟನ್ ತೋರಿಸು ಪ್ಯಾಡಿಂಗ್ (ಪಿಎಕ್ಸ್)"
-
-msgid "Floating rounded theme"
-msgstr "ತೇಲುವ ದುಂಡಾದ ಥೀಮ್"
diff --git a/po/ko.po b/po/ko.po
index 6188bf3..2213a75 100644
--- a/po/ko.po
+++ b/po/ko.po
@@ -1469,9 +1469,6 @@ msgstr "바탕 화면 아이콘 표시"
msgid "Show Desktop button padding (px)"
msgstr "바탕 화면 버튼 표시 패딩(px)"
-msgid "Floating rounded theme"
-msgstr "떠 다니는 둥근 테마"
-
#~ msgid "Current Show Applications icon"
#~ msgstr "현재 프로그램 표시 아이콘"
diff --git a/po/lt.po b/po/lt.po
index 20956d4..f169353 100644
--- a/po/lt.po
+++ b/po/lt.po
@@ -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"
diff --git a/po/lv.po b/po/lv.po
index fef070b..847b547 100644
--- a/po/lv.po
+++ b/po/lv.po
@@ -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"
diff --git a/po/mk.po b/po/mk.po
index ca8323d..96e8510 100644
--- a/po/mk.po
+++ b/po/mk.po
@@ -18,6 +18,3 @@ msgstr "Покажете ја иконата за работната површ
msgid "Show Desktop button padding (px)"
msgstr "Пополнување „Покажи копче за работна површина“ (px)"
-
-msgid "Floating rounded theme"
-msgstr "Лебдечка заоблена тема"
diff --git a/po/ms.po b/po/ms.po
index c1ef357..b2a1c36 100644
--- a/po/ms.po
+++ b/po/ms.po
@@ -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"
diff --git a/po/ne.po b/po/ne.po
index 69f286f..d1f5f27 100644
--- a/po/ne.po
+++ b/po/ne.po
@@ -21,6 +21,3 @@ msgstr "डेस्कटप प्रतिमा देखाउनुहो
msgid "Show Desktop button padding (px)"
msgstr "डेस्कटप बटन देखाउनुहोस् प्याडि ((px)"
-
-msgid "Floating rounded theme"
-msgstr "फ्लोटिंग गोल थिम"
diff --git a/po/nl.po b/po/nl.po
index 229e879..94424e3 100644
--- a/po/nl.po
+++ b/po/nl.po
@@ -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"
diff --git a/po/pa.po b/po/pa.po
index 41cf3a7..9b72054 100644
--- a/po/pa.po
+++ b/po/pa.po
@@ -21,6 +21,3 @@ msgstr "ਡੈਸਕਟਾਪ ਆਈਕਾਨ ਵੇਖਾਓ"
msgid "Show Desktop button padding (px)"
msgstr "ਡੈਸਕਟਾਪ ਬਟਨ ਦਿਖਾਓ ਭਰਾਵ (px)"
-
-msgid "Floating rounded theme"
-msgstr "ਫਲੋਟਿੰਗ ਗੋਲ ਥੀਮ"
diff --git a/po/pl.po b/po/pl.po
index 145f608..c1f2838 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -4,183 +4,2127 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: \n"
+"Project-Id-Version: Dash to Panel\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-02-08 08:31-0500\n"
-"PO-Revision-Date: 2019-10-11 12:34+0200\n"
-"Last-Translator: Alex \n"
+"POT-Creation-Date: 2025-03-10 16:25+0100\n"
+"PO-Revision-Date: 2025-03-10 16:31+0100\n"
+"Last-Translator: Adam Lewicki \n"
"Language-Team: \n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 2.2.1\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n"
+"X-Generator: Poedit 3.4.4\n"
-#: prefs.js:247
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:75
+msgid "Panel position (Deprecated)"
+msgstr "Położenie panelu (przestarzałe)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:76
+msgid "Panel is shown on the Bottom or Top of the screen."
+msgstr "Panel jest wyświetlany u dołu lub u góry ekranu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:80
+msgid "Sync element positions"
+msgstr "Synchronizuj położenie elementu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:81
+msgid "Sync panel element positions on all monitors."
+msgstr "Synchronizuj położenie elementów panelu na wszystkich monitorach."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:85
+msgid "Panel positions"
+msgstr "Położenie panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:86
+msgid "Panel positions (JSON)."
+msgstr "Położenie panelu (JSON)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:90
+msgid "Panel element positions"
+msgstr "Położenie elementów panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:91
+msgid "Panel element positions (JSON)."
+msgstr "Położenie elementów panelu (JSON)."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:95
+msgid ""
+"Percentages of screen edge for panel to span, -1 for dynamic length (dock "
+"mode)"
+msgstr ""
+"Procent krawędzi ekranu, na której rozciąga się panel, -1 dla dynamicznej "
+"długości (tryb doku)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:96
+msgid "Length of the panels, in percent (JSON)."
+msgstr "Długość paneli w procentach (JSON)."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:100
+msgid "Positions along screen edge"
+msgstr "Położenia wzdłuż krawędzi ekranu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:101
+msgid ""
+"Where to show the panels if it is not the full length of the screen edge "
+"(JSON)."
+msgstr ""
+"Gdzie wyświetlać panele, jeśli nie zajmują całej długości krawędzi ekranu "
+"(JSON)."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:105
+msgid "Panel sizes"
+msgstr "Rozmiary paneli"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:106
+msgid "Sizes of panels, in pixels."
+msgstr "Rozmiary paneli w pikselach."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:110
+msgid "Panel size (Deprecated)"
+msgstr "Rozmiar panelu (przestarzałe)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:111
+msgid "Set the size of the panel."
+msgstr "Ustaw rozmiar panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:115
+#: ui/BoxShowDesktopOptions.ui:53
+msgid "Override Show Desktop line color"
+msgstr "Zastąp kolor linii Pokaż pulpit"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:116
+msgid "Replace current Show Desktop button line color"
+msgstr "Zastąp obecny kolor linii przycisku Pokaż pulpit"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:120
+msgid "Custom Show Desktop line color"
+msgstr "Niestandardowy kolor linii przycisku Pokaż pulpit"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:121
+msgid "Custom Show Desktop button line color"
+msgstr "Niestandardowy kolor linii przycisku Pokaż pulpit"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:125
+msgid "Dot position"
+msgstr "Położenie kropki"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:126
+msgid "Running indicators are shown on the Bottom or Top of the screen."
+msgstr ""
+"Wskaźniki uruchomionych programów są wyświetlane u dołu lub u góry ekranu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:130
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:131
+msgid "Style of Appicons"
+msgstr "Styl ikon programów"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:135
+msgid "Style of the running indicator (focused)"
+msgstr "Styl wskaźnika uruchomionych programów (pierwszoplanowych)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:136
+msgid ""
+"Style of the running indicator for the icon for the currently focused "
+"application"
+msgstr ""
+"Styl wskaźnika uruchomionych programów dla ich ikony programów "
+"pierwszoplanowych"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:140
+msgid "Style of the running indicator (unfocused)"
+msgstr "Styl wskaźnika uruchomionych programów (drugoplanowych)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:141
+msgid ""
+"Style of the running indicator for the icon for applications which are not "
+"currently focused"
+msgstr ""
+"Styl wskaźnika uruchomionych programów dla ich ikon, które nie są aktualnie "
+"na pierwszym planie"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:145
+msgid "Running indicator dominant color"
+msgstr "Dominujący kolor wskaźnika uruchomienia"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:146
+msgid "Whether to use the app icon's dominant color for .app-well-running-dot"
+msgstr "Używanie dominującego koloru ikony aplikacji dla .app-well-running-dot"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:150
+msgid "Running indicator color override"
+msgstr "Zastąpienie koloru wskaźnika uruchomionych programów"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:151
+msgid ""
+"Whether to override the theme background color for .app-well-running-dot"
+msgstr "Zastąpienie koloru tła motywu dla .app-well-running-dot"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:155
+msgid "Color of running indicator (1 window)"
+msgstr "Kolor wskaźnika uruchomienia (1 okno)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:156
+msgid ""
+"Customize the color of the running indicator when one window is running for "
+"that application"
+msgstr ""
+"Dostosuj kolor wskaźnika uruchomionych programów, gdy dla danego programu "
+"jest uruchomione jedno okno"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:160
+msgid "Color of running indicator (2 windows)"
+msgstr "Kolor wskaźnika uruchomienia (2 okna)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:161
+msgid ""
+"Customize the color of the running indicator when two windows are running "
+"for that application"
+msgstr ""
+"Dostosuj kolor wskaźnika uruchomionych programów, gdy dla danego programu są "
+"uruchomione dwa okna"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:165
+msgid "Color of running indicator (3 windows)"
+msgstr "Kolor wskaźnika uruchomienia (3 okna)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:166
+msgid ""
+"Customize the color of the running indicator when three windows are running "
+"for that application"
+msgstr ""
+"Dostosuj kolor wskaźnika uruchomionych programów, gdy dla danego programu są "
+"uruchomione trzy okna"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:170
+msgid "Color of running indicator (4+ windows)"
+msgstr "Kolor wskaźnika uruchomienia (4+ okien)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:171
+msgid ""
+"Customize the color of the running indicator when four or more windows are "
+"running for that application"
+msgstr ""
+"Dostosuj kolor wskaźnika uruchomionych programów, gdy dla danego programu są "
+"uruchomione cztery lub więcej okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:175
+msgid "Unfocused color is different than focused"
+msgstr "Kolor programów drugoplanowych jest inny niż pierwszoplanowych"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:176
+msgid ""
+"Whether to apply a 2nd color scheme to the indicator when the app is not "
+"focused"
+msgstr ""
+"Drugi schemat kolorów do wskaźnika, gdy aplikacja nie jest na pierwszym "
+"planie"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:180
+msgid "Color of unfocused running indicator (1 window)"
+msgstr "Kolor wskaźnika drugoplanowych uruchomionych programów (1 okno)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:181
+msgid ""
+"Customize the color of the unfocused running indicator when one window is "
+"running for that application"
+msgstr ""
+"Dostosuj kolor wskaźnika drugoplanowych uruchomionych programów, gdy dla "
+"danej aplikacji jest uruchomione jedno okno"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:185
+msgid "Color of unfocused running indicator (2 windows)"
+msgstr "Kolor wskaźnika drugoplanowych uruchomionych programów (2 okna)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:186
+msgid ""
+"Customize the color of the unfocused running indicator when two windows are "
+"running for that application"
+msgstr ""
+"Dostosuj kolor wskaźnika drugoplanowych programów, gdy dla danej aplikacji "
+"są uruchomione dwa okna"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:190
+msgid "Color of unfocused running indicator (3 windows)"
+msgstr "Kolor wskaźnika drugoplanowych uruchomionych programów (3 okna)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:191
+msgid ""
+"Customize the color of the unfocused running indicator when three windows "
+"are running for that application"
+msgstr ""
+"Dostosuj kolor wskaźnika drugoplanowych uruchomionych programów, gdy dla "
+"danej aplikacji są uruchomione trzy okna"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:195
+msgid "Color of unfocused running indicator (4+ windows)"
+msgstr "Kolor wskaźnika drugoplanowych uruchomionych programów (4+ okien)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:196
+msgid ""
+"Customize the color of the unfocused running indicator when four or more "
+"windows are running for that application"
+msgstr ""
+"Dostosuj kolor wskaźnika drugoplanowych uruchomionych programów, gdy dla "
+"danej aplikacji są uruchomione cztery lub więcej okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:200
+msgid "Running indicator height"
+msgstr "Wysokość wskaźnika uruchomionych programów"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:201
+msgid "Height of the running indicator line/diameter of window indicator dots"
+msgstr ""
+"Wysokość linii wskaźnika uruchomionych programów/średnica kropek wskaźnika "
+"okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:205
+msgid "Highlight icon of focused application"
+msgstr "Podświetl ikonę pierwszoplanowego programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:206
+msgid ""
+"Whether to highlight the background of the currently focused application's "
+"icon"
+msgstr "Podświetlenie tła ikony aktualnego pierwszoplanowego programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:210
+msgid "Highlight icon dominant color"
+msgstr "Podświetl dominujący kolor ikony"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:211
+msgid "Base the active window highlight color on that application's icon"
+msgstr "Oparcie koloru podświetlenia aktywnego okna na ikonie tego programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:215
+msgid "Color of highlight of focused application"
+msgstr "Kolor podświetlenia programu pierwszoplanowego"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:216
+msgid "Customize the color of the highlight of the focused application"
+msgstr "Dostosuj kolor podświetlenia pierwszoplanowego programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:220
+msgid "Opacity of highlight of focused application"
+msgstr "Przezroczystość podświetlenia programu pierwszoplanowego"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:221
+msgid "Customize the opacity of the highlight of the focused application"
+msgstr "Dostosuj przezroczystość podświetlenia pierwszoplanowej aplikacji"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:225
+msgid "Keep dash"
+msgstr "Zachowaj panel"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:226
+msgid "Whether to keep the stock gnome-shell dash while in overview"
+msgstr "Zachowuj domyślny panel powłoki GNOME podczas przeglądu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:230
+msgid "Keep top panel"
+msgstr "Zachowaj górny panel"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:231
+msgid "Whether to keep the stock gnome-shell top panel"
+msgstr "Zachowaj domyślny górny panel powłoki GNOME"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:235
+msgid "Panel menu buttons require click"
+msgstr "Przyciski menu panelu wymagają kliknięcia"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:236
+msgid "Whether to activate the panel menu buttons on hover or on click"
+msgstr ""
+"Aktywacja przycisków menu panelu po najechaniu kursorem, lub po kliknięciu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:240
+msgid "Force hot corner"
+msgstr "Wymuś gorący róg"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:241
+msgid "Wheter to force having an Activities hot corner on the primary monitor"
+msgstr "Wymuś posiadanie aktywnego rogu Aktywności na monitorze głównym"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:245
+msgid "Lock the taskbar"
+msgstr "Zablokuj pasek zadań"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:246
+msgid "Specifies if the user can modify the taskbar"
+msgstr "Określa, czy użytkownik może modyfikować pasek zadań"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:250
+msgid "Panel top and bottom margins"
+msgstr "Marginesy górny i dolny panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:254
+msgid "Panel side margins"
+msgstr "Marginesy boczne panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:258
+msgid "Panel top and bottom padding"
+msgstr "Wypełnienie górne i dolne panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:262
+msgid "Panel sides padding"
+msgstr "Wypełnienie boków panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:266
+msgid "Override theme background color"
+msgstr "Zastąp kolor tła motywu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:267
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:277
+msgid "Replace current theme background color for the panel"
+msgstr "Zastąp aktualny kolor tła motywu dla panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:271
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:276
+msgid "Custom background color"
+msgstr "Niestandardowy kolor tła"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:272
+msgid "Custom background color for the panel"
+msgstr "Niestandardowy kolor tła panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:281
+msgid "Dynamic opacity"
+msgstr "Dynamiczna przezroczystość"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:282
+msgid "Enable dynamic opacity"
+msgstr "Włącz dynamiczną przezroczystość"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:286
+msgid "Panel opacity"
+msgstr "Przezroczystość panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:287
+msgid "Custom opacity for the panel"
+msgstr "Niestandardowa przezroczystość panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:291
+msgid "Dynamic opacity behavior"
+msgstr "Zachowanie dynamicznej przezroczystości"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:292
+msgid "Dictates which window type affects the panel opacity"
+msgstr "Wpływ typu okna wpływa na przezroczystość panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:296
+msgid "Distance to change opacity"
+msgstr "Odległość zmiany przezroczystości"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:297
+msgid "The distance a window needs to be from the panel to change opacity"
+msgstr ""
+"Odległość, jaką okno musi osiągnąć od panelu, aby zmienić przezroczystość"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:301
+msgid "Modified panel opacity"
+msgstr "Zmodyfikowana przezroczystość panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:302
+msgid "Modified opacity for the panel when a window is near"
+msgstr "Zmodyfikowana przezroczystość panelu, gdy okno znajduje się w pobliżu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:306
+msgid "Opacity change duration"
+msgstr "Czas trwania zmiany przezroczystości"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:307
+msgid "The duration of the animation when the opacity changes"
+msgstr "Czas trwania animacji zmiany przezroczystości"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:311
+msgid "Custom gradient"
+msgstr "Niestandardowy gradient"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:312
+msgid "Replace current theme gradient for the panel"
+msgstr "Zastąp aktualny gradient motywu dla panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:316
+msgid "Custom gradient top color"
+msgstr "Niestandardowy górny kolor gradientu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:317
+msgid "Custom gradient top color for the panel"
+msgstr "Niestandardowy górny kolor gradientu panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:321
+msgid "Custom gradient top opacity"
+msgstr "Niestandardowa górna przezroczystość gradientu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:322
+msgid "Custom gradient top opacity for the panel"
+msgstr "Niestandardowa górna przezroczystość gradientu panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:326
+msgid "Custom gradient bottom color"
+msgstr "Niestandardowy dolny kolor gradientu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:327
+msgid "Custom gradient bottom color for the panel"
+msgstr "Niestandardowy dolny kolor gradientu panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:331
+msgid "Custom gradient bottom opacity"
+msgstr "Niestandardowa dolna przezroczystość gradientu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:332
+msgid "Custom gradient bottom opacity for the panel"
+msgstr "Niestandardowa dolna przezroczystość gradientu panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:336
+msgid "Intellihide"
+msgstr "Inteligentne ukrywanie"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:337
+msgid "Whether to intelligently hide the panel"
+msgstr "Inteligentne ukrywanie panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:341
+msgid "Only hide from windows"
+msgstr "Ukrywaj tylko przed oknami"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:342
+msgid "Dictates if the dash should only hide when in conflict with windows"
+msgstr ""
+"Określa, czy panel powinien być ukrywany tylko w przypadku kolizji z oknami"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:346
+msgid "Intellihide behaviour"
+msgstr "Zachowanie inteligentnego ukrywania"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:347
+msgid "Dictates how to intelligently hide the panel"
+msgstr "Określa, jak inteligentnie ukrywać panel"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:351
+msgid "Intellihide pressure"
+msgstr "Nacisk inteligentnego ukrywania"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:352
+msgid ""
+"To reveal the panel, pressure needs to be applied to the edege of the screen"
+msgstr "Aby odsłonić panel, należy wywrzeć nacisk na krawędź ekranu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:356
+msgid "Intellihide pressure threshold"
+msgstr "Próg nacisku inteligentnego ukrywania"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:357
+msgid "The pressure needed to reveal the panel"
+msgstr "Nacisk potrzebny do odsłonięcia panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:361
+msgid "Intellihide pressure time"
+msgstr "Czas nacisku inteligentnego ukrywania"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:362
+msgid ""
+"The numer of milliseconds that the pressure needs to be applied to reveal "
+"the panel"
+msgstr ""
+"Liczba milisekund, przez które należy wywierać nacisk, aby odsłonić panel"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:366
+msgid "Allow revealing the panel while in fullscreen"
+msgstr "Zezwalaj na ujawnienie panelu w trybie pełnoekranowym"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:367
+msgid ""
+"Allow the panel to be revealed while an application is in fullscreen mode"
+msgstr ""
+"Zezwalaj na ujawnienie panelu, gdy program jest w trybie pełnoekranowym"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:371
+msgid "Reveal the panel on notification"
+msgstr "Odsłoń panel przy powiadomieniu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:375
+msgid "Intellihide only secondary"
+msgstr "Inteligentne ukrywanie tylko na dodatkowych monitorach"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:376
+msgid "Whether to only hide secondary panels"
+msgstr "Ukryj tylko panele dodatkowe"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:380
+msgid "Intellihide animation time"
+msgstr "Czas trwania animacji inteligentnego ukrywania"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:381
+msgid "The animation time (ms) to hide and reveal the panel"
+msgstr "Czas animacji (ms) ukrywania i odkrywania panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:385
+msgid "Intellihide close delay"
+msgstr "Opóźnienie zamykania inteligentnego ukrywania"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:386
+msgid "The delay (ms) before hiding the panel"
+msgstr "Opóźnienie (ms) przed ukryciem panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:390
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:395
+msgid "Keybinding toggle intellihide"
+msgstr "Skrót klawiszowy do przełączania inteligentnego ukrywania"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:391
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:396
+msgid "Keybinding to reveal the panel while in intellihide mode"
+msgstr ""
+"Skrót klawiszowy do odsłonięcia panelu w trybie inteligentnego ukrywania"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:400
+msgid "Persisted intellihide hold status. -1 means the option is disabled"
+msgstr ""
+"Utrwalony stan przytrzymania inteligentnego ukrywania. -1 oznacza, że opcja "
+"jest wyłączona"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:404
+msgid "Intellihide enable start delay"
+msgstr "Opóźnienie włączenia inteligentnego ukrywania"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:405
+msgid "The delay before enabling intellihide on start"
+msgstr "Opóźnienie przed włączeniem inteligentnego ukrywania przy starcie"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:409
+msgid "Custom Show Applications icon"
+msgstr "Niestandardowa ikona Pokaż programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:410
+msgid "Customize the Show Applications icon"
+msgstr "Dostosuj ikonę Pokaż programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:414
+msgid "Show Applications icon side padding"
+msgstr "Wypełnienie boczne ikony Pokaż programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:415
+msgid "Customize the Show Applications icon side padding"
+msgstr "Dostosuj odstęp ikony Pokaż programy od krawędzi"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:419
+msgid "Override escape key"
+msgstr "Zastąp klawisz ESC"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:420
+msgid ""
+"Override the escape key to return to the desktop when entering the overview "
+"using the Show Applications button"
+msgstr ""
+"Zastąp klawisz ESC, aby powrócić do pulpitu podczas wchodzenia do podglądu "
+"za pomocą przycisku Pokaż programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:424
+msgid "Show Apps button context menu commands"
+msgstr "Polecenia menu kontekstowego przycisku Pokaż programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:425
+msgid "Commands to add to the Show Apps button right click menu"
+msgstr "Polecenia do dodania do menu prawego przycisku myszy Pokaż programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:429
+msgid "Show Apps button context menu titles"
+msgstr "Tytuły menu kontekstowego przycisku Pokaż programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:430
+msgid "Titles for commands added to Show Apps button right click menu"
+msgstr "Tytuły poleceń dodanych do menu prawego przycisku myszy Pokaż programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:434
+msgid "Panel context menu commands"
+msgstr "Polecenia menu kontekstowego panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:435
+msgid "Commands to add to the panel right click menu"
+msgstr "Polecenia do dodania do menu prawego przycisku myszy panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:439
+msgid "Panel context menu titles"
+msgstr "Tytuły menu kontekstowego panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:440
+msgid "Titles for commands added to panel right click menu"
+msgstr "Tytuły poleceń dodanych do menu prawego przycisku myszy panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:444
+msgid "Show activities button"
+msgstr "Pokaż przycisk Aktywności"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:445
+msgid "Show activities button on the left hand side of the taskbar"
+msgstr "Pokaż przycisk Aktywności po lewej stronie paska zadań"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:449
+msgid "Width of show Desktop button"
+msgstr "Szerokość przycisku Pokaż pulpit"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:450
+msgid "Customize the width of the show Desktop button"
+msgstr "Dostosuj szerokość przycisku Pokaż pulpit"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:454
+msgid "Show desktop on hover"
+msgstr "Pokaż pulpit po najechaniu kursorem"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:455
+msgid "Show the desktop on mouse hover"
+msgstr "Pokaż pulpit po najechaniu myszą"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:459
+msgid "Delay show desktop"
+msgstr "Opóźnienie pokazywania pulpitu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:460
+msgid "Delay before showing the desktop"
+msgstr "Opóźnienie przed pokazaniem pulpitu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:464
+msgid "Show desktop animation time"
+msgstr "Czas animacji pokazywania pulpitu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:465
+msgid "Window fade animation time when showing the destop"
+msgstr "Czas animacji zanikania okna podczas pokazywania pulpitu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:469
+msgid "Show window preview"
+msgstr "Pokaż podgląd okna"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:470
+msgid "Show preview of running window on hover of app icon"
+msgstr ""
+"Pokaż podgląd uruchomionego okna po najechaniu kursorem na ikonę programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:474
+msgid "Show tooltip"
+msgstr "Pokaż etykietkę"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:475
+msgid "Show tooltip on hover of app icon"
+msgstr "Pokaż etykietkę po najechaniu kursorem na ikonę programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:479
+msgid "Show running apps"
+msgstr "Pokaż uruchomione programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:480
+msgid "Show or hide running application icons in the dash"
+msgstr "Pokaż lub ukryj ikony uruchomionych programów w panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:484
+msgid "Show favorites apps"
+msgstr "Pokaż ulubione programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:485
+msgid "Show or hide favorite application icons in the dash"
+msgstr "Pokaż lub ukryj ikony ulubionych programów w panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:489
+msgid "Icon enter display time"
+msgstr "Czas wyświetlania po najechaniu na ikonę"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:490
+msgid ""
+"Amount of time after entering icon to wait before displaying window preview "
+"if icon is not clicked or mouse has not left."
+msgstr ""
+"Czas oczekiwania po najechaniu na ikonę, zanim zostanie wyświetlony podgląd "
+"okna, jeśli ikona nie zostanie kliknięta lub kursor myszy nie opuścił "
+"obszaru ikony."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:494
+msgid "Enable peek mode"
+msgstr "Włącz tryb podglądu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:495
+msgid "Peek a window upon hover for some time"
+msgstr "Podgląd okna po najechaniu kursorem na pewien czas"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:499
+msgid "Display title in preview"
+msgstr "Wyświetl tytuł w podglądzie"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:500
+msgid "Display window title in preview"
+msgstr "Wyświetl tytuł okna w podglądzie"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:504
+msgid "Window previews manual styling"
+msgstr "Ręczne style podglądu okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:505
+msgid "This defines if the default window previews styling should be applied"
+msgstr "Określa, czy powinien być stosowany domyślny styl podglądu okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:509
+msgid "Title position"
+msgstr "Pozycja tytułu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:510
+msgid "Position of the window title, close button and icon in preview."
+msgstr "Pozycja tytułu okna, przycisku zamknięcia i ikony w podglądzie."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:514
+msgid "Window previews title font color"
+msgstr "Kolor czcionki tytułu podglądu okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:515
+msgid "This defines the window preview titles font color."
+msgstr "Określa kolor czcionki tytułów podglądu okien."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:519
+msgid "Window previews title font size"
+msgstr "Rozmiar czcionki tytułu podglądu okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:520
+msgid "This defines the window preview titles font size."
+msgstr "Określa rozmiar czcionki tytułów podglądu okien."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:524
+msgid "Window previews use custom icon size"
+msgstr "Podgląd okien używa niestandardowego rozmiaru ikony"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:525
+msgid "Window previews use custom application icon size."
+msgstr "Podglądy okien używają niestandardowego rozmiaru ikony programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:529
+msgid "Window previews custom icon size"
+msgstr "Niestandardowy rozmiar ikony podglądu okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:530
+msgid "Window previews custom application icon size."
+msgstr "Niestandardowy rozmiar ikony programu podglądu okien."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:534
+msgid "Window previews animation time"
+msgstr "Czas animacji podglądu okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:535
+msgid "This defines the window previews animation time."
+msgstr "Określa czas animacji podglądu okien."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:539
+msgid "Font weight of window preview titles"
+msgstr "Grubość czcionki tytułów podglądu okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:540
+msgid ""
+"This defines the font weight of window preview titles. Supported values: "
+"inherit (from theme), normal, lighter, bold and bolder."
+msgstr ""
+"Określa grubość czcionki tytułów podglądu okien. Obsługiwane wartości: "
+"dziedzicz (z motywu), normalna, cieńsza, gruba i grubsza."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:544
+msgid "Window previews size"
+msgstr "Rozmiar podglądów okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:545
+msgid "Preferred window previews size"
+msgstr "Preferowany rozmiar podglądu okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:549
+msgid "Fixed aspect ratio X"
+msgstr "Stały współczynnik proporcji X"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:550
+msgid "This defines if the window previews use a fixed aspect ratio X."
+msgstr "Określa, czy podgląd okien używa stałego współczynnika proporcji X."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:554
+msgid "Fixed aspect ratio Y"
+msgstr "Stały współczynnik proporcji Y"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:555
+msgid "This defines if the window previews use a fixed aspect ratio Y."
+msgstr "Określa, czy podgląd okien używa stałego współczynnika proporcji Y."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:559
+msgid "Window previews padding"
+msgstr "Wypełnienie podglądów okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:560
+msgid "The padding of the window previews"
+msgstr "Wypełnienie podglądów okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:564
+msgid "Aspect ratio X"
+msgstr "Współczynnik proporcji X"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:565
+msgid "The window previews respected aspect ratio X."
+msgstr "Podglądy okien zachowują proporcje X okna."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:569
+msgid "Aspect ratio Y"
+msgstr "Proporcje okna Y"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:570
+msgid "The window previews respected aspect ratio Y."
+msgstr "Podglądy okien zachowują proporcje Y okna."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:574
+msgid "Immediate hide on icon click"
+msgstr "Ukryj natychmiast po kliknięciu na ikonę"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:575
+msgid ""
+"The window previews immediately hide when an application icon is clicked."
+msgstr "Podgląd okna jest natychmiast ukrywany po kliknięciu ikony programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:579
+msgid "Provide workspace isolation"
+msgstr "Zapewnij izolację obszaru roboczego"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:580
+msgid "Dash shows only windows from the current workspace"
+msgstr "Panel wyświetla tylko okna z bieżącego obszaru roboczego"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:584
+msgid "Close overview by clicking in empty space"
+msgstr "Zamknij przegląd, klikając w puste miejsce"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:585
+msgid "Close overview or app grid by clicking in empty space"
+msgstr "Zamknij przegląd lub siatkę programów, klikając w puste miejsce"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:589
+msgid "Hide overview on startup"
+msgstr "Ukryj przegląd przy uruchomieniu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:590
+msgid ""
+"Hide overview on startup, which would be shown by default at gnome startup."
+msgstr ""
+"Ukryj przegląd podczas uruchamiania, który będzie domyślnie wyświetlany "
+"podczas uruchamiania środowiska GNOME."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:594
+msgid "Group applications"
+msgstr "Grupa programów"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:595
+msgid "Dash groups the application instances under the same icon"
+msgstr "Panel grupuje instancje programów pod tą samą ikoną"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:599
+msgid "Application title font size"
+msgstr "Rozmiar czcionki tytułu programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:600
+msgid ""
+"When the applications are ungrouped, this defines the application titles "
+"font size."
+msgstr ""
+"Gdy programy są rozgrupowane, definiuje rozmiar czcionki tytułów programów."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:604
+#: ui/BoxGroupAppsOptions.ui:47
+msgid "Font weight of application titles"
+msgstr "Grubość czcionki tytułów programów"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:605
+msgid ""
+"When the applications are ungrouped, this defines font weight of application "
+"titles. Supported values: inherit (from theme), normal, lighter, bold and "
+"bolder."
+msgstr ""
+"Gdy programy są rozgrupowane, definiuje grubość czcionki tytułów aplikacji. "
+"Obsługiwane wartości: dziedzicz (z motywu), normalna, cieńsza, gruba i "
+"grubsza."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:609
+msgid "Application title font color"
+msgstr "Kolor czcionki tytułu programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:610
+msgid ""
+"When the applications are ungrouped, this defines the application titles "
+"font color."
+msgstr ""
+"Gdy programy są rozgrupowane, ta opcja definiuje kolor czcionki ich tytułów."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:614
+msgid "Minimized application title font color"
+msgstr "Kolor czcionki tytułu zminimalizowanego programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:615
+msgid ""
+"When the applications are ungrouped, this defines the titles font color for "
+"minimized applications."
+msgstr ""
+"Gdy programy są rozgrupowane, ta opcja definiuje kolor czcionki tytułów "
+"zminimalizowanych programów."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:619
+msgid "Application title max width"
+msgstr "Maksymalna szerokość tytułu programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:620
+msgid ""
+"When the applications are ungrouped, this defines the application titles "
+"maximum width."
+msgstr ""
+"Gdy programy są rozgrupowane, definiuje maksymalną szerokość ich tytułów."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:624
+#: ui/BoxGroupAppsOptions.ui:111
+msgid "Use a fixed width for the application titles"
+msgstr "Użyj stałej szerokości tytułów programów"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:625
+#: ui/BoxGroupAppsOptions.ui:112
+msgid ""
+"The application titles all have the same width, even if their texts are "
+"shorter than the maximum width. The maximum width value is used as the fixed "
+"width."
+msgstr ""
+"Wszystkie tytuły programów będą miały tę samą szerokość, nawet jeśli ich "
+"teksty są krótsze niż maksymalna szerokość. Wartość stałej szerokości jest "
+"taka, jaka została podana w polu Maksymalna szerokość."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:629
+#: ui/BoxGroupAppsOptions.ui:129
+msgid "Display running indicators on unfocused applications"
+msgstr "Wyświetl wskaźnik dla otwartych okien drugoplanowych"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:630
+msgid ""
+"When the applications are ungrouped, this defines if running applications "
+"should display an indicator."
+msgstr ""
+"Określa, czy po rozgrupowaniu programów, uruchomione programy mają "
+"wyświetlać wskaźnik."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:634
+msgid "Use favorite icons as application launchers"
+msgstr "Użyj ulubionych ikon jako uruchamiających programy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:635
+msgid ""
+"When the applications are ungrouped, this defines if running applications "
+"stay separate from the favorite icons."
+msgstr ""
+"Po rozgrupowaniu programów opcja ta określa, czy uruchomione programy mają "
+"być oddzielone od ikon ulubionych."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:639
+msgid "Primary monitor index"
+msgstr "Indeks Głównego monitora"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:640
+msgid "Specifies the id of the primary monitor."
+msgstr "Określa identyfikator monitora głównego."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:644
+#: ui/SettingsPosition.ui:35
+msgid "Display panels on all monitors"
+msgstr "Wyświetl panel na wszystkich monitorach"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:645
+msgid "Specifies if a panel is shown on every monitors"
+msgstr "Określa, czy panel jest wyświetlany na każdym monitorze"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:649
+msgid "Provide monitor isolation"
+msgstr "Zapewnij izolację monitora"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:650
+msgid "Dash shows only windows from the current monitor"
+msgstr "Panel pokazuje tylko okna z bieżącego monitora"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:654
+msgid "Display the favorites on all monitors"
+msgstr "Wyświetl ulubione na wszystkich monitorach"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:655
+msgid ""
+"Specifies if every panel should display the favorite applications. If false, "
+"the favorite appplications are only displayed on the primary monitor."
+msgstr ""
+"Określa, czy każdy panel powinien wyświetlać ulubione programy. Jeśli nie, "
+"ulubione programy są wyświetlane tylko na głównym monitorze."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:659
+msgid "Customize click behaviour"
+msgstr "Dostosuj zachowanie kliknięcia"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:660
+msgid "Customize action on various mouse events"
+msgstr "Dostosuj działanie w przypadku różnych zdarzeń myszy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:664
+msgid "Minimize on shift+click"
+msgstr "Minimalizuj po naciśnięciu Shift+kliknięcie myszą"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:668
+msgid "Activate only one window"
+msgstr "Aktywuj tylko jedno okno"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:672
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:682
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:687
+msgid "Action when clicking on a running app"
+msgstr "Akcja po kliknięciu uruchomionego programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:673
+msgid ""
+"Set the action that is executed when clicking on the icon of a running "
+"application"
+msgstr ""
+"Ustaw akcję, która zostanie wykonana po kliknięciu ikony uruchomionego "
+"programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:677
+msgid "Action when shift+clicking on a running app"
+msgstr ""
+"Akcja po kliknięciu z wciśniętym klawiszem Shift na uruchomionym programie"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:678
+msgid ""
+"Set the action that is executed when shift+clicking on the icon of a running "
+"application"
+msgstr ""
+"Ustaw akcję wykonywaną po kliknięciu ikony uruchomionego programu z "
+"wciśniętym klawiszem Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:683
+msgid ""
+"Set the action that is executed when middle-clicking on the icon of a "
+"running application"
+msgstr ""
+"Ustaw akcję, która zostanie wykonana po kliknięciu środkowym przyciskiem "
+"myszy ikony uruchomionego programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:688
+msgid ""
+"Set the action that is executed when shift+middle-clicking on the icon of a "
+"running application"
+msgstr ""
+"Ustaw akcję wykonywaną po naciśnięciu Shift+środkowy przycisk myszy na "
+"ikonie uruchomionego programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:692
+msgid "Action when scrolling over the panel"
+msgstr "Akcja podczas przewijania nad panelem"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:693
+msgid "Set the action that is executed when scrolling over the panel"
+msgstr "Ustaw akcję, która zostanie wykonana po najechaniu kursorem na panel"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:716
+msgid "User defined context menu entries"
+msgstr "Wpisy menu kontekstowego zdefiniowane przez użytkownika"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:720
+msgid "Delay between panel mouse scroll events"
+msgstr "Opóźnienie między zdarzeniami przewijania myszką na panelem"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:721
+msgid "Set the minimum delay between panel mouse scroll events"
+msgstr ""
+"Ustaw minimalne opóźnienie między zdarzeniami przewijania nad panelem myszą"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:725
+msgid ""
+"Show the workspace switch head-up when workspace is changed by scrolling on "
+"the panel"
+msgstr ""
+"Wyświetlaj powiadomienie o zmianie obszaru roboczego, gdy obszar jest "
+"zmieniany przez przewijanie nad panelem"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:729
+msgid "Action when scrolling over a running app"
+msgstr "Akcja podczas przewijania kursorem nad uruchomionym programem"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:730
+msgid ""
+"Set the action that is executed when scrolling over a running application"
+msgstr ""
+"Ustaw akcję, która jest wykonywana podczas przewijania kursorem nad "
+"uruchomionym programem"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:734
+msgid "Delay between icon mouse scroll events"
+msgstr "Opóźnienie między zdarzeniami przewijania myszą nad ikoną"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:735
+msgid "Set the minimum delay between icon mouse scroll events"
+msgstr ""
+"Ustaw minimalne opóźnienie między zdarzeniami przewijania myszą nad ikoną"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:739
+msgid "Icon leave preview timeout"
+msgstr "Limit czasu podglądu po opuszczeniu ikony"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:740
+msgid ""
+"Amount of time to leave preview windows open when the mouse has left the "
+"application's icon."
+msgstr ""
+"Czas, przez jaki okna podglądu pozostaną otwarte po opuszczeniu ikony "
+"aplikacji przez kursor myszy."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:744
+msgid "Enter window peeking mode timeout"
+msgstr "Limit czasu wejścia w tryb podglądu okna"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:745
+msgid ""
+"Amount of time of inactivity to enter the window peeking mode when the mouse "
+"has entered a window preview."
+msgstr ""
+"Czas bezczynności potrzebny do przejścia w tryb podglądu okna po najechaniu "
+"kursorem myszy na podgląd okna."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:749
+#: ui/BoxWindowPreviewOptions.ui:466
+msgid "Window peeking mode opacity"
+msgstr "Przezroczystość trybu podglądu okna"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:750
+#: ui/BoxWindowPreviewOptions.ui:467
+msgid ""
+"All windows except for the peeked one have their opacity set to the same "
+"value."
+msgstr ""
+"Wszystkie okna, za wyjątkiem okna głównego, mają tą samą przeźroczystość."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:754
+msgid "Middle click preview to close window"
+msgstr "Zamknięcie podglądu poprzez kliknięcie środkowego przycisku"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:755
+msgid "Middle click on the window preview to close that window"
+msgstr ""
+"Kliknięcie środkowym przyciskiem myszy na podglądzie okna powoduje "
+"zamknięcie tego okna"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:759
+msgid "Window previews use custom opacity"
+msgstr "Podglądy okien używają niestandardowej przezroczystości"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:760
+msgid "Window previews background use a different opacity from the panel"
+msgstr "Tło podglądów okien używa innej przezroczystości niż panel"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:764
+msgid "Window previews background opacity"
+msgstr "Przezroczystość tła podglądów okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:765
+msgid "Window previews use this custom background opacity."
+msgstr "Podglądy okien używają tej niestandardowej przezroczystości tła."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:769
+msgid "Tray font size"
+msgstr "Rozmiar czcionki zasobnika"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:770
+msgid "Set the size of the tray font. (0 for default)"
+msgstr "Ustaw rozmiar czcionki zasobnika. (0 dla domyślnego)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:774
+msgid "Leftbox font size"
+msgstr "Rozmiar czcionki lewego pola"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:775
+msgid "Set the size of the leftBox font. (0 for default)"
+msgstr "Ustaw rozmiar czcionki lewego pola. (0 dla domyślnego)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:779
+msgid "Border radius of panel elements"
+msgstr "Promień zaokrąglenia krawędzi elementów panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:783
+msgid "App icon margin"
+msgstr "Margines ikony programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:784
+msgid "Set the margin for application icons in the embedded dash."
+msgstr "Ustaw margines ikon programów w osadzonym panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:788
+msgid "App icon padding"
+msgstr "Wypełnienie ikon programów"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:789
+msgid "Set the padding for application icons in the embedded dash."
+msgstr "Ustaw odstęp wewnętrzny ikon programów w osadzonym panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:793
+msgid "Tray item padding"
+msgstr "Wypełnienie elementów zasobnika"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:794
+msgid "Set the size of the tray padding. (-1 for default)"
+msgstr "Ustaw odstęp wewnętrzny zasobnika. (-1 dla domyślnego)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:798
+msgid "Leftbox item padding"
+msgstr "Wypełnienie elementów lewego pola"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:799
+msgid "Set the size of the leftBox padding. (-1 for default)"
+msgstr "Ustaw odstęp wewnętrzny lewego pola. (-1 dla domyślnego)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:803
+msgid "Status icon padding"
+msgstr "Wypełnienie ikony stanu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:804
+msgid ""
+"Set the size of the aggregate (status) menu icon padding. (-1 for default)"
+msgstr ""
+"Ustaw odstęp wewnętrzny ikony menu zbiorczego (stanu). (-1 dla domyślnego)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:808
+msgid "Animate running indicator when open/closing/switching applications"
+msgstr ""
+"Animuj wskaźnik uruchomienia podczas otwierania/zamykania/przełączania "
+"programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:812
+msgid "Animate when new window launched"
+msgstr "Animuj przy uruchamianiu nowego okna"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:816
+msgid "Animate app icon on hover"
+msgstr "Animuj ikonę aplikacji po najechaniu kursorem"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:820
+msgid "App icon hover animation type"
+msgstr "Typ animacji ikony programu po najechaniu kursorem"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:824
+msgid ""
+"App icon hover animation curve convexity (1 is linear, more is convex, less "
+"is concave)"
+msgstr ""
+"Wypukłość krzywej animacji najechania kursorem na ikonę programu (1 to "
+"liniowa, więcej to wypukła, mniej to wklęsła)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:828
+msgid "App icon hover animation duration in milliseconds"
+msgstr ""
+"Czas trwania animacji ikony programu po najechaniu kursorem w milisekundach"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:832
+msgid "App icon hover animation extent (maximum number of animated icons)"
+msgstr ""
+"Zasięg animacji ikony programu po najechaniu kursorem (maksymalna liczba "
+"animowanych ikon)"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:836
+msgid "App icon hover animation rotation in degrees"
+msgstr "Obrót ikony programu po najechaniu kursorem w stopniach"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:840
+msgid ""
+"App icon hover animation travel translation in relation to the app icon size"
+msgstr ""
+"Przesunięcie animacji najechania kursorem na ikonę programu w odniesieniu do "
+"rozmiaru ikony programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:844
+msgid "App icon hover animation zoom scale in relation to the app icon size"
+msgstr ""
+"Skala powiększenia animacji najechania kursorem na ikonę programu w "
+"odniesieniu do rozmiaru ikony programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:848
+msgid "Highlight app icon on hover"
+msgstr "Podświetl ikonę programu po najechaniu kursorem"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:852
+msgid "Highlight color"
+msgstr "Kolor podświetlenia"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:856
+msgid "Mouse down highlight color"
+msgstr "Kolor podświetlenia przy naciśnięciu myszy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:860
+msgid "Highlight border radius"
+msgstr "Promień zaokrąglenia obramowania podświetlenia"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:864
+msgid "Integrate items from the gnome appmenu into the right click menu"
+msgstr ""
+"Zintegruj elementy z menu programu GNOME z menu prawego przycisku myszy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:868
+msgid "Display App Details to open Gnome Software from right click menu"
+msgstr ""
+"Wyświetlaj szczegóły programu, aby otworzyć Oprogramowanie GNOME z menu "
+"prawego przycisku myszy"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:872
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:877
+msgid "Keybinding to show the dock and the number overlay."
+msgstr "Skrót klawiszowy do wyświetlenia doku i nakładki z numerami."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:873
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:878
+msgid "Behavior depends on hotkeys-show-dock and hotkeys-overlay."
+msgstr ""
+"Zachowanie zależy od ustawień skrótów klawiszowych \"hotkeys-show-dock\" i "
+"\"hotkeys-overlay\"."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:882
+msgid ""
+"Timeout to hide the panel after showing the overlay using the shortcut, in "
+"seconds"
+msgstr ""
+"Czas oczekiwania na ukrycie panelu po wyświetleniu nakładki za pomocą skrótu "
+"klawiszowego, w sekundach"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:886
+msgid "Timeout to hide the dock, in seconds"
+msgstr "Czas oczekiwania na ukrycie doku, w sekundach"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:887
+msgid "Sets the time duration before the dock is hidden again."
+msgstr "Ustawia czas, po którym dok zostanie ponownie ukryty."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:891
+msgid "Transitivity of the number overlay"
+msgstr "Transaktywność nakładki z numerami"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:892
+msgid "You can choose between NEVER, TEMPORARILY and ALWAYS."
+msgstr "Możesz wybrać pomiędzy NIGDY, TYMCZASOWO i ZAWSZE."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:896
+msgid "Super Hot-Keys"
+msgstr "Skróty klawiszowe z Super"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:897
+msgid "Launch and switch between dash items using Super+(0-9)"
+msgstr ""
+"Uruchamiaj i przełączaj się między elementami panelu za pomocą Super+(0-9)."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:901
+msgid "Prefix to use for hotkeys"
+msgstr "Prefiks do użycia dla skrótów klawiszowych"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:902
+msgid "You can choose between Super or SuperAlt as the prefix for hotkeys."
+msgstr ""
+"Możesz wybrać pomiędzy Super lub Super+Alt jako prefiks dla skrótów "
+"klawiszowych."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:906
+msgid "Show overlay on secondary monitors"
+msgstr "Pokaż nakładkę na dodatkowym monitorze"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:910
+msgid "Show window previews"
+msgstr "Pokaż podglądy okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:911
+msgid ""
+"When multiple instances of the application are available, show their window "
+"previews"
+msgstr ""
+"Gdy dostępnych jest wiele instancji programu, wyświetl ich podglądy okien"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:915
+msgid "Hotkeys number keys"
+msgstr "Klawisze numeryczne skrótów klawiszowych"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:916
+msgid "Which number keys are used for the hotkeys"
+msgstr "Klawisze numeryczne są używane do skrótów klawiszowych"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:920
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1130
+msgid "Keybinding to launch 1st dash app"
+msgstr "Skrót klawiszowy do uruchomienia 1. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:921
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1131
+msgid "Keybinding to launch 1st app."
+msgstr "Skrót klawiszowy do uruchomienia 1. programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:927
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1137
+msgid "Keybinding to launch 2nd dash app"
+msgstr "Skrót klawiszowy do uruchomienia 2. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:928
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1138
+msgid "Keybinding to launch 2nd app."
+msgstr "Skrót klawiszowy do uruchomienia 2. programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:934
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1144
+msgid "Keybinding to launch 3rd dash app"
+msgstr "Skrót klawiszowy do uruchomienia 3 programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:935
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1145
+msgid "Keybinding to launch 3rd app."
+msgstr "Skrót klawiszowy do uruchomienia 3. programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:941
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1151
+msgid "Keybinding to launch 4th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 4. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:942
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1152
+msgid "Keybinding to launch 4th app."
+msgstr "Skrót klawiszowy do uruchomienia 4. programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:948
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1158
+msgid "Keybinding to launch 5th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 5. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:949
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1159
+msgid "Keybinding to launch 5th app."
+msgstr "Skrót klawiszowy do uruchomienia 5. programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:955
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1165
+msgid "Keybinding to launch 6th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 5. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:956
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1166
+msgid "Keybinding to launch 6th app."
+msgstr "Skrót klawiszowy do uruchomienia 6. programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:962
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1172
+msgid "Keybinding to launch 7th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 7. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:963
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1173
+msgid "Keybinding to launch 7th app."
+msgstr "Skrót klawiszowy do uruchomienia 7. programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:969
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1179
+msgid "Keybinding to launch 8th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 8. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:970
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1180
+msgid "Keybinding to launch 8th app."
+msgstr "Skrót klawiszowy do uruchomienia 8. programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:976
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1186
+msgid "Keybinding to launch 9th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 9. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:977
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1187
+msgid "Keybinding to launch 9th app."
+msgstr "Skrót klawiszowy do uruchomienia 9. programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:983
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1193
+msgid "Keybinding to launch 10th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 10. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:984
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1194
+msgid "Keybinding to launch 10th app."
+msgstr "Skrót klawiszowy do uruchomienia 10. programu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:990
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1200
+msgid "Keybinding to trigger 1st dash app with shift behavior"
+msgstr ""
+"Skrót klawiszowy do uruchomienia 1. programu z panelu z zachowaniem klawisza "
+"Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:991
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1201
+msgid "Keybinding to trigger 1st app with shift behavior."
+msgstr ""
+"Skrót klawiszowy do uruchomienia 1. programu z zachowaniem klawisza Shift."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:997
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1207
+msgid "Keybinding to trigger 2nd dash app with shift behavior"
+msgstr ""
+"Skrót klawiszowy do uruchomienia 2. programu z panelu z zachowaniem klawisza "
+"Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:998
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1208
+msgid "Keybinding to trigger 2nd app with shift behavior."
+msgstr ""
+"Skrót klawiszowy do uruchomienia 2. programu z zachowaniem klawisza Shift."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1004
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1214
+msgid "Keybinding to trigger 3rd dash app with shift behavior"
+msgstr ""
+"Skrót klawiszowy do uruchomienia 3. programu z panelu z zachowaniem klawisza "
+"Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1005
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1215
+msgid "Keybinding to trigger 3rd app with shift behavior."
+msgstr ""
+"Skrót klawiszowy do uruchomienia 3. programu z zachowaniem klawisza Shift."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1011
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1221
+msgid "Keybinding to trigger 4th dash app with shift behavior"
+msgstr ""
+"Skrót klawiszowy do uruchomienia 4. programu z panelu z zachowaniem klawisza "
+"Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1012
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1222
+msgid "Keybinding to trigger 4th app with shift behavior."
+msgstr ""
+"Skrót klawiszowy do uruchomienia 4. programu z zachowaniem klawisza Shift."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1018
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1228
+msgid "Keybinding to trigger 5th dash app with shift behavior"
+msgstr ""
+"Skrót klawiszowy do uruchomienia 5. programu z panelu z zachowaniem klawisza "
+"Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1019
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1229
+msgid "Keybinding to trigger 5th app with shift behavior."
+msgstr ""
+"Skrót klawiszowy do uruchomienia 5. programu z zachowaniem klawisza Shift."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1025
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1235
+msgid "Keybinding to trigger 6th dash app with shift behavior"
+msgstr ""
+"Skrót klawiszowy do uruchomienia 6. programu z panelu z zachowaniem klawisza "
+"Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1026
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1236
+msgid "Keybinding to trigger 6th app with shift behavior."
+msgstr ""
+"Skrót klawiszowy do uruchomienia 6. programu z zachowaniem klawisza Shift."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1032
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1242
+msgid "Keybinding to trigger 7th dash app with shift behavior"
+msgstr ""
+"Skrót klawiszowy do uruchomienia 7. programu z panelu z zachowaniem klawisza "
+"Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1033
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1243
+msgid "Keybinding to trigger 7th app with shift behavior."
+msgstr ""
+"Skrót klawiszowy do uruchomienia 7. programu z zachowaniem klawisza Shift."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1039
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1249
+msgid "Keybinding to trigger 8th dash app with shift behavior"
+msgstr ""
+"Skrót klawiszowy do uruchomienia 8. programu z panelu z zachowaniem klawisza "
+"Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1040
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1250
+msgid "Keybinding to trigger 8th app with shift behavior."
+msgstr ""
+"Skrót klawiszowy do uruchomienia 8. programu z zachowaniem klawisza Shift."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1046
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1256
+msgid "Keybinding to trigger 9th dash app with shift behavior"
+msgstr ""
+"Skrót klawiszowy do uruchomienia 9. programu z panelu z zachowaniem klawisza "
+"Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1047
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1257
+msgid "Keybinding to trigger 9th app with shift behavior."
+msgstr ""
+"Skrót klawiszowy do uruchomienia 9. programu z zachowaniem klawisza Shift."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1053
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1263
+msgid "Keybinding to trigger 10th dash app with shift behavior"
+msgstr ""
+"Skrót klawiszowy do uruchomienia 10. programu z panelu z zachowaniem "
+"klawisza Shift"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1054
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1264
+msgid "Keybinding to trigger 10th app with shift behavior."
+msgstr ""
+"Skrót klawiszowy do uruchomienia 10. programu z zachowaniem klawisza Shift."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1060
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1270
+msgid "Keybinding to trigger 1st dash app"
+msgstr "Skrót klawiszowy do uruchomienia 1. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1061
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1271
+msgid "Keybinding to either show or launch the 1st application in the dash."
+msgstr ""
+"Skrót klawiszowy do wyświetlenia lub uruchomienia 1. programu w panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1067
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1277
+msgid "Keybinding to trigger 2nd dash app"
+msgstr "Skrót klawiszowy do uruchomienia 2. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1068
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1278
+msgid "Keybinding to either show or launch the 2nd application in the dash."
+msgstr ""
+"Skrót klawiszowy do wyświetlenia lub uruchomienia 2. programu w panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1074
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1284
+msgid "Keybinding to trigger 3rd dash app"
+msgstr "Skrót klawiszowy do uruchomienia 3. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1075
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1285
+msgid "Keybinding to either show or launch the 3rd application in the dash."
+msgstr ""
+"Skrót klawiszowy do wyświetlenia lub uruchomienia 3. programu w panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1081
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1291
+msgid "Keybinding to trigger 4th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 4. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1082
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1292
+msgid "Keybinding to either show or launch the 4th application in the dash."
+msgstr ""
+"Skrót klawiszowy do wyświetlenia lub uruchomienia 4. programu w panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1088
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1298
+msgid "Keybinding to trigger 5th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 5. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1089
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1299
+msgid "Keybinding to either show or launch the 5th application in the dash."
+msgstr ""
+"Skrót klawiszowy do wyświetlenia lub uruchomienia 5. programu w panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1095
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1305
+msgid "Keybinding to trigger 6th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 6. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1096
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1306
+msgid "Keybinding to either show or launch the 6th application in the dash."
+msgstr ""
+"Skrót klawiszowy do wyświetlenia lub uruchomienia 6. programu w panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1102
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1312
+msgid "Keybinding to trigger 7th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 7. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1103
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1313
+msgid "Keybinding to either show or launch the 7th application in the dash."
+msgstr ""
+"Skrót klawiszowy do wyświetlenia lub uruchomienia 7. programu w panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1109
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1319
+msgid "Keybinding to trigger 8th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 8. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1110
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1320
+msgid "Keybinding to either show or launch the 8th application in the dash."
+msgstr ""
+"Skrót klawiszowy do wyświetlenia lub uruchomienia 8. programu w panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1116
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1326
+msgid "Keybinding to trigger 9th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 9. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1117
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1327
+msgid "Keybinding to either show or launch the 9th application in the dash."
+msgstr ""
+"Skrót klawiszowy do wyświetlenia lub uruchomienia 9. programu w panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1123
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1333
+msgid "Keybinding to trigger 10th dash app"
+msgstr "Skrót klawiszowy do uruchomienia 10. programu z panelu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1124
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1334
+msgid "Keybinding to either show or launch the 10th application in the dash."
+msgstr ""
+"Skrót klawiszowy do wyświetlenia lub uruchomienia 10. programu w panelu."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1340
+msgid "Show progress bar on app icon"
+msgstr "Wyświetlaj pasek postępu na ikonie programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1341
+msgid ""
+"Whether to show progress bar overlay on app icon, for supported applications."
+msgstr ""
+"Wyświetlanie nakładki paska postępu na ikonie programu dla obsługiwanych "
+"programów."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1345
+msgid "Show badge count on app icon"
+msgstr "Pokaż licznik na ikonie programu"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1346
+msgid ""
+"Whether to show badge count overlay on app icon, for supported applications."
+msgstr ""
+"Wyświetlanie nakładki z liczbą plakietki na ikonie programu dla "
+"obsługiwanych programów."
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1350
+msgid "The preferences page name to display"
+msgstr "Nazwa strony preferencji do wyświetlenia"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1354
+msgid "Track if the preferences window is opened"
+msgstr "Śledź, czy okno preferencji jest otwarte"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1358
+msgid "Unix time when the donate icon was hidden"
+msgstr "Czas uniksowy, kiedy ikona darowizny została ukryta"
+
+#: schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml:1362
+msgid "Installed extension version"
+msgstr "Zainstalowana wersja rozszerzenia"
+
+#: src/appIcons.js:1911 src/appIcons.js:1928 ui/BoxMiddleClickOptions.ui:33
+#: ui/BoxMiddleClickOptions.ui:62 ui/BoxMiddleClickOptions.ui:91
+msgid "Quit"
+msgstr "Zakończ"
+
+#: src/appIcons.js:1931
+#, javascript-format
+msgid "Quit %d Window"
+msgid_plural "Quit %d Windows"
+msgstr[0] "Zamknij %d okno"
+msgstr[1] "Zamknij %d okna"
+msgstr[2] "Zamknij %d okien"
+
+#: src/appIcons.js:2253
+msgid "Power options"
+msgstr "Opcje zasilania"
+
+#: src/appIcons.js:2258
+msgid "Event logs"
+msgstr "Dzinnik zdarzeń"
+
+#: src/appIcons.js:2263
+msgid "System"
+msgstr "System"
+
+#: src/appIcons.js:2268
+msgid "Device Management"
+msgstr "Zarządzanie urządzeniami"
+
+#: src/appIcons.js:2273
+msgid "Disk Management"
+msgstr "Zarządzanie dyskami"
+
+msgid "System Monitor"
+msgstr "Monitor procesów"
+
+msgid "Files"
+msgstr "Pliki"
+
+msgid "Settings"
+msgstr "Ustawienia"
+
+#: src/appIcons.js:2304
+msgid "Unlock taskbar"
+msgstr "Odblokuj pasek zadań"
+
+#: src/appIcons.js:2305
+msgid "Lock taskbar"
+msgstr "Zablokuj pasek zadań"
+
+#: src/appIcons.js:2315
+msgid "Gnome Settings"
+msgstr "Ustawienia GNOME"
+
+#: src/appIcons.js:2319
+msgid "Taskbar Settings"
+msgstr "Ustawienia pasek zadań"
+
+#: src/appIcons.js:2326
+msgid "Restore Windows"
+msgstr "Przywróć okna"
+
+#: src/appIcons.js:2327
+msgid "Show Desktop"
+msgstr "Pokaż pulpit"
+
+#: src/extension.js:96
+msgid "Dash to Panel has been updated!"
+msgstr "Panel został zaktualizowany!"
+
+#: src/extension.js:97
+msgid "You are now running version"
+msgstr "Aktualnie używasz wersji"
+
+#: src/extension.js:103
+msgid "See what's new"
+msgstr "Zobacz, co nowego"
+
+#: src/panel.js:213
+msgid "Top Bar"
+msgstr "Górny pasek"
+
+#: src/prefs.js:275
msgid "Show Desktop button height (px)"
-msgstr "Wysokość przycisku , , , "
-msgstr "Składnia: , , , "
-
-#: ui/BoxIntellihideOptions.ui.h:14
+#: ui/BoxIntellihideOptions.ui:143
msgid "e.g. i"
msgstr "np. i"
-#: ui/BoxIntellihideOptions.ui.h:15
+#: ui/BoxIntellihideOptions.ui:152
+msgid "Persist state across restarts"
+msgstr "Zachowaj stan po ponownym uruchomieniu"
+
+#: ui/BoxIntellihideOptions.ui:162
+msgid ""
+"(respects \"Do Not Disturb\" and requires show notification counter "
+"badge option)"
+msgstr ""
+"(uwględnia opcję „Nie przeszkadzać” i wymaga włączenia opcji "
+"wyświetlania licznika powiadomień)"
+
+#: ui/BoxIntellihideOptions.ui:163
+msgid "Reveal and hold the panel on notification"
+msgstr "Odsłoń i przytrzymaj panel przy powiadomieniu"
+
+#: ui/BoxIntellihideOptions.ui:177
msgid "Hide and reveal animation duration (ms)"
-msgstr "Czas trwania animacji ukrywania i odsłaniania (ms)"
+msgstr "Czas trwania animacji ukrywania i odkrywania (ms)"
-#: ui/BoxIntellihideOptions.ui.h:16
+#: ui/BoxIntellihideOptions.ui:191
msgid "Delay before hiding the panel (ms)"
-msgstr "Opóźnienie ukrycia panelu (ms)"
+msgstr "Opóźnienie ukrycia panela (ms)"
-#: ui/BoxIntellihideOptions.ui.h:17
+#: ui/BoxIntellihideOptions.ui:206
msgid "Delay before enabling intellihide on start (ms)"
msgstr "Opóźnienie przed aktywacją inteligentnego ukrywania (ms)"
-#: ui/BoxMiddleClickOptions.ui.h:1
+#: ui/BoxMiddleClickOptions.ui:19
msgid "Shift+Click action"
-msgstr "Kliknięcie lewym przyciskiem + Shift"
+msgstr "Kliknięcie myszą + Shift"
-#: ui/BoxMiddleClickOptions.ui.h:2
+#: ui/BoxMiddleClickOptions.ui:20
msgid ""
"When set to minimize, double clicking minimizes all the windows of the "
"application."
@@ -589,359 +2434,388 @@ msgstr ""
"Wybranie zminimalizowania okna umożliwia minimalizowanie wszystkich okien "
"programu dwukrotnym kliknięciem."
-#: ui/BoxMiddleClickOptions.ui.h:3 ui/SettingsAction.ui.h:8
+#: ui/BoxMiddleClickOptions.ui:25 ui/BoxMiddleClickOptions.ui:54
+#: ui/BoxMiddleClickOptions.ui:83 ui/SettingsAction.ui:40
msgid "Raise windows"
-msgstr "Przywróć okna"
+msgstr "Podnieś okna"
-#: ui/BoxMiddleClickOptions.ui.h:4
+#: ui/BoxMiddleClickOptions.ui:26 ui/BoxMiddleClickOptions.ui:55
+#: ui/BoxMiddleClickOptions.ui:84
msgid "Minimize window"
-msgstr "Zminimalizowanie okna"
+msgstr "Minimalizacja okna"
-#: ui/BoxMiddleClickOptions.ui.h:5 ui/SettingsAction.ui.h:9
+#: ui/BoxMiddleClickOptions.ui:27 ui/BoxMiddleClickOptions.ui:56
+#: ui/BoxMiddleClickOptions.ui:85 ui/SettingsAction.ui:41
msgid "Launch new instance"
-msgstr "Uruchomienie nowego okna"
+msgstr "Uruchomienie nowej instancji"
-#: ui/BoxMiddleClickOptions.ui.h:6 ui/SettingsAction.ui.h:4
+#: ui/BoxMiddleClickOptions.ui:28 ui/BoxMiddleClickOptions.ui:57
+#: ui/BoxMiddleClickOptions.ui:86 ui/SettingsAction.ui:35
msgid "Cycle through windows"
msgstr "Przełączanie między oknami"
-#: ui/BoxMiddleClickOptions.ui.h:7 ui/SettingsAction.ui.h:3
+#: ui/BoxMiddleClickOptions.ui:29 ui/BoxMiddleClickOptions.ui:58
+#: ui/BoxMiddleClickOptions.ui:87 ui/SettingsAction.ui:34
msgid "Cycle windows + minimize"
-msgstr "Przełączanie + zminimalizowanie okien"
+msgstr "Przełączanie + minimalizowanie okien"
-#: ui/BoxMiddleClickOptions.ui.h:8 ui/SettingsAction.ui.h:5
+#: ui/BoxMiddleClickOptions.ui:30 ui/BoxMiddleClickOptions.ui:59
+#: ui/BoxMiddleClickOptions.ui:88 ui/SettingsAction.ui:36
msgid "Toggle single / Preview multiple"
msgstr "Przełącz pojedyncze / Podejrzyj wiele"
-#: ui/BoxMiddleClickOptions.ui.h:9 ui/SettingsAction.ui.h:6
+#: ui/BoxMiddleClickOptions.ui:31 ui/BoxMiddleClickOptions.ui:60
+#: ui/BoxMiddleClickOptions.ui:89 ui/SettingsAction.ui:37
msgid "Toggle single / Cycle multiple"
-msgstr "Przełącz pojedyncze / Podejrzyj wiele"
+msgstr "Przełącz pojedyncze / Przełącz wiele"
-#: ui/BoxMiddleClickOptions.ui.h:11
+#: ui/BoxMiddleClickOptions.ui:32 ui/BoxMiddleClickOptions.ui:61
+#: ui/BoxMiddleClickOptions.ui:90 ui/SettingsAction.ui:38
+msgid "Toggle single / Spread multiple"
+msgstr "Przełącz pojedyncze / Rozłóż wiele"
+
+#: ui/BoxMiddleClickOptions.ui:48
msgid "Middle-Click action"
msgstr "Akcja środkowego przycisku"
-#: ui/BoxMiddleClickOptions.ui.h:12
+#: ui/BoxMiddleClickOptions.ui:49
msgid "Behavior for Middle-Click."
-msgstr "Konfiguruje działanie kliknięcia środkowym przyciskiem."
+msgstr "Zachowanie środkowego przycisku myszy."
-#: ui/BoxMiddleClickOptions.ui.h:13
+#: ui/BoxMiddleClickOptions.ui:77
msgid "Shift+Middle-Click action"
-msgstr "Kliknięcie środkowym przyciskiem + Shift"
+msgstr "Kliknięcie środkowym przyciskiem myszy + Shift"
-#: ui/BoxMiddleClickOptions.ui.h:14
+#: ui/BoxMiddleClickOptions.ui:78
msgid "Behavior for Shift+Middle-Click."
-msgstr "Zachowanie dla Shift+środkowy przycisk"
+msgstr "Zachowanie dla Shift+środkowy przycisk myszy."
-#: ui/BoxOverlayShortcut.ui.h:1
-msgid "Hotkeys prefix"
-msgstr "Prefiks dla skrótów klawiszowych"
-
-#: ui/BoxOverlayShortcut.ui.h:2
+#: ui/BoxOverlayShortcut.ui:23
msgid "Hotkeys will either be Super+Number or Super+Alt+Num"
msgstr "Skrót może być aktywowany jako Super+Cyfra lub Super+Alt+Cyfra"
-#: ui/BoxOverlayShortcut.ui.h:3
+#: ui/BoxOverlayShortcut.ui:24
+msgid "Hotkeys prefix"
+msgstr "Prefiks dla skrótów klawiszowych"
+
+#: ui/BoxOverlayShortcut.ui:29
msgid "Super"
msgstr "Super"
-#: ui/BoxOverlayShortcut.ui.h:4
+#: ui/BoxOverlayShortcut.ui:30
msgid "Super + Alt"
msgstr "Super + Alt"
-#: ui/BoxOverlayShortcut.ui.h:5
-msgid "Number overlay"
-msgstr "Pokazywanie cyfr"
-
-#: ui/BoxOverlayShortcut.ui.h:6
+#: ui/BoxOverlayShortcut.ui:38
msgid ""
"Temporarily show the application numbers over the icons when using the "
"hotkeys."
-msgstr "Podczas używania skrótów klawiszowych wyświetlaj cyfry nad ikonami ."
+msgstr ""
+"Tymczasowo wyświetlaj numery aplikacji nad ikonami podczas korzystania ze "
+"skrótów klawiszowych."
-#: ui/BoxOverlayShortcut.ui.h:7
+#: ui/BoxOverlayShortcut.ui:39
+msgid "Number overlay"
+msgstr "Nakładka liczowa"
+
+#: ui/BoxOverlayShortcut.ui:44
msgid "Never"
msgstr "Nigdy"
-#: ui/BoxOverlayShortcut.ui.h:8
+#: ui/BoxOverlayShortcut.ui:45
msgid "Show temporarily"
-msgstr "Przez chwilę"
+msgstr "Pokaż tymczasowo"
-#: ui/BoxOverlayShortcut.ui.h:9
+#: ui/BoxOverlayShortcut.ui:46
msgid "Always visible"
-msgstr "Zawsze"
+msgstr "Zawsze pokazuj"
-#: ui/BoxOverlayShortcut.ui.h:10
+#: ui/BoxOverlayShortcut.ui:54
msgid "Hide timeout (ms)"
-msgstr "Opóźnienie ukrywania (ms)"
+msgstr "Limit czasu ukrywania (ms)"
-#: ui/BoxOverlayShortcut.ui.h:11
+#: ui/BoxOverlayShortcut.ui:66
msgid "Shortcut to show the overlay for 2 seconds"
-msgstr "Skrót wyświetlający cyfry przez 2 sekundy"
+msgstr "Skrót do wyświetlenia nakładki na 2 sekundy"
-#: ui/BoxOverlayShortcut.ui.h:13
+#: ui/BoxOverlayShortcut.ui:69
msgid "e.g. q"
msgstr "np. q"
-#: ui/BoxOverlayShortcut.ui.h:14
+#: ui/BoxOverlayShortcut.ui:78
+msgid ""
+"On secondary monitors, show the overlay on icons matching the primary monitor"
+msgstr ""
+"Na monitorach dodatkowych wyświetlaj nakładkę na ikonach pasujących do "
+"monitora głównego"
+
+#: ui/BoxOverlayShortcut.ui:79
+msgid "Show the overlay on all monitors"
+msgstr "Wyświetlaj nakładkę na wszystkich monitorach"
+
+#: ui/BoxOverlayShortcut.ui:89
+msgid "Show previews when the application have multiple instances"
+msgstr "Pokaż podgląd, gdy program ma wiele instancji"
+
+#: ui/BoxOverlayShortcut.ui:90
msgid "Show window previews on hotkey"
msgstr "Pokaż podgląd okna po wciśnięciu klawisza skrótu"
-#: ui/BoxOverlayShortcut.ui.h:15
-msgid "Show previews when the application have multiple instances"
-msgstr "Pokaż podgląd, gdy aplikacja ma wiele instancji"
+#: ui/BoxOverlayShortcut.ui:100
+msgid "Select which keyboard number keys are used to activate the hotkeys"
+msgstr ""
+"Wybierz, które klawisze numeryczne klawiatury są używane do aktywacji "
+"skrótów klawiszowych"
-#: ui/BoxOverlayShortcut.ui.h:16
+#: ui/BoxOverlayShortcut.ui:101
msgid "Hotkeys are activated with"
msgstr "Aktywacja skrótów klawiszowych wymaga"
-#: ui/BoxOverlayShortcut.ui.h:17
-msgid "Select which keyboard number keys are used to activate the hotkeys"
-msgstr ""
-"Zaznacz które klawisze cyfr mają być używane do aktywacji skrótów "
-"klawiszowych"
-
-#: ui/BoxOverlayShortcut.ui.h:18
+#: ui/BoxOverlayShortcut.ui:106
msgid "Number row"
msgstr "Rząd cyfr"
-#: ui/BoxOverlayShortcut.ui.h:19
+#: ui/BoxOverlayShortcut.ui:107
msgid "Numeric keypad"
msgstr "Klawiatura numeryczna"
-#: ui/BoxOverlayShortcut.ui.h:20
+#: ui/BoxOverlayShortcut.ui:108
msgid "Both"
-msgstr "Obie"
+msgstr "Oba"
-#: ui/BoxScrollIconOptions.ui.h:1 ui/BoxScrollPanelOptions.ui.h:1
+#: ui/BoxScrollIconOptions.ui:25 ui/BoxScrollPanelOptions.ui:25
msgid "Delay between mouse scroll events (ms)"
-msgstr "Opóźnienie między przewijaniem myszą (ms)"
+msgstr "Opóźnienie między zdarzeniami przewijaniem myszą (ms)"
-#: ui/BoxScrollIconOptions.ui.h:2 ui/BoxScrollPanelOptions.ui.h:2
+#: ui/BoxScrollIconOptions.ui:26 ui/BoxScrollPanelOptions.ui:26
msgid "Use this value to limit the number of captured mouse scroll events."
msgstr "Użyj tą wartość by ograniczyć liczbę przechwyceń przewijania myszą."
-#: ui/BoxScrollPanelOptions.ui.h:3
+#: ui/BoxScrollPanelOptions.ui:42
msgid "Show popup when changing workspace"
-msgstr "Pokaż wyskakujące okno podczas zmiany przestrzeni roboczej"
+msgstr "Pokaż wyskakujące okno podczas zmiany obszaru roboczego"
-#: ui/BoxScrollPanelOptions.ui.h:4
+#: ui/BoxScrollPanelOptions.ui:43
msgid "This affects workspace popup when scrolling on the panel only."
-msgstr "Ma wpływ na wyskakujące okno w przestrzeni roboczej tylko na panelu"
+msgstr "Wpływa na wyskakujące okno w przestrzeni roboczej tylko na panelu."
-#: ui/BoxSecondaryMenuOptions.ui.h:1
+#: ui/BoxSecondaryMenuOptions.ui:19
msgid "Integrate AppMenu items"
msgstr "Zintegruj elementy Menu programów"
-#: ui/BoxSecondaryMenuOptions.ui.h:2
-msgid "Show Details menu item"
-msgstr "Wyświetl szczegóły"
+#: ui/BoxSecondaryMenuOptions.ui:30
+msgid "App Details menu item"
+msgstr "Element menu Wyświetl szczegóły"
-#: ui/BoxShowApplicationsOptions.ui.h:1
+#: ui/BoxSecondaryMenuOptions.ui:31
+msgid "App Details is only available when Gnome Software is installed"
+msgstr ""
+"Opcja Szczegóły aplikacji jest dostępna tylko wtedy, gdy "
+"zainstalowane jest Oprogramowanie GNOME"
+
+#: ui/BoxShowApplicationsOptions.ui:25
msgid "Show Applications icon"
-msgstr "Opcje wyświetlania programów"
+msgstr "Ikona Pokaż programy"
-#: ui/BoxShowApplicationsOptions.ui.h:2
+#: ui/BoxShowApplicationsOptions.ui:60
msgid "Show Applications icon side padding (px)"
msgstr "Wewnętrzny margines przycisku Pokaż programy (px)"
-#: ui/BoxShowApplicationsOptions.ui.h:4
+#: ui/BoxShowApplicationsOptions.ui:73
msgid "Override escape key and return to desktop"
-msgstr "Nadpisz przycisk wyjścia i wróć do pulpitu"
+msgstr "Zastąp przycisk ESC i wróć do pulpitu"
-#: ui/BoxShowDesktopOptions.ui.h:1
-msgid "Override Show Desktop line color"
-msgstr "Nadpisz kolor przycisku Pokaż pulpit"
-
-#: ui/BoxShowDesktopOptions.ui.h:2
+#: ui/BoxShowDesktopOptions.ui:77
msgid "Reveal the desktop when hovering the Show Desktop button"
-msgstr "Pokaż pulpit po najechaniu na przycisk Pokaż pulpit"
+msgstr "Odsłoń pulpit po najechaniu kursorem na przycisk Pokaż pulpit"
-#: ui/BoxShowDesktopOptions.ui.h:3
+#: ui/BoxShowDesktopOptions.ui:90
msgid "Delay before revealing the desktop (ms)"
msgstr "Opóźnienie przed ujawnieniem pulpitu (ms)"
-#: ui/BoxShowDesktopOptions.ui.h:4
+#: ui/BoxShowDesktopOptions.ui:106
msgid "Fade duration (ms)"
-msgstr "Opóźnienie ukrywania (ms)"
+msgstr "Czas trwania zanikania (ms)"
-#: ui/BoxWindowPreviewOptions.ui.h:1
+#: ui/BoxWindowPreviewOptions.ui:89
msgid "Time (ms) before showing"
-msgstr "Opóźnienie (ms) przed pokazaniem (domyślnie 100)"
+msgstr "Opóźnienie (ms) przed pokazaniem"
-#: ui/BoxWindowPreviewOptions.ui.h:2
+#: ui/BoxWindowPreviewOptions.ui:90
msgid "(400 is default)"
msgstr "(Domyślnie 400)"
-#: ui/BoxWindowPreviewOptions.ui.h:3
+#: ui/BoxWindowPreviewOptions.ui:105
msgid "Time (ms) before hiding"
-msgstr "Opóźnienie ukrywania miniatur (domyślnie 100 ms)"
+msgstr "Czas (ms) przed ukryciem"
-#: ui/BoxWindowPreviewOptions.ui.h:4
+#: ui/BoxWindowPreviewOptions.ui:106
msgid "(100 is default)"
msgstr "(Domyślnie 100)"
-#: ui/BoxWindowPreviewOptions.ui.h:5
+#: ui/BoxWindowPreviewOptions.ui:117
msgid "Immediate on application icon click"
-msgstr "Natychmiastowo po kliknięciu na ikonę aplikacji"
+msgstr "Natychmiast po kliknięciu na ikonę programu"
-#: ui/BoxWindowPreviewOptions.ui.h:6
+#: ui/BoxWindowPreviewOptions.ui:138
msgid "Animation time (ms)"
-msgstr "Długość animacji (ms)"
+msgstr "Czas animacji (ms)"
-#: ui/BoxWindowPreviewOptions.ui.h:7
+#: ui/BoxWindowPreviewOptions.ui:159
msgid "Middle click on the preview to close the window"
-msgstr ""
-"Kliknięcie środkowego przycisku myszy na podglądzie zamyka okno programu"
+msgstr "Zamknij okno poprzez kliknięcie przyciskiem myszy na podglądzie"
-#: ui/BoxWindowPreviewOptions.ui.h:8
+#: ui/BoxWindowPreviewOptions.ui:176
msgid "Window previews preferred size (px)"
msgstr "Preferowany rozmiar podglądu okna (px)"
-#: ui/BoxWindowPreviewOptions.ui.h:9
+#: ui/BoxWindowPreviewOptions.ui:192
msgid "Window previews aspect ratio X (width)"
-msgstr "Proporcja szerokości podglądu okna"
+msgstr "Proporcje podglądu okna X (szerokość)"
-#: ui/BoxWindowPreviewOptions.ui.h:10
+#: ui/BoxWindowPreviewOptions.ui:197 ui/BoxWindowPreviewOptions.ui:238
msgid "1"
msgstr "1"
-#: ui/BoxWindowPreviewOptions.ui.h:11
+#: ui/BoxWindowPreviewOptions.ui:198 ui/BoxWindowPreviewOptions.ui:239
msgid "2"
msgstr "2"
-#: ui/BoxWindowPreviewOptions.ui.h:12
+#: ui/BoxWindowPreviewOptions.ui:199 ui/BoxWindowPreviewOptions.ui:240
msgid "3"
msgstr "3"
-#: ui/BoxWindowPreviewOptions.ui.h:13
+#: ui/BoxWindowPreviewOptions.ui:200 ui/BoxWindowPreviewOptions.ui:241
msgid "4"
msgstr "4"
-#: ui/BoxWindowPreviewOptions.ui.h:14
+#: ui/BoxWindowPreviewOptions.ui:201 ui/BoxWindowPreviewOptions.ui:242
+#: ui/BoxWindowPreviewOptions.ui:306
msgid "5"
msgstr "5"
-#: ui/BoxWindowPreviewOptions.ui.h:15
+#: ui/BoxWindowPreviewOptions.ui:202 ui/BoxWindowPreviewOptions.ui:243
msgid "6"
msgstr "6"
-#: ui/BoxWindowPreviewOptions.ui.h:16
+#: ui/BoxWindowPreviewOptions.ui:203 ui/BoxWindowPreviewOptions.ui:244
msgid "7"
msgstr "7"
-#: ui/BoxWindowPreviewOptions.ui.h:17
+#: ui/BoxWindowPreviewOptions.ui:204 ui/BoxWindowPreviewOptions.ui:245
msgid "8"
msgstr "8"
-#: ui/BoxWindowPreviewOptions.ui.h:18
+#: ui/BoxWindowPreviewOptions.ui:205 ui/BoxWindowPreviewOptions.ui:246
msgid "9"
msgstr "9"
-#: ui/BoxWindowPreviewOptions.ui.h:19
+#: ui/BoxWindowPreviewOptions.ui:206 ui/BoxWindowPreviewOptions.ui:247
msgid "10"
msgstr "10"
-#: ui/BoxWindowPreviewOptions.ui.h:20
+#: ui/BoxWindowPreviewOptions.ui:207 ui/BoxWindowPreviewOptions.ui:248
msgid "11"
msgstr "11"
-#: ui/BoxWindowPreviewOptions.ui.h:21
+#: ui/BoxWindowPreviewOptions.ui:208 ui/BoxWindowPreviewOptions.ui:249
msgid "12"
msgstr "12"
-#: ui/BoxWindowPreviewOptions.ui.h:22
+#: ui/BoxWindowPreviewOptions.ui:209 ui/BoxWindowPreviewOptions.ui:250
msgid "13"
msgstr "13"
-#: ui/BoxWindowPreviewOptions.ui.h:23
+#: ui/BoxWindowPreviewOptions.ui:210 ui/BoxWindowPreviewOptions.ui:251
msgid "14"
msgstr "14"
-#: ui/BoxWindowPreviewOptions.ui.h:24
+#: ui/BoxWindowPreviewOptions.ui:211 ui/BoxWindowPreviewOptions.ui:252
msgid "15"
msgstr "15"
-#: ui/BoxWindowPreviewOptions.ui.h:25
+#: ui/BoxWindowPreviewOptions.ui:212 ui/BoxWindowPreviewOptions.ui:253
msgid "16"
msgstr "16"
-#: ui/BoxWindowPreviewOptions.ui.h:26
+#: ui/BoxWindowPreviewOptions.ui:213 ui/BoxWindowPreviewOptions.ui:254
msgid "17"
msgstr "17"
-#: ui/BoxWindowPreviewOptions.ui.h:27
+#: ui/BoxWindowPreviewOptions.ui:214 ui/BoxWindowPreviewOptions.ui:255
msgid "18"
msgstr "18"
-#: ui/BoxWindowPreviewOptions.ui.h:28
+#: ui/BoxWindowPreviewOptions.ui:215 ui/BoxWindowPreviewOptions.ui:256
msgid "19"
msgstr "19"
-#: ui/BoxWindowPreviewOptions.ui.h:29
+#: ui/BoxWindowPreviewOptions.ui:216 ui/BoxWindowPreviewOptions.ui:257
msgid "20"
msgstr "20"
-#: ui/BoxWindowPreviewOptions.ui.h:30
+#: ui/BoxWindowPreviewOptions.ui:217 ui/BoxWindowPreviewOptions.ui:258
msgid "21"
msgstr "21"
-#: ui/BoxWindowPreviewOptions.ui.h:31
+#: ui/BoxWindowPreviewOptions.ui:223 ui/BoxWindowPreviewOptions.ui:264
msgid "Fixed"
msgstr "Stałe"
-#: ui/BoxWindowPreviewOptions.ui.h:32
+#: ui/BoxWindowPreviewOptions.ui:233
msgid "Window previews aspect ratio Y (height)"
-msgstr "Proporcja wysokości podglądu okna"
+msgstr "Proporcje podglądu okna Y (wysokość)"
-#: ui/BoxWindowPreviewOptions.ui.h:33
+#: ui/BoxWindowPreviewOptions.ui:274
msgid "Window previews padding (px)"
-msgstr "Wewnętrzny odstęp w podglądzie okien (px)"
+msgstr "Wypełnienie podglądów okien (px)"
-#: ui/BoxWindowPreviewOptions.ui.h:34
+#: ui/BoxWindowPreviewOptions.ui:296
msgid "Use custom opacity for the previews background"
-msgstr "Własna przeźroczystość dla tła podglądu okna"
+msgstr "Własna przezroczystość dla tła podglądu"
-#: ui/BoxWindowPreviewOptions.ui.h:35
+#: ui/BoxWindowPreviewOptions.ui:297
msgid ""
"If disabled, the previews background have the same opacity as the panel."
msgstr ""
-"Jeśli wyłączone, podgląd okna będzie mieć taką samą przeźroczystość jak panel"
+"Jeśli wyłączone, tło podglądów będzie miało taką samą przezroczystość jak "
+"panel."
-#: ui/BoxWindowPreviewOptions.ui.h:36
+#: ui/BoxWindowPreviewOptions.ui:322
msgid "Close button and header position"
msgstr "Położenie przycisku zamykania i nagłówka"
-#: ui/BoxWindowPreviewOptions.ui.h:39
+#: ui/BoxWindowPreviewOptions.ui:352
msgid "Display window preview headers"
msgstr "Wyświetlaj nagłówek w podglądzie okna"
-#: ui/BoxWindowPreviewOptions.ui.h:40
+#: ui/BoxWindowPreviewOptions.ui:363
msgid "Icon size (px) of the window preview"
-msgstr "Wielkość czcionki etykiet (px) etykiet podglądu"
+msgstr "Rozmiar ikony (px) podglądu okna"
-#: ui/BoxWindowPreviewOptions.ui.h:41
+#: ui/BoxWindowPreviewOptions.ui:364
msgid "If disabled, the previews icon size will be based on headerbar size"
msgstr ""
-"Jeśli wyłączone, podgląd okna będzie mieć taką samą przeźroczystość jak panel"
+"Jeśli wyłączone, rozmiar ikony podglądu będzie oparty na rozmiarze paska "
+"nagłówka"
-#: ui/BoxWindowPreviewOptions.ui.h:42
+#: ui/BoxWindowPreviewOptions.ui:385
msgid "Font size (px) of the preview titles"
-msgstr "Wielkość czcionki etykiet (px) etykiet podglądu"
+msgstr "Wielkość czcionki (px) tytułów podglądu"
-#: ui/BoxWindowPreviewOptions.ui.h:43
+#: ui/BoxWindowPreviewOptions.ui:401
msgid "Font weight of the preview titles"
-msgstr "Grubość czcionki etykiet podglądu"
+msgstr "Grubość czcionki tytułów podglądu"
-#: ui/BoxWindowPreviewOptions.ui.h:49
+#: ui/BoxWindowPreviewOptions.ui:419
msgid "Font color of the preview titles"
-msgstr "Kolor czcionki etykiet podglądu"
+msgstr "Kolor czcionki tytułów podglądu"
-#: ui/BoxWindowPreviewOptions.ui.h:50
+#: ui/BoxWindowPreviewOptions.ui:437
msgid "Enable window peeking"
-msgstr "Podgląd okien otwartych programów"
+msgstr "Włącz podgląd okien"
-#: ui/BoxWindowPreviewOptions.ui.h:51
+#: ui/BoxWindowPreviewOptions.ui:438
msgid ""
"When hovering over a window preview for some time, the window gets "
"distinguished."
@@ -949,71 +2823,67 @@ msgstr ""
"Po najechaniu kursorem na podgląd okna zostanie ono pokazane na tle "
"wszystkich otwartych okien programów."
-#: ui/BoxWindowPreviewOptions.ui.h:52
+#: ui/BoxWindowPreviewOptions.ui:449
msgid "Enter window peeking mode timeout (ms)"
-msgstr "Opóźnienie wyświetlania (ms)"
+msgstr "Limit czasu wejścia w tryb podglądu okna (ms)"
-#: ui/BoxWindowPreviewOptions.ui.h:53
+#: ui/BoxWindowPreviewOptions.ui:450
msgid ""
"Time of inactivity while hovering over a window preview needed to enter the "
"window peeking mode."
msgstr ""
-"Czas opóźnienia, po którym wyświetlony zostanie podgląd okien otwartych "
-"programów."
+"Czas bezczynności podczas najeżdżania kursorem na podgląd okna, potrzebny do "
+"wejścia w tryb podglądu okna."
-#: ui/BoxWindowPreviewOptions.ui.h:54
+#: ui/BoxWindowPreviewOptions.ui:455
msgid "50"
msgstr "50"
-#: ui/BoxWindowPreviewOptions.ui.h:55
-msgid "Window peeking mode opacity"
-msgstr "Przeźroczystość podglądanych okien"
+#: ui/SettingsAbout.ui:8
+msgid "About"
+msgstr "Informacje"
-#: ui/BoxWindowPreviewOptions.ui.h:56
-msgid "All windows except for the peeked one have their opacity set to the same value."
-msgstr "Wszystkie okna, za wyjątkiem okna głównego, mają tą samą przeźroczystość."
-
-#: ui/SettingsAbout.ui.h:1
+#: ui/SettingsAbout.ui:11
msgid "Info"
-msgstr "Info"
+msgstr "O programie"
-#: ui/SettingsAbout.ui.h:2
+#: ui/SettingsAbout.ui:14
msgid "Version"
msgstr "Wersja"
-#: ui/SettingsAbout.ui.h:3
+#: ui/SettingsAbout.ui:22
msgid "Source"
msgstr "Źródło"
-#: ui/SettingsAbout.ui.h:4
+#: ui/SettingsAbout.ui:26
msgid "GitHub"
msgstr "GitHub"
-#: ui/SettingsAbout.ui.h:5
+#: ui/SettingsAbout.ui:37
msgid "Export and Import"
-msgstr "Ustawienia eksportu i importu"
+msgstr "Eksport i import"
-#: ui/SettingsAbout.ui.h:6
-msgid "Export and import settings"
-msgstr "Ustawienia eksportu i importu"
-
-#: ui/SettingsAbout.ui.h:7
+#: ui/SettingsAbout.ui:40
msgid ""
"Use the buttons below to create a settings file from your current "
"preferences that can be imported on a different machine."
msgstr ""
-"Użyj poniższych przycisków, aby utworzyć plik ustawień bieżącychpreferencji, "
-"które można zaimportować na innym komputerze."
+"Użyj poniższych przycisków, aby utworzyć plik ustawień bieżących "
+"preferencji, które można zaimportować na innym komputerze."
-#: ui/SettingsAbout.ui.h:8
+#: ui/SettingsAbout.ui:41
+msgid "Export and import settings"
+msgstr "Ustawienia eksportu i importu"
+
+#: ui/SettingsAbout.ui:56
msgid "Export to file"
msgstr "Eksportuj do pliku"
-#: ui/SettingsAbout.ui.h:9
+#: ui/SettingsAbout.ui:62
msgid "Import from file"
msgstr "Importuj z pliku"
-#: ui/SettingsAbout.ui.h:10
+#: ui/SettingsAbout.ui:77
msgid ""
"This program comes with ABSOLUTELY NO WARRANTY.\n"
"See the GNU General Public License, wersja 2 "
"lub nowsza."
-#: ui/SettingsAction.ui.h:1
+#: ui/SettingsAction.ui:8
+msgid "Action"
+msgstr "Działanie"
+
+#: ui/SettingsAction.ui:11 ui/SettingsAction.ui:15
msgid "Click action"
msgstr "Działanie kliknięcia"
-#: ui/SettingsAction.ui.h:2
+#: ui/SettingsAction.ui:14
msgid "Behaviour when clicking on the icon of a running application."
-msgstr "Reakcja na kliknięcie ikony aktywnego programu."
+msgstr "Zachowanie po kliknięciu ikony uruchomionego programu."
-#: ui/SettingsAction.ui.h:7
+#: ui/SettingsAction.ui:39
msgid "Toggle windows"
msgstr "Przełącz okna"
-#: ui/SettingsAction.ui.h:10
+#: ui/SettingsAction.ui:51
msgid "Scroll action"
-msgstr "Działanie przewijania na ikonie"
+msgstr "Akcja przewijania"
-#: ui/SettingsAction.ui.h:11
-msgid "Scroll panel action"
-msgstr "Działanie przewijania na panelu"
-
-#: ui/SettingsAction.ui.h:12
+#: ui/SettingsAction.ui:54
msgid "Behavior when mouse scrolling over the panel."
-msgstr "Reakcja na przewijanie myszą nad panelem."
+msgstr "Zachowanie przewijania myszą nad panelem."
-#: ui/SettingsAction.ui.h:13
+#: ui/SettingsAction.ui:55
+msgid "Scroll panel action"
+msgstr "Akcja przewijania na panelu"
+
+#: ui/SettingsAction.ui:79 ui/SettingsAction.ui:112
msgid "Do nothing"
msgstr "Nic nie rób"
-#: ui/SettingsAction.ui.h:14
+#: ui/SettingsAction.ui:80
msgid "Switch workspace"
-msgstr "Przełącz ekran roboczy"
+msgstr "Przełącz obszar roboczy"
-#: ui/SettingsAction.ui.h:15
+#: ui/SettingsAction.ui:81 ui/SettingsAction.ui:113
msgid "Cycle windows"
msgstr "Przełącz między oknami"
-#: ui/SettingsAction.ui.h:16
+#: ui/SettingsAction.ui:82
msgid "Change volume"
msgstr "Zmień głośność"
-#: ui/SettingsAction.ui.h:17
-msgid "Scroll icon action"
-msgstr "Działanie przewijania na ikonie"
-
-#: ui/SettingsAction.ui.h:18
+#: ui/SettingsAction.ui:90
msgid "Behavior when mouse scrolling over an application icon."
-msgstr "Reakcja na przewijanie myszą nad ikoną programu."
+msgstr "Zachowanie przewijania myszą nad ikoną programu."
-#: ui/SettingsAction.ui.h:19
+#: ui/SettingsAction.ui:91
+msgid "Scroll icon action"
+msgstr "Akcja przewijania na ikonie"
+
+#: ui/SettingsAction.ui:114
msgid "Same as panel"
-msgstr "Tak jak panel"
+msgstr "Tak jak dla panela"
-#: ui/SettingsAction.ui.h:20
+#: ui/SettingsAction.ui:124
msgid "Hotkey overlay"
-msgstr "Pokazywanie cyfr"
+msgstr "Nakładka skrótów klawiszowych"
-#: ui/SettingsAction.ui.h:21
-msgid "Use hotkeys to activate apps"
-msgstr "Skróty klawiszowe uruchamiania programów"
-
-#: ui/SettingsAction.ui.h:22
+#: ui/SettingsAction.ui:127
msgid ""
"Enable Super+(0-9) as shortcuts to activate apps. It can also be used "
"together with Shift and Ctrl."
msgstr ""
-"Konfigurowanie skrótów uruchamiania programów\n"
-"Super+(0-9) - możliwe użycie razem z Shift i Ctrl."
+"Włącz Super+(0-9) jako skróty do aktywacji programu. Można go również używać "
+"w połączeniu z Shift i Ctrl."
-#: ui/SettingsBehavior.ui.h:1
+#: ui/SettingsAction.ui:128
+msgid "Use hotkeys to activate apps"
+msgstr "Skróty klawiszowe uruchamiania programów"
+
+#: ui/SettingsAction.ui:154
+msgid "Application icons context menu"
+msgstr "Menu kontekstowe ikon programów"
+
+#: ui/SettingsAction.ui:157
+msgid "(right-click menu)"
+msgstr "(menu prawego przycisku myszy)"
+
+#: ui/SettingsAction.ui:158
+msgid "Secondary menu"
+msgstr "Menu kontekstowe"
+
+#: ui/SettingsAction.ui:179
+msgid "Panel context menu entries"
+msgstr "Wpisy menu kontekstowego panelu"
+
+#: ui/SettingsAction.ui:190
+msgid "Add entry"
+msgstr "Dodaj wpis"
+
+#: ui/SettingsBehavior.ui:5
+msgid "Behavior"
+msgstr "Zachowanie"
+
+#: ui/SettingsBehavior.ui:11
msgid "Applications"
-msgstr "Tryb listy (nie scalaj ikon)"
+msgstr "Aplikacje"
-#: ui/SettingsBehavior.ui.h:2
+#: ui/SettingsBehavior.ui:15
msgid "Show favorite applications"
msgstr "Pokaż ulubione programy"
-#: ui/SettingsBehavior.ui.h:3
+#: ui/SettingsBehavior.ui:26
msgid "Show favorite applications on secondary panels"
-msgstr "Pokaż ulubione programy"
+msgstr "Pokaż ulubione programy na dodatkowym panelu"
-#: ui/SettingsBehavior.ui.h:4
+#: ui/SettingsBehavior.ui:37
msgid "Show running applications"
msgstr "Pokaż uruchomione programy"
-#: ui/SettingsBehavior.ui.h:5
-msgid "Show AppMenu button"
-msgstr "Pokaż przycisk Menu programu"
-
-#: ui/SettingsBehavior.ui.h:6
+#: ui/SettingsBehavior.ui:48
msgid "Ungroup applications"
-msgstr "Tryb listy (nie scalaj ikon)"
+msgstr "Rozgrupuj programy"
-#: ui/SettingsBehavior.ui.h:7
+#: ui/SettingsBehavior.ui:73
msgid "Show notification counter badge"
msgstr "Pokaż licznik powiadomień"
-#: ui/SettingsBehavior.ui.h:8
+#: ui/SettingsBehavior.ui:90
+msgid "Hover"
+msgstr "Najechanie kursorem"
+
+#: ui/SettingsBehavior.ui:94
msgid "Show window previews on hover"
msgstr "Pokaż podgląd okna po najechaniu myszą"
-#: ui/SettingsBehavior.ui.h:9
+#: ui/SettingsBehavior.ui:119
msgid "Show tooltip on hover"
-msgstr "Pokaż szczegóły po najechaniu myszą"
+msgstr "Pokaż etykietkę po najechaniu kursorem"
-#: ui/SettingsBehavior.ui.h:10
+#: ui/SettingsBehavior.ui:134
msgid "Isolate"
-msgstr "Niezależne obszary robocze"
+msgstr "Niezależne"
-#: ui/SettingsBehavior.ui.h:11
+#: ui/SettingsBehavior.ui:138
msgid "Isolate Workspaces"
msgstr "Niezależne obszary robocze"
-#: ui/SettingsBehavior.ui.h:12
+#: ui/SettingsBehavior.ui:149
msgid "Isolate monitors"
-msgstr "Niezależne obszary robocze"
+msgstr "Niezależne ekrany"
-#: ui/SettingsBehavior.ui.h:13
+#: ui/SettingsBehavior.ui:164
msgid "Overview"
msgstr "Przegląd"
-#: ui/SettingsBehavior.ui.h:14
+#: ui/SettingsBehavior.ui:168
msgid "Click empty space to close overview"
-msgstr "Kliknij na pustą przestrzeń, aby zamknąć podgląd"
+msgstr "Kliknij na pustą przestrzeń, aby zamknąć przegląd"
-#: ui/SettingsBehavior.ui.h:15
+#: ui/SettingsBehavior.ui:179
msgid "Disable show overview on startup"
-msgstr "Wyłącz pokazywanie podglądu przy uruchomieniu"
+msgstr "Wyłącz pokazywanie przeglądu przy uruchomieniu"
-#: ui/SettingsFineTune.ui.h:1
+#: ui/SettingsFineTune.ui:38
+msgid "Fine-Tune"
+msgstr "Dostrajanie"
+
+#: ui/SettingsFineTune.ui:41
msgid "Font size"
msgstr "Rozmiar czcionki"
-#: ui/SettingsFineTune.ui.h:2
-msgid "Tray Font Size"
-msgstr "Rozmiar czcionki zasobnika"
-
-#: ui/SettingsFineTune.ui.h:3
+#: ui/SettingsFineTune.ui:44 ui/SettingsFineTune.ui:60
msgid "(0 = theme default)"
msgstr "(0 - domyślne motywu)"
-#: ui/SettingsFineTune.ui.h:4
+#: ui/SettingsFineTune.ui:45
+msgid "Tray Font Size"
+msgstr "Rozmiar czcionki zasobnika"
+
+#: ui/SettingsFineTune.ui:61
msgid "LeftBox Font Size"
-msgstr ""
-"Rozmiar czcionki lewej strony panelu\n"
-"(0 - domyślne motywu)"
+msgstr "Rozmiar czcionki lewego pola"
-#: ui/SettingsFineTune.ui.h:5
+#: ui/SettingsFineTune.ui:78
msgid "Padding"
-msgstr "Odstęp"
+msgstr "Wypełnienie"
-#: ui/SettingsFineTune.ui.h:6
-msgid "Tray Item Padding"
-msgstr "Odstęp elementów zasobnika"
-
-#: ui/SettingsFineTune.ui.h:7
+#: ui/SettingsFineTune.ui:81 ui/SettingsFineTune.ui:97
+#: ui/SettingsFineTune.ui:113
msgid "(-1 = theme default)"
msgstr "(-1 - domyślne motywu)"
-#: ui/SettingsFineTune.ui.h:8
+#: ui/SettingsFineTune.ui:82
+msgid "Tray Item Padding"
+msgstr "Wypełnienie elementów zasobnika"
+
+#: ui/SettingsFineTune.ui:98
msgid "Status Icon Padding"
-msgstr "Odstęp ikon stanu"
+msgstr "Wypełnienie ikony stanu"
-#: ui/SettingsFineTune.ui.h:9
+#: ui/SettingsFineTune.ui:114
msgid "LeftBox Padding"
-msgstr "Do lewej"
+msgstr "Wypełnienie lewego pola"
-#: ui/SettingsFineTune.ui.h:10
+#: ui/SettingsFineTune.ui:131
msgid "Animate"
-msgstr "Animacja"
+msgstr "Animuj"
-#: ui/SettingsFineTune.ui.h:11
+#: ui/SettingsFineTune.ui:134
msgid "Animate switching applications"
msgstr "Animuj przełączenie programów"
-#: ui/SettingsFineTune.ui.h:12
+#: ui/SettingsFineTune.ui:144
msgid "Animate launching new windows"
msgstr "Animuj uruchamianie nowych programów"
-#: ui/SettingsFineTune.ui.h:13
+#: ui/SettingsFineTune.ui:156
msgid "Gnome functionality"
-msgstr "Funkcja Gnome"
+msgstr "Funkcjonalność GNOME"
-#: ui/SettingsFineTune.ui.h:14
-msgid "Keep original gnome-shell dash"
-msgstr "Zachowaj oryginalny panel (podgląd)"
-
-#: ui/SettingsFineTune.ui.h:15
+#: ui/SettingsFineTune.ui:159
msgid "(overview)"
msgstr "(przegląd)"
-#: ui/SettingsFineTune.ui.h:16
+#: ui/SettingsFineTune.ui:160
+msgid "Keep original gnome-shell dash"
+msgstr "Zachowaj oryginalny panel powłoki GNOME"
+
+#: ui/SettingsFineTune.ui:170
msgid "Keep original gnome-shell top panel"
-msgstr "Zachowaj oryginalny panel (podgląd)"
+msgstr "Zachowaj oryginalny górny panel powłoki GNOME"
-#: ui/SettingsFineTune.ui.h:17
-msgid "Activate panel menu buttons on click only"
-msgstr ""
-"Aktywuj przyciski menu panelu (np. menu kalendarza) tylko po kliknięciu"
-
-#: ui/SettingsFineTune.ui.h:18
+#: ui/SettingsFineTune.ui:180
msgid "(e.g. date menu)"
msgstr "(np. menu daty)"
-#: ui/SettingsFineTune.ui.h:19
+#: ui/SettingsFineTune.ui:181
+msgid "Activate panel menu buttons on click only"
+msgstr "Aktywacja przycisków menu panela tylko po kliknięciu"
+
+#: ui/SettingsFineTune.ui:191
msgid "Force Activities hot corner on primary monitor"
-msgstr "Wymuś Aktywności gorącego rogu na głównym monitorze"
+msgstr "Wymuszaj aktywność gorącego rogu na głównym monitorze"
-#: ui/SettingsFineTune.ui.h:20
-msgid "App icon secondary menu"
-msgstr "Menu kontekstowe programu (prawy przycisk myszy)"
+#: ui/SettingsPosition.ui:19
+msgid "Position"
+msgstr "Pozycja"
-#: ui/SettingsFineTune.ui.h:21
-msgid "(right-click menu)"
-msgstr "(prawy przycisk myszy)"
-
-#: ui/SettingsPosition.ui.h:1
+#: ui/SettingsPosition.ui:22
msgid "Panel"
msgstr "Panel"
-#: ui/SettingsPosition.ui.h:2
+#: ui/SettingsPosition.ui:25
msgid "Display the main panel on"
-msgstr "Wyświetl główny panel na"
+msgstr "Wyświetlaj główny panel na"
-#: ui/SettingsPosition.ui.h:3
-msgid "Display panels on all monitors"
-msgstr "Wyświetl panel na wszystkich monitorach"
-
-#: ui/SettingsPosition.ui.h:4
-msgid "Panel Intellihide"
-msgstr "Inteligentne ukrywanie panelu"
-
-#: ui/SettingsPosition.ui.h:5
+#: ui/SettingsPosition.ui:49
msgid "Hide and reveal the panel according to preferences"
msgstr "Ukryj i odsłoń panel według preferencji"
-#: ui/SettingsPosition.ui.h:6
+#: ui/SettingsPosition.ui:50
+msgid "Panel Intellihide"
+msgstr "Inteligentne ukrywanie panelu"
+
+#: ui/SettingsPosition.ui:76
msgid "Order and Position on monitors"
msgstr "Kolejność i pozycja na monitorach"
-#: ui/SettingsPosition.ui.h:7
+#: ui/SettingsPosition.ui:79
msgid "Monitor"
msgstr "Monitor"
-#: ui/SettingsPosition.ui.h:8
+#: ui/SettingsPosition.ui:90
msgid "Apply changes to all monitors"
msgstr "Zastosuj zmiany na wszyskich monitorach"
-#: ui/SettingsPosition.ui.h:9
+#: ui/SettingsPosition.ui:111
msgid "Panel screen position"
msgstr "Położenie panelu na ekranie"
-#: ui/SettingsPosition.ui.h:14
-msgid "Panel thickness"
-msgstr "Inteligentne ukrywanie panelu"
-
-#: ui/SettingsPosition.ui.h:15
+#: ui/SettingsPosition.ui:152
msgid "(default is 48)"
-msgstr "(domyślnie 48)"
+msgstr "(Domyślnie 48)"
-#: ui/SettingsPosition.ui.h:17
-#, no-c-format
-msgid "Panel length (%)"
-msgstr "Długość panela (%)"
+#: ui/SettingsPosition.ui:153
+msgid "Panel thickness"
+msgstr "Grubość panela"
-#: ui/SettingsPosition.ui.h:18
+#: ui/SettingsPosition.ui:168
msgid "(default is 100)"
-msgstr "(domyślnie 100)"
+msgstr "(Domyślnie 100)"
-#: ui/SettingsPosition.ui.h:19
+#: ui/SettingsPosition.ui:169
+msgid "Panel length"
+msgstr "Długość panelu"
+
+#: ui/SettingsPosition.ui:174
+msgid "Dynamic"
+msgstr "Dynamiczna"
+
+#: ui/SettingsPosition.ui:192
msgid "Anchor"
msgstr "Zakotwiczenie"
-#: ui/SettingsPosition.ui.h:23
+#: ui/SettingsPosition.ui:211
msgid "Taskbar Display"
msgstr "Wyświetlanie paska zadań"
-#: ui/SettingsStyle.ui.h:1
+#: ui/SettingsStyle.ui:59
+msgid "Style"
+msgstr "Wygląd"
+
+#: ui/SettingsStyle.ui:62
+msgid "Global style"
+msgstr "Styl globalny"
+
+#: ui/SettingsStyle.ui:65
+msgid "Border radius"
+msgstr "Promień zaokrąglenia krawędzi"
+
+#: ui/SettingsStyle.ui:82
msgid "AppIcon style"
-msgstr "Styl ikon aplikacji"
+msgstr "Styl ikon programu"
-#: ui/SettingsStyle.ui.h:2
-msgid "App Icon Margin"
-msgstr "Odstęp między ikonami"
-
-#: ui/SettingsStyle.ui.h:3
+#: ui/SettingsStyle.ui:85
msgid "(default is 8)"
-msgstr "(domyślnie 8)"
+msgstr "(Domyślnie 8)"
-#: ui/SettingsStyle.ui.h:4
-msgid "App Icon Padding"
-msgstr "Wypełnienie ikony aplikacji"
+#: ui/SettingsStyle.ui:86
+msgid "App Icon Margin"
+msgstr "Margines ikony programu"
-#: ui/SettingsStyle.ui.h:5
+#: ui/SettingsStyle.ui:101
msgid "(default is 4)"
-msgstr "(domyślnie 4)"
+msgstr "(Domyślnie 4)"
-#: ui/SettingsStyle.ui.h:6
+#: ui/SettingsStyle.ui:102
+msgid "App Icon Padding"
+msgstr "Wypełnienie ikony programów"
+
+#: ui/SettingsStyle.ui:117
msgid "Animate hovering app icons"
-msgstr "Animuj przełączenie programów"
+msgstr "Animuj ikony aplikacji po najechaniu kursorem"
-#: ui/SettingsStyle.ui.h:7
+#: ui/SettingsStyle.ui:141
+msgid "Highlight hovering app icons"
+msgstr "Podświetl ikony aplikacji po najechaniu kursorem"
+
+#: ui/SettingsStyle.ui:165
+msgid "Icon style"
+msgstr "Styl ikony"
+
+#: ui/SettingsStyle.ui:170
+msgid "Normal"
+msgstr "Normalna"
+
+#: ui/SettingsStyle.ui:171
+msgid "Symbolic"
+msgstr "Symboliczna"
+
+#: ui/SettingsStyle.ui:172
+msgid "Grayscale"
+msgstr "Skala szarości"
+
+#: ui/SettingsStyle.ui:182
msgid "Running indicator"
-msgstr "Pozycja wskaźnika aktywnych okien"
+msgstr "Wskaźnik uruchomienia"
-#: ui/SettingsStyle.ui.h:8
+#: ui/SettingsStyle.ui:185
msgid "Running indicator position"
-msgstr "Pozycja wskaźnika aktywnych okien"
+msgstr "Pozycja wskaźnika uruchomienia"
-#: ui/SettingsStyle.ui.h:13
+#: ui/SettingsStyle.ui:221
msgid "Running indicator style (Focused app)"
-msgstr "Wygląd wskaźnika (okno na pierwszym planie)"
+msgstr "Wygląd wskaźnika uruchomienia (okno na pierwszym planie)"
-#: ui/SettingsStyle.ui.h:14
+#: ui/SettingsStyle.ui:239 ui/SettingsStyle.ui:258
msgid "Dots"
msgstr "Kropki"
-#: ui/SettingsStyle.ui.h:15
+#: ui/SettingsStyle.ui:240 ui/SettingsStyle.ui:259
msgid "Squares"
msgstr "Kwadraty"
-#: ui/SettingsStyle.ui.h:16
+#: ui/SettingsStyle.ui:241 ui/SettingsStyle.ui:260
msgid "Dashes"
msgstr "Kreski"
-#: ui/SettingsStyle.ui.h:17
+#: ui/SettingsStyle.ui:242 ui/SettingsStyle.ui:261
msgid "Segmented"
msgstr "Segmenty"
-#: ui/SettingsStyle.ui.h:18
+#: ui/SettingsStyle.ui:243 ui/SettingsStyle.ui:262
msgid "Solid"
msgstr "Ciągły"
-#: ui/SettingsStyle.ui.h:19
+#: ui/SettingsStyle.ui:244 ui/SettingsStyle.ui:263
msgid "Ciliora"
msgstr "Rzęski"
-#: ui/SettingsStyle.ui.h:20
+#: ui/SettingsStyle.ui:245 ui/SettingsStyle.ui:264
msgid "Metro"
msgstr "Metro"
-#: ui/SettingsStyle.ui.h:21
+#: ui/SettingsStyle.ui:253
msgid "Running indicator style (Unfocused apps)"
-msgstr "Wygląd wskaźnika (okno na drugim planie)"
+msgstr "Wygląd wskaźnika uruchomienia (okno na drugim planie)"
-#: ui/SettingsStyle.ui.h:22
+#: ui/SettingsStyle.ui:274
msgid "Panel style"
-msgstr "Inteligentne ukrywanie panelu"
+msgstr "Styl panelu"
-#: ui/SettingsStyle.ui.h:23
+#: ui/SettingsStyle.ui:277 ui/SettingsStyle.ui:293 ui/SettingsStyle.ui:309
+#: ui/SettingsStyle.ui:325
+msgid "(default is 0)"
+msgstr "(Domyślnie 0)"
+
+#: ui/SettingsStyle.ui:278
+msgid "Side margins"
+msgstr "Marginesy boczne"
+
+#: ui/SettingsStyle.ui:294
+msgid "Top and bottom margins"
+msgstr "Marginesy górne i dolne"
+
+#: ui/SettingsStyle.ui:310
+msgid "Side padding"
+msgstr "Wypełnienie boczne"
+
+#: ui/SettingsStyle.ui:326
+msgid "Top and bottom padding"
+msgstr "Wypełnienie górne i dolne"
+
+#: ui/SettingsStyle.ui:345
msgid "Override panel theme background color"
-msgstr "Zastąp kolor panelu "
+msgstr "Zastąp kolor tła panelu"
-#: ui/SettingsStyle.ui.h:24
+#: ui/SettingsStyle.ui:360
msgid "Override panel theme background opacity"
-msgstr "Zastąp przeźroczystość panelu"
+msgstr "Zastąp przeźroczystość tła panelu"
-#: ui/SettingsStyle.ui.h:26
-#, no-c-format
+#: ui/SettingsStyle.ui:370
msgid "Panel background opacity (%)"
-msgstr "Przeźroczystość panelu (%)"
+msgstr "Przeźroczystość tła panelu (%)"
-#: ui/SettingsStyle.ui.h:28
-msgid "Dynamic background opacity"
-msgstr "Dynamiczna przeźroczystość"
-
-#: ui/SettingsStyle.ui.h:29
+#: ui/SettingsStyle.ui:382
msgid "Change opacity when a window gets close to the panel"
-msgstr "Zmiana przeźroczystości w kontakcie z oknem"
+msgstr "Zmień przezroczystość, gdy okno zbliży się do panelu"
-#: ui/SettingsStyle.ui.h:30
+#: ui/SettingsStyle.ui:383
+msgid "Dynamic background opacity"
+msgstr "Dynamiczna przezroczystość tła"
+
+#: ui/SettingsStyle.ui:411
msgid "Override panel theme gradient"
-msgstr "Zastąp kolor panelu gradientem "
+msgstr "Zastąp kolor panelu gradientem"
-#: ui/SettingsStyle.ui.h:32
-#, no-c-format
+#: ui/SettingsStyle.ui:421
msgid "Gradient top color and opacity (%)"
msgstr "Gradient górnego koloru i przeźroczystość (%)"
-#: ui/SettingsStyle.ui.h:34
-#, no-c-format
+#: ui/SettingsStyle.ui:439
msgid "Gradient bottom color and opacity (%)"
msgstr "Gradient dolnego koloru i przeźroczystość (%)"
@@ -1422,218 +3367,5 @@ msgstr "Pokaż ikony na pulpicie"
msgid "Show Desktop button padding (px)"
msgstr "Pokaż margines wewnętrzny przycisków pulpitu (px)"
-msgid "Floating rounded theme"
-msgstr "Pływający, zaokrąglony motyw"
-
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Izoluj obszary robocze i monitory w ustawieniach Przełączanie programów"
-
-#~ msgid "Top, with plugin icons collapsed to bottom"
-#~ msgstr "Góra, ikony wtyczek wyrównane do prawej"
-
-#~ msgid "Left, with plugin icons collapsed to right"
-#~ msgstr "Lewa, ikony wtyczek wyrównane do prawej"
-
-#~ msgid "Top, with fixed center plugin icons"
-#~ msgstr "Góra, ze stałym wyśrodkowaniem ikon wtyczek"
-
-#~ msgid "Left, with fixed center plugin icons"
-#~ msgstr "Lewa, ze stałym wyśrodkowaniem ikon wtyczek"
-
-#~ msgid "Top, with floating center plugin icons"
-#~ msgstr "Góra, ze swobodnym wyśrodkowaniem ikon wtyczek"
-
-#~ msgid "Left, with floating center plugin icons"
-#~ msgstr "Lewa, ze swobodnym wyśrodkowaniem ikon wtyczek"
-
-#~ msgid "Center, fixed in middle of monitor"
-#~ msgstr "Środek, ze stałym wyśrodkowaniem na monitorze"
-
-#~ msgid "Center, floating between top and bottom elements"
-#~ msgstr "Środek, z elementami swobodnymi między górą a dołem"
-
-#~ msgid "Center, floating between left and right elements"
-#~ msgstr "Środek, z elementami swobodnymi między lewą a prawą stroną"
-
-#~ msgid "Top of plugin icons"
-#~ msgstr "Górna strona ikon wtyczek"
-
-#~ msgid "Left of plugin icons"
-#~ msgstr "Lewa strona ikon wtyczek"
-
-#~ msgid "Bottom of plugin icons"
-#~ msgstr "Dolna strona ikon wtyczek"
-
-#~ msgid "Right of plugin icons"
-#~ msgstr "Prawa strona ikon wtyczek"
-
-#~ msgid "Top of system indicators"
-#~ msgstr "Górna strona menu systemowego"
-
-#~ msgid "Left of system indicators"
-#~ msgstr "Lewa strona menu systemowego"
-
-#~ msgid "Bottom of system indicators"
-#~ msgstr "Dolna strona menu systemowego"
-
-#~ msgid "Right of system indicators"
-#~ msgstr "Prawa strona menu systemowego"
-
-#~ msgid "Left of taskbar"
-#~ msgstr "Lewa strona paska zadań"
-
-#~ msgid "Bottom of taskbar"
-#~ msgstr "Dolna strona paska zadań"
-
-#~ msgid "Right of taskbar"
-#~ msgstr "Prawa strona paska zadań"
-
-#~ msgid "Show Details"
-#~ msgstr "Pokaż szczegóły"
-
-#~ msgid "New Window"
-#~ msgstr "Nowe okno"
-
-#, javascript-format
-#~ msgid "Version %s (%s) is available"
-#~ msgstr "Wersja %s (%s) jest dostępna"
-
-#~ msgid "Details"
-#~ msgstr "Szczegóły"
-
-#~ msgid "Update"
-#~ msgstr "Aktualizacja"
-
-#~ msgid "Already up to date"
-#~ msgstr "Brak nowszej wersji"
-
-#~ msgid "Update successful, please log out/in"
-#~ msgstr "Aktualizacja zakończona pomyślnie, zaloguj się ponownie"
-
-#~ msgid "Log out"
-#~ msgstr "Wyloguj"
-
-#~ msgid "Update successful, please restart GNOME Shell"
-#~ msgstr "Aktualizacja zakończona pomyślnie, prosimy zrestartować powłokę GNOME"
-
-#~ msgid "Restart GNOME Shell"
-#~ msgstr "Zrestartuj powłokę GNOME"
-
-#~ msgid "Restarting GNOME Shell..."
-#~ msgstr "Restartowanie powłoki GNOME..."
-
-#~ msgid "Error: "
-#~ msgstr "Błąd: "
-
-#~ msgid "Display favorite applications on all monitors"
-#~ msgstr "Ulubione programy na wszystkich monitorach"
-
-#~ msgid "Display the clock on all monitors"
-#~ msgstr "Zegar na wszystkich monitorach"
-
-#~ msgid "Display the status menu on all monitors"
-#~ msgstr "Menu systemowe na wszystkich monitorach"
-
-#~ msgid "Current Show Applications icon"
-#~ msgstr "Aktualna ikona przycisku Pokaż programy"
-
-#~ msgid "Select a Show Applications image icon"
-#~ msgstr "Wybierz ikonę przycisku Pokaż programy"
-
-#~ msgid "Custom Show Applications image icon"
-#~ msgstr "Wybierz własną ikonę przycisku Pokaż programy"
-
-#~ msgid "Taskbar position"
-#~ msgstr "Położenie paska zadań"
-
-#~ msgid "Clock location"
-#~ msgstr "Położenie zegara"
-
-#~ msgid "Style"
-#~ msgstr "Wygląd"
-
-#~ msgid "Show Applications icon"
-#~ msgstr "Pokaż ikonę Programy"
-
-#~ msgid "Animate Show Applications."
-#~ msgstr "Animuj pokazanie programów."
-
-#~ msgid "Top Bar > Show App Menu must be enabled in Tweak Tool"
-#~ msgstr "Górny pasek > Menu programu - musi być włączone w Dostrajanie"
-
-#~ msgid "Behavior"
-#~ msgstr "Reakcja"
-
-#~ msgid "Action"
-#~ msgstr "Działanie"
-
-#~ msgid "Fine-Tune"
-#~ msgstr "Dostrajanie"
-
-#~ msgid "Position"
-#~ msgstr "Pozycja"
-
-#~ msgid "Icon style"
-#~ msgstr "Styl ikony"
-
-#~ msgid "Normal"
-#~ msgstr "Normalna"
-
-#~ msgid "Symbolic"
-#~ msgstr "Symboliczna"
-
-#~ msgid ""
-#~ "This allows you to update the extension directly from the GitHub "
-#~ "repository."
-#~ msgstr ""
-#~ "Ta opcja pozwala ci na zaktualizowanie wtyczki bezpośrednio z "
-#~ "repozytorium GitHub."
-
-#~ msgid "Updates"
-#~ msgstr "Aktualizacje"
-
-#~ msgid "Periodically check for updates"
-#~ msgstr "Sprawdzaj regularnie dostępność aktualizacji"
-
-#~ msgid "Check now"
-#~ msgstr "Sprawdź teraz"
-
-#~ msgid ""
-#~ "Be aware, these official Dash to "
-#~ "Panel releases might not be reviewed yet on extensions.gnome.org! "
-#~ "Read more"
-#~ msgstr ""
-#~ "Bądź świadom, że te oficjalne "
-#~ "wydania Dash to Panel mogły jeszcze nie przejść weryfikacji na extensions."
-#~ "gnome.org! Więcej "
-#~ "informacji"
-
-#~ msgid "About"
-#~ msgstr "Informacje"
-
-#~ msgid "Highlight color"
-#~ msgstr "Kolor podświetlenia"
-
-#~ msgid "Preview timeout on icon leave (ms)"
-#~ msgstr "Opóźnienie wygaszenia podglądu po opuszczeniu ikony (ms)"
-
-#~ msgid ""
-#~ "If set too low, the window preview of running applications may seem to "
-#~ "close too quickly when trying to enter the popup. If set too high, the "
-#~ "preview may linger too long when moving to an adjacent icon."
-#~ msgstr ""
-#~ "Ustawienie zbyt małej wartości może spowodować, że pogląd okien może "
-#~ "zamykać się zbyt szybko, natomiast za duża wartość spowoduje długi czas "
-#~ "wyświetlania podglądu po przejściu do sąsiedniej ikony."
-
-#~ msgid "Middle click to close window"
-#~ msgstr "Zamknięcie okna poprzez kliknięcie środkowego przycisku"
-
-#~ msgid "Width of the window previews (px)"
-#~ msgstr "Szerokość miniatury (px)"
-
-#~ msgid "Height of the window previews (px)"
-#~ msgstr "Wysokość miniatury (px)"
-
-#~ msgid "Padding of the window previews (px)"
-#~ msgstr "Odstęp między miniaturami (px)"
diff --git a/po/pt.po b/po/pt.po
index 750324e..22aa7b7 100644
--- a/po/pt.po
+++ b/po/pt.po
@@ -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"
diff --git a/po/pt_BR.po b/po/pt_BR.po
index 5fe9e31..dde81b0 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -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"
diff --git a/po/ru.po b/po/ru.po
index a34a936..0659e0b 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -1461,9 +1461,6 @@ msgstr "Показать значок рабочего стола"
msgid "Show Desktop button padding (px)"
msgstr "Показать рабочий стол - отступ внутри кнопки (px)"
-msgid "Floating rounded theme"
-msgstr "Плавающая закругленная тема"
-
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Изолируйте рабочие столы и мониторы в настройках Переключения между приложениями"
diff --git a/po/sk.po b/po/sk.po
index 951c0f5..9ffcf08 100644
--- a/po/sk.po
+++ b/po/sk.po
@@ -1404,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 ."
diff --git a/po/sl.po b/po/sl.po
index 5aaac62..9ce07e1 100644
--- a/po/sl.po
+++ b/po/sl.po
@@ -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"
diff --git a/po/sq.po b/po/sq.po
index 09fd8c7..f46e0fa 100644
--- a/po/sq.po
+++ b/po/sq.po
@@ -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"
diff --git a/po/sr.po b/po/sr.po
index 17b914f..32d4269 100644
--- a/po/sr.po
+++ b/po/sr.po
@@ -21,6 +21,3 @@ msgstr "Прикажи икону радне површине"
msgid "Show Desktop button padding (px)"
msgstr "Подлога „Прикажи дугме радне површине“ (пк)"
-
-msgid "Floating rounded theme"
-msgstr "Плутајућа заобљена тема"
diff --git a/po/sv.po b/po/sv.po
index daa2aa8..336c77c 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -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"
diff --git a/po/ta.po b/po/ta.po
index cc8c9f2..fa40a4d 100644
--- a/po/ta.po
+++ b/po/ta.po
@@ -21,6 +21,3 @@ msgstr "டெஸ்க்டாப் ஐகானைக் காட்டு"
msgid "Show Desktop button padding (px)"
msgstr "டெஸ்க்டாப் பொத்தானைக் காட்டு திணிப்பு (px)"
-
-msgid "Floating rounded theme"
-msgstr "மிதக்கும் வட்டமான தீம்"
diff --git a/po/te.po b/po/te.po
index 0cb3205..3ca9150 100644
--- a/po/te.po
+++ b/po/te.po
@@ -21,6 +21,3 @@ msgstr "డెస్క్టాప్ చిహ్నాన్ని చూ
msgid "Show Desktop button padding (px)"
msgstr "డెస్క్టాప్ బటన్ చూపించు పాడింగ్ (px)"
-
-msgid "Floating rounded theme"
-msgstr "తేలియాడే గుండ్రని థీమ్"
diff --git a/po/th.po b/po/th.po
index da784e7..8dad220 100644
--- a/po/th.po
+++ b/po/th.po
@@ -21,6 +21,3 @@ msgstr "แสดงไอคอนเดสก์ท็อป"
msgid "Show Desktop button padding (px)"
msgstr "ช่องว่างภายใน แสดงปุ่มเดสก์ท็อป (px)"
-
-msgid "Floating rounded theme"
-msgstr "ธีมกลมลอย"
diff --git a/po/tr.po b/po/tr.po
index 4760bfa..1419897 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -1525,9 +1525,6 @@ msgstr "Masaüstünü Göster simgesi"
msgid "Show Desktop button padding (px)"
msgstr "Masaüstünü göster butonu boşluğu (px)"
-msgid "Floating rounded theme"
-msgstr "Yüzen yuvarlatılmış tema"
-
msgid "Isolate Workspaces and Monitors in Application Switching settings"
msgstr "Uygulama Geçişi ayarlarında Çalışma Alanlarını ve Monitörleri Yalıtım"
diff --git a/po/uk.po b/po/uk.po
index 403ac0d..266ea1e 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-04-03 00:40+0300\n"
-"PO-Revision-Date: 2024-04-03 01:12+0300\n"
+"POT-Creation-Date: 2025-03-09 22:39+0200\n"
+"PO-Revision-Date: 2025-03-09 22:56+0200\n"
"Last-Translator: Yevhen Popok \n"
"Language-Team: \n"
"Language: uk\n"
@@ -17,171 +17,239 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
-"X-Generator: Poedit 3.4.2\n"
+"X-Generator: Poedit 3.4.4\n"
-#: prefs.js:243
+#: src/extension.js:92
+msgid "Dash to Panel has been updated!"
+msgstr "Dash to Panel оновлено!"
+
+#: src/extension.js:93
+msgid "You are now running version"
+msgstr "Тепер у вас версія"
+
+#: src/extension.js:99
+msgid "See what's new"
+msgstr "Що нового"
+
+#: src/prefs.js:275
msgid "Show Desktop button height (px)"
msgstr "Висота кнопки «Показати Стільницю» (пкс)"
-#: prefs.js:243
+#: src/prefs.js:276
msgid "Show Desktop button width (px)"
msgstr "Ширина кнопки «Показати Стільницю» (пкс)"
-#: prefs.js:255
-msgid "Unavailable when gnome-shell top panel is present"
-msgstr "Недоступно, якщо присутня верхня панель gnome-shell"
-
-#: prefs.js:313 ui/SettingsPosition.ui:13 ui/SettingsStyle.ui:15
+#: src/prefs.js:348 ui/SettingsPosition.ui:133 ui/SettingsStyle.ui:204
msgid "Left"
msgstr "Ліворуч"
-#: prefs.js:314
+#: src/prefs.js:349
msgid "Center"
-msgstr "У центрі"
+msgstr "По центру"
-#: prefs.js:315 ui/SettingsPosition.ui:14 ui/SettingsStyle.ui:16
+#: src/prefs.js:350 ui/SettingsPosition.ui:142 ui/SettingsStyle.ui:212
msgid "Right"
msgstr "Праворуч"
-#: prefs.js:317 ui/BoxWindowPreviewOptions.ui:38 ui/SettingsPosition.ui:12
-#: ui/SettingsStyle.ui:14
+#: src/prefs.js:352 ui/BoxWindowPreviewOptions.ui:334
+#: ui/SettingsPosition.ui:124 ui/SettingsStyle.ui:196
msgid "Top"
msgstr "Вгорі"
-#: prefs.js:318 prefs.js:323 ui/SettingsPosition.ui:22
+#: src/prefs.js:353 src/prefs.js:358 ui/SettingsPosition.ui:198
msgid "Middle"
msgstr "Посередині"
-#: prefs.js:319 ui/BoxWindowPreviewOptions.ui:37 ui/SettingsPosition.ui:11
-#: ui/SettingsStyle.ui:13
+#: src/prefs.js:354 ui/BoxWindowPreviewOptions.ui:325
+#: ui/SettingsPosition.ui:115 ui/SettingsStyle.ui:188
msgid "Bottom"
msgstr "Знизу"
-#: prefs.js:322 ui/SettingsPosition.ui:21
+#: src/prefs.js:357 ui/SettingsPosition.ui:197
msgid "Start"
msgstr "На початку"
-#: prefs.js:324 ui/SettingsPosition.ui:23
+#: src/prefs.js:359 ui/SettingsPosition.ui:199
msgid "End"
msgstr "В кінці"
-#: prefs.js:409
+#: src/prefs.js:484
msgid "Show Applications button"
msgstr "Кнопка «Показати програми»"
-#: prefs.js:410
+#: src/prefs.js:485
msgid "Activities button"
msgstr "Кнопка «Діяльність»"
-#: prefs.js:411
+#: src/prefs.js:486
msgid "Taskbar"
msgstr "Панель завдань"
-#: prefs.js:412
+#: src/prefs.js:487
msgid "Date menu"
msgstr "Меню дати"
-#: prefs.js:413
+#: src/prefs.js:488
msgid "System menu"
msgstr "Меню системи"
-#: prefs.js:414
+#: src/prefs.js:489
msgid "Left box"
msgstr "Лівий блок"
-#: prefs.js:415
+#: src/prefs.js:490
msgid "Center box"
msgstr "Центральний блок"
-#: prefs.js:416
+#: src/prefs.js:491
msgid "Right box"
msgstr "Правий блок"
-#: prefs.js:417
+#: src/prefs.js:492
msgid "Desktop button"
msgstr "Кнопка «Стільниця»"
-#: prefs.js:423
+#: src/prefs.js:502 src/prefs.js:2788
msgid "Move up"
msgstr "Перемістити вище"
-#: prefs.js:425
+#: src/prefs.js:504 src/prefs.js:2796
msgid "Move down"
msgstr "Перемістити нижче"
-#: prefs.js:427
+#: src/prefs.js:510
msgid "Visible"
-msgstr "Видимий"
+msgstr "Видимість"
-#: prefs.js:428
+#: src/prefs.js:514
msgid "Select element position"
-msgstr "Оберіть розміщення елемента"
+msgstr "Визначте розміщення елемента"
-#: prefs.js:439
+#: src/prefs.js:528
msgid "Stacked to top"
-msgstr "Укладний вгору"
+msgstr "Укладено вгору"
-#: prefs.js:439
+#: src/prefs.js:528
msgid "Stacked to left"
-msgstr "Укладений ліворуч"
+msgstr "Укладено ліворуч"
-#: prefs.js:440
+#: src/prefs.js:532
msgid "Stacked to bottom"
-msgstr "Укладений донизу"
+msgstr "Укладено вниз"
-#: prefs.js:440
+#: src/prefs.js:532
msgid "Stacked to right"
-msgstr "Укладений праворуч"
+msgstr "Укладено праворуч"
-#: prefs.js:441
+#: src/prefs.js:534
msgid "Centered"
-msgstr "Відцентрований"
+msgstr "По центру"
-#: prefs.js:442
+#: src/prefs.js:535
msgid "Monitor Center"
-msgstr "У центрі монітора"
+msgstr "По центру монітора"
-#: prefs.js:461
+#: src/prefs.js:562
msgid "More options"
msgstr "Більше параметрів"
-#: prefs.js:493
+#: src/prefs.js:597
msgid "Reset to defaults"
msgstr "Скинути налаштування"
-#: prefs.js:516
+#: src/prefs.js:620
msgid "Show Applications options"
msgstr "Параметри «Показати програми»"
-#: prefs.js:526
+#: src/prefs.js:643
msgid "Open icon"
msgstr "Відкрити піктограму"
-#: prefs.js:573
+#: src/prefs.js:708
msgid "Show Desktop options"
-msgstr "Параметри «Показати стільницю»"
+msgstr "Параметри «Показати Cтільницю»"
-#: prefs.js:657
+#: src/prefs.js:800
+msgid "Primary monitor"
+msgstr "Основний монітор"
+
+#: src/prefs.js:801
+msgid "Monitor "
+msgstr "Монітор "
+
+#: src/prefs.js:928
+msgid "Running Indicator Options"
+msgstr "Параметри індикатора роботи"
+
+#: src/prefs.js:1461
+msgid "Dynamic opacity options"
+msgstr "Параметри динамічної непрозорості"
+
+#: src/prefs.js:1710
+msgid "Intellihide options"
+msgstr "Параметри розумного автоприховування"
+
+#: src/prefs.js:1916
+msgid "Window preview options"
+msgstr "Параметри мініатюр вікон"
+
+#: src/prefs.js:2467
+msgid "Ungrouped application options"
+msgstr "Параметри не згрупованих програм"
+
+#: src/prefs.js:2634
+msgid "Customize middle-click behavior"
+msgstr "Поведінка під час клацання середньою"
+
+#: src/prefs.js:2763
+msgid "Text"
+msgstr "Текст"
+
+#: src/prefs.js:2772
+msgid "Command"
+msgstr "Команда"
+
+#: src/prefs.js:2804
+msgid "Remove"
+msgstr "Вилучити"
+
+#: src/prefs.js:2832
+msgid "Customize panel scroll behavior"
+msgstr "Налаштування гортання над панеллю"
+
+#: src/prefs.js:2878
+msgid "Customize icon scroll behavior"
+msgstr "Налаштування гортання над піктограмою"
+
+#: src/prefs.js:3002
+msgid "Advanced hotkeys options"
+msgstr "Розширені параметри гарячих клавіш"
+
+#: src/prefs.js:3030
+msgid "Secondary Menu Options"
+msgstr "Параметри контекстного меню"
+
+#: src/prefs.js:3230
#, javascript-format
msgid "%d ms"
msgstr "%d мс"
-#: prefs.js:662
+#: src/prefs.js:3236
#, javascript-format
msgid "%d °"
msgstr "%d °"
-#: prefs.js:667 prefs.js:672
+#: src/prefs.js:3242 src/prefs.js:3248
#, javascript-format
msgid "%d %%"
msgstr "%d %%"
-#: prefs.js:677
+#: src/prefs.js:3254
#, javascript-format
msgid "%.1f"
msgstr "%.1f"
-#: prefs.js:682
+#: src/prefs.js:3260
#, javascript-format
msgid "%d icon"
msgid_plural "%d icons"
@@ -189,75 +257,28 @@ msgstr[0] "%d піктограма"
msgstr[1] "%d піктограми"
msgstr[2] "%d піктограм"
-#: prefs.js:784
-msgid "Running Indicator Options"
-msgstr "Налаштування індикатора роботи"
-
-#: prefs.js:930
-msgid "Primary monitor"
-msgstr "Основний монітор"
-
-#: prefs.js:930
-msgid "Monitor "
-msgstr "Монітор"
-
-#: prefs.js:1124
-msgid "Dynamic opacity options"
-msgstr "Параметри динамічної непрозорості"
-
-#: prefs.js:1257
-msgid "Intellihide options"
-msgstr "Параметри розумного автоприховування"
-
-#: prefs.js:1363
-msgid "Window preview options"
-msgstr "Параметри мініатюр вікон"
-
-#: prefs.js:1639
-msgid "Ungrouped application options"
-msgstr "Параметри незгрупованих програм"
-
-#: prefs.js:1718
-msgid "Customize middle-click behavior"
-msgstr "Поведінка при кліку середньою кнопкою"
-
-#: prefs.js:1768
-msgid "Customize panel scroll behavior"
-msgstr "Параметри гортання над панеллю"
-
-#: prefs.js:1796
-msgid "Customize icon scroll behavior"
-msgstr "Параметри гортання над піктограмою"
-
-#: prefs.js:1877
-msgid "Advanced hotkeys options"
-msgstr "Розширені параметри гарячих клавіш"
-
-#: prefs.js:1895
-msgid "Secondary Menu Options"
-msgstr "Параметри контекстного меню"
-
-#: prefs.js:1922 ui/SettingsFineTune.ui:23
-msgid "Advanced Options"
-msgstr "Розширені налаштування"
-
-#: prefs.js:2038
+#: src/prefs.js:3387
msgid "App icon animation options"
-msgstr "Параметри анімування піктограм програм"
+msgstr "Параметри анімації піктограм програм"
-#: prefs.js:2088
+#: src/prefs.js:3510
+msgid "App icon highlight options"
+msgstr "Параметри підсвічування піктограм програм"
+
+#: src/prefs.js:3599
msgid "Export settings"
-msgstr "Експортувати параметри"
+msgstr "Експортувати налаштування"
-#: prefs.js:2104
+#: src/prefs.js:3620
msgid "Import settings"
-msgstr "Імпортувати параметри"
+msgstr "Імпортувати налаштування"
-#: appIcons.js:1485 appIcons.js:1495 ui/BoxMiddleClickOptions.ui:10
+#: src/appIcons.js:1912 src/appIcons.js:1929 ui/BoxMiddleClickOptions.ui:33
+#: ui/BoxMiddleClickOptions.ui:62 ui/BoxMiddleClickOptions.ui:91
msgid "Quit"
msgstr "Закрити"
-#: appIcons.js:1497
+#: src/appIcons.js:1932
#, javascript-format
msgid "Quit %d Window"
msgid_plural "Quit %d Windows"
@@ -265,249 +286,246 @@ msgstr[0] "Закрити %d вікно"
msgstr[1] "Закрити %d вікна"
msgstr[2] "Закрити %d вікон"
-#: appIcons.js:1772
+#: src/appIcons.js:2254
msgid "Power options"
msgstr "Параметри живлення"
-#: appIcons.js:1777
+#: src/appIcons.js:2259
msgid "Event logs"
msgstr "Журнали"
-#: appIcons.js:1782
+#: src/appIcons.js:2264
msgid "System"
msgstr "Система"
-#: appIcons.js:1787
+#: src/appIcons.js:2269
msgid "Device Management"
msgstr "Керування пристроями"
-#: appIcons.js:1792
+#: src/appIcons.js:2274
msgid "Disk Management"
msgstr "Керування дисками"
-#: appIcons.js:1805
-msgid "Terminal"
-msgstr "Термінал"
-
-#: appIcons.js:1810
msgid "System Monitor"
msgstr "Системний монітор"
-#: appIcons.js:1815
msgid "Files"
msgstr "Файли"
-#: appIcons.js:1820
-msgid "Extensions"
-msgstr "Розширення"
-
-#: appIcons.js:1825
msgid "Settings"
msgstr "Параметри"
-#: appIcons.js:1836
+#: src/appIcons.js:2305
msgid "Unlock taskbar"
msgstr "Розблокувати панель завдань"
-#: appIcons.js:1836
+#: src/appIcons.js:2306
msgid "Lock taskbar"
msgstr "Заблокувати панель завдань"
-#: appIcons.js:1841
+#: src/appIcons.js:2316
+msgid "Gnome Settings"
+msgstr "Параметри Gnome"
+
+#: src/appIcons.js:2320
msgid "Taskbar Settings"
msgstr "Налаштування панелі завдань"
-#: appIcons.js:1846
+#: src/appIcons.js:2327
msgid "Restore Windows"
msgstr "Відновити вікна"
-#: appIcons.js:1846
+#: src/appIcons.js:2328
msgid "Show Desktop"
msgstr "Показати Стільницю"
-#: ui/BoxAdvancedOptions.ui:1
-msgid "Nothing yet!"
-msgstr "Поки нічого!"
+#: src/taskbar.js:66
+msgid "Donation options"
+msgstr "Можливості фінансової підтримки"
-#: ui/BoxAdvancedOptions.ui:2
-msgid "For real..."
-msgstr "Справді..."
+#: src/taskbar.js:79
+msgid "Thank you!"
+msgstr "Дякую!"
-#: ui/BoxAnimateAppIconHoverOptions.ui:1
+#: src/taskbar.js:79
+msgid "Please donate :)"
+msgstr "Прохання підтримати фінансово :)"
+
+#: ui/BoxAnimateAppIconHoverOptions.ui:62
msgid "Animation type"
-msgstr "Тип анімації"
+msgstr "Вид анімації"
-#: ui/BoxAnimateAppIconHoverOptions.ui:2
+#: ui/BoxAnimateAppIconHoverOptions.ui:67
msgid "Simple"
msgstr "Проста"
-#: ui/BoxAnimateAppIconHoverOptions.ui:3
+#: ui/BoxAnimateAppIconHoverOptions.ui:68
msgid "Ripple"
msgstr "Хвиля"
-#: ui/BoxAnimateAppIconHoverOptions.ui:4
+#: ui/BoxAnimateAppIconHoverOptions.ui:69
msgid "Plank"
msgstr "Plank"
-#: ui/BoxAnimateAppIconHoverOptions.ui:5
+#: ui/BoxAnimateAppIconHoverOptions.ui:84
msgid "Duration"
msgstr "Тривалість"
-#: ui/BoxAnimateAppIconHoverOptions.ui:6
+#: ui/BoxAnimateAppIconHoverOptions.ui:101
msgid "Rotation"
msgstr "Обертання"
-#: ui/BoxAnimateAppIconHoverOptions.ui:7
+#: ui/BoxAnimateAppIconHoverOptions.ui:118
msgid "Travel"
msgstr "Переміщення"
-#: ui/BoxAnimateAppIconHoverOptions.ui:8
+#: ui/BoxAnimateAppIconHoverOptions.ui:135
msgid "Zoom"
msgstr "Масштабування"
-#: ui/BoxAnimateAppIconHoverOptions.ui:9
+#: ui/BoxAnimateAppIconHoverOptions.ui:152
msgid "Convexity"
msgstr "Вигин"
-#: ui/BoxAnimateAppIconHoverOptions.ui:10
+#: ui/BoxAnimateAppIconHoverOptions.ui:169
msgid "Extent"
msgstr "Поширення"
-#: ui/BoxDotOptions.ui:1
+#: ui/BoxDotOptions.ui:37
msgid "Highlight focused application"
msgstr "Підсвічувати програми у фокусі"
-#: ui/BoxDotOptions.ui:2
+#: ui/BoxDotOptions.ui:54
msgid "Icon dominant color"
msgstr "Домінантний колір піктограми"
-#: ui/BoxDotOptions.ui:3
+#: ui/BoxDotOptions.ui:65
msgid "Custom color"
msgstr "Власний колір"
-#: ui/BoxDotOptions.ui:4
+#: ui/BoxDotOptions.ui:76
msgid "Highlight opacity"
msgstr "Непрозорість підсвічування"
-#: ui/BoxDotOptions.ui:5
+#: ui/BoxDotOptions.ui:96
msgid "Indicator size (px)"
msgstr "Розмір індикатора (пкс)"
-#: ui/BoxDotOptions.ui:6
+#: ui/BoxDotOptions.ui:109
msgid "Indicator color - Icon Dominant"
msgstr "Колір індикатора - домінантний в піктограмі"
-#: ui/BoxDotOptions.ui:7
+#: ui/BoxDotOptions.ui:126
msgid "Indicator color - Override Theme"
-msgstr "Колір індикатора - не як в темі"
+msgstr "Колір індикатора - замінює той, що в темі"
-#: ui/BoxDotOptions.ui:8
+#: ui/BoxDotOptions.ui:142 ui/BoxDotOptions.ui:215
msgid "1 window open (or ungrouped)"
-msgstr "1 відкрите вікно (або незгруповане)"
+msgstr "1 вікно відкрито (або не згруповано)"
-#: ui/BoxDotOptions.ui:9
+#: ui/BoxDotOptions.ui:146 ui/BoxDotOptions.ui:219
msgid "Apply to all"
msgstr "Застосувати для всіх"
-#: ui/BoxDotOptions.ui:10
+#: ui/BoxDotOptions.ui:159 ui/BoxDotOptions.ui:232
msgid "2 windows open"
-msgstr "2 відкритих вікна"
+msgstr "2 вікна відкрито"
-#: ui/BoxDotOptions.ui:11
+#: ui/BoxDotOptions.ui:170 ui/BoxDotOptions.ui:243
msgid "3 windows open"
-msgstr "3 відкритих вікна"
+msgstr "3 вікна відкрито"
-#: ui/BoxDotOptions.ui:12
+#: ui/BoxDotOptions.ui:181 ui/BoxDotOptions.ui:254
msgid "4+ windows open"
-msgstr "4 та більше відкритих вікон"
+msgstr "4 та більше вікон відкрито"
-#: ui/BoxDotOptions.ui:13
+#: ui/BoxDotOptions.ui:198
msgid "Use different for unfocused"
msgstr "Окремо для вікон не у фокусі"
-#: ui/BoxDynamicOpacityOptions.ui:1
+#: ui/BoxDynamicOpacityOptions.ui:37
msgid "The panel background opacity is affected by"
-msgstr "Непрозорий фон панелі зумовлюють"
+msgstr "Непрозорість тла панелі зумовлюють"
-#: ui/BoxDynamicOpacityOptions.ui:2 ui/BoxIntellihideOptions.ui:3
+#: ui/BoxDynamicOpacityOptions.ui:42 ui/BoxIntellihideOptions.ui:62
msgid "All windows"
msgstr "Всі вікна"
-#: ui/BoxDynamicOpacityOptions.ui:3 ui/BoxIntellihideOptions.ui:4
+#: ui/BoxDynamicOpacityOptions.ui:43 ui/BoxIntellihideOptions.ui:63
msgid "Focused windows"
msgstr "Вікна у фокусі"
-#: ui/BoxDynamicOpacityOptions.ui:4 ui/BoxIntellihideOptions.ui:5
+#: ui/BoxDynamicOpacityOptions.ui:44 ui/BoxIntellihideOptions.ui:64
msgid "Maximized windows"
msgstr "Розгорнуті вікна"
-#: ui/BoxDynamicOpacityOptions.ui:5
+#: ui/BoxDynamicOpacityOptions.ui:53
msgid "Change opacity when a window gets closer than (px)"
msgstr "Змінювати непрозорість, якщо вікно ближче, ніж (пкс)"
-#: ui/BoxDynamicOpacityOptions.ui:7
-#, no-c-format
+#: ui/BoxDynamicOpacityOptions.ui:69
msgid "Change opacity to (%)"
msgstr "Значення непрозорості (%)"
-#: ui/BoxDynamicOpacityOptions.ui:8 ui/BoxShowApplicationsOptions.ui:3
-#: ui/BoxWindowPreviewOptions.ui:57 ui/SettingsStyle.ui:31
+#: ui/BoxDynamicOpacityOptions.ui:72 ui/BoxShowApplicationsOptions.ui:64
+#: ui/BoxWindowPreviewOptions.ui:472 ui/SettingsStyle.ui:374
+#: ui/SettingsStyle.ui:431 ui/SettingsStyle.ui:449
msgid "0"
msgstr "0"
-#: ui/BoxDynamicOpacityOptions.ui:9
+#: ui/BoxDynamicOpacityOptions.ui:82
msgid "Opacity change animation duration (ms)"
msgstr "Тривалість анімації зміни непрозорості (в мс)"
-#: ui/BoxGroupAppsOptions.ui:1
+#: ui/BoxGroupAppsOptions.ui:32
msgid "Font size (px) of the application titles (default is 14)"
-msgstr "Розмір шрифту (пкс) в заголовках програм (типово - 14)"
+msgstr "Розмір шрифту (пкс) заголовків програм (типово - 14)"
-#: ui/BoxGroupAppsOptions.ui:2
+#: ui/BoxGroupAppsOptions.ui:47
msgid "Font weight of application titles"
-msgstr "Товщина шрифту в заголовках програм"
+msgstr "Товщина шрифту заголовків програм"
-#: ui/BoxGroupAppsOptions.ui:3 ui/BoxWindowPreviewOptions.ui:44
+#: ui/BoxGroupAppsOptions.ui:52 ui/BoxWindowPreviewOptions.ui:406
msgid "inherit from theme"
-msgstr "Як в темі"
+msgstr "як в темі"
-#: ui/BoxGroupAppsOptions.ui:4 ui/BoxWindowPreviewOptions.ui:45
+#: ui/BoxGroupAppsOptions.ui:53 ui/BoxWindowPreviewOptions.ui:407
msgid "normal"
-msgstr "Звичайний"
+msgstr "звичайний"
-#: ui/BoxGroupAppsOptions.ui:5 ui/BoxWindowPreviewOptions.ui:46
+#: ui/BoxGroupAppsOptions.ui:54 ui/BoxWindowPreviewOptions.ui:408
msgid "lighter"
-msgstr "Світліший"
+msgstr "світліший"
-#: ui/BoxGroupAppsOptions.ui:6 ui/BoxWindowPreviewOptions.ui:47
+#: ui/BoxGroupAppsOptions.ui:55 ui/BoxWindowPreviewOptions.ui:409
msgid "bold"
-msgstr "Жирний"
+msgstr "жирний"
-#: ui/BoxGroupAppsOptions.ui:7 ui/BoxWindowPreviewOptions.ui:48
+#: ui/BoxGroupAppsOptions.ui:56 ui/BoxWindowPreviewOptions.ui:410
msgid "bolder"
-msgstr "Жирніший"
+msgstr "жирніший"
-#: ui/BoxGroupAppsOptions.ui:8
+#: ui/BoxGroupAppsOptions.ui:65
msgid "Font color of the application titles"
-msgstr "Колір шрифту в заголовках програм"
+msgstr "Колір шрифту заголовків програм"
-#: ui/BoxGroupAppsOptions.ui:9
+#: ui/BoxGroupAppsOptions.ui:77
msgid "Font color of the minimized application titles"
-msgstr "Колір шрифту в заголовках згорнутих програм"
+msgstr "Колір шрифту заголовків згорнутих програм"
-#: ui/BoxGroupAppsOptions.ui:10
+#: ui/BoxGroupAppsOptions.ui:95
msgid "Maximum width (px) of the application titles"
msgstr "Максимальна довжина (пкс) заголовків програм"
-#: ui/BoxGroupAppsOptions.ui:11
+#: ui/BoxGroupAppsOptions.ui:96
msgid "(default is 160)"
msgstr "(типово - 160)"
-#: ui/BoxGroupAppsOptions.ui:12
+#: ui/BoxGroupAppsOptions.ui:111
msgid "Use a fixed width for the application titles"
msgstr "Використовувати сталу довжину заголовків програм"
-#: ui/BoxGroupAppsOptions.ui:13
+#: ui/BoxGroupAppsOptions.ui:112
msgid ""
"The application titles all have the same width, even if their texts are "
"shorter than the maximum width. The maximum width value is used as the fixed "
@@ -517,498 +535,559 @@ msgstr ""
"максимальної довжини. Значення максимальної довжини буде використано для "
"сталої довжини."
-#: ui/BoxGroupAppsOptions.ui:14
+#: ui/BoxGroupAppsOptions.ui:129
msgid "Display running indicators on unfocused applications"
msgstr "Показувати індикатор роботи для програм не у фокусі"
-#: ui/BoxGroupAppsOptions.ui:15
+#: ui/BoxGroupAppsOptions.ui:140
msgid "Use the favorite icons as application launchers"
-msgstr "Піктограми пришпилених програм використовуються як запускачі"
+msgstr "Зробити піктограми пришпилених програм запускачами"
-#: ui/BoxIntellihideOptions.ui:1
+#: ui/BoxHighlightAppIconHoverOptions.ui:26
+msgid "Highlight AppIcon color"
+msgstr "Колір підсвічування піктограм програм"
+
+#: ui/BoxHighlightAppIconHoverOptions.ui:38
+msgid "Pressed AppIcon color"
+msgstr "Колір піктограм програм під час натискання"
+
+#: ui/BoxHighlightAppIconHoverOptions.ui:50
+msgid "Highlight AppIcon border radius"
+msgstr "Радіус рамки підсвічування піктограм програм"
+
+#: ui/BoxHighlightAppIconHoverOptions.ui:51
+msgid "Overrides global border radius (default is 0)"
+msgstr "Замінює глобальний радіус межі (типово - 0)"
+
+#: ui/BoxIntellihideOptions.ui:47
msgid "Only hide the panel when it is obstructed by windows"
msgstr "Приховувати панель лише якщо її перекривають вікна"
-#: ui/BoxIntellihideOptions.ui:2
+#: ui/BoxIntellihideOptions.ui:57
msgid "The panel hides from"
msgstr "Приховування панелі зумовлюють"
-#: ui/BoxIntellihideOptions.ui:6
+#: ui/BoxIntellihideOptions.ui:76
msgid "Require pressure at the edge of the screen to reveal the panel"
-msgstr "Для появи панелі потрібне притискання на краю екрану"
+msgstr "Для появи панелі потрібне притискання на межі екрану"
-#: ui/BoxIntellihideOptions.ui:7
+#: ui/BoxIntellihideOptions.ui:86
msgid "Required pressure threshold (px)"
msgstr "Поріг притискання (пкс)"
-#: ui/BoxIntellihideOptions.ui:8
+#: ui/BoxIntellihideOptions.ui:100
msgid "Required pressure timeout (ms)"
msgstr "Затримка після притискання (мс)"
-#: ui/BoxIntellihideOptions.ui:9
+#: ui/BoxIntellihideOptions.ui:118
msgid "Allow the panel to be revealed while in fullscreen mode"
msgstr "Дозволити появу панелі в повноекранному режимі"
-#: ui/BoxIntellihideOptions.ui:10
+#: ui/BoxIntellihideOptions.ui:128
+msgid "(requires multi-monitors option)"
+msgstr "(необхідна присутність на кількох моніторах)"
+
+#: ui/BoxIntellihideOptions.ui:129
msgid "Only hide secondary panels"
msgstr "Приховувати лише додаткові панелі"
-#: ui/BoxIntellihideOptions.ui:11
-msgid "(requires multi-monitors option)"
-msgstr "(потрібне налаштування для декількох моніторів)"
-
-#: ui/BoxIntellihideOptions.ui:12
-msgid "Keyboard shortcut to reveal and hold the panel"
-msgstr "Клавіатурне скорочення для появи та утримання панелі"
-
-#: ui/BoxIntellihideOptions.ui:13 ui/BoxOverlayShortcut.ui:12
+#: ui/BoxIntellihideOptions.ui:139 ui/BoxOverlayShortcut.ui:65
msgid "Syntax: <Shift>, <Ctrl>, <Alt>, <Super>"
msgstr "Синтаксис: <Shift>, <Ctrl>, <Alt>, <Super>"
-#: ui/BoxIntellihideOptions.ui:14
+#: ui/BoxIntellihideOptions.ui:140
+msgid "Keyboard shortcut to reveal and hold the panel"
+msgstr "Клавіатурне скорочення для появи та утримання панелі"
+
+#: ui/BoxIntellihideOptions.ui:143
msgid "e.g. i"
msgstr "напр., i"
-#: ui/BoxIntellihideOptions.ui:15
+#: ui/BoxIntellihideOptions.ui:152
+msgid "Persist state across restarts"
+msgstr "Зберігати стан між перезапусками"
+
+#: ui/BoxIntellihideOptions.ui:162
+msgid ""
+"(respects \"Do Not Disturb\" and requires show notification counter "
+"badge option)"
+msgstr ""
+"(враховує режим «Не турбувати» та потребує «Показувати лічильник сповіщень»)"
+
+#: ui/BoxIntellihideOptions.ui:163
+msgid "Reveal and hold the panel on notification"
+msgstr "Показувати та утримувати панель, коли є сповіщення"
+
+#: ui/BoxIntellihideOptions.ui:177
msgid "Hide and reveal animation duration (ms)"
msgstr "Тривалість анімації приховування та появи (мс)"
-#: ui/BoxIntellihideOptions.ui:16
+#: ui/BoxIntellihideOptions.ui:191
msgid "Delay before hiding the panel (ms)"
-msgstr "Затримка перед приховання панелі (мс)"
+msgstr "Затримка перед приховуванням панелі (мс)"
-#: ui/BoxIntellihideOptions.ui:17
+#: ui/BoxIntellihideOptions.ui:206
msgid "Delay before enabling intellihide on start (ms)"
-msgstr "Затримка перед активацією першого інтелектуального приховування (мс)"
+msgstr "Затримка перед активацією розумного приховування під час запуску (мс)"
-#: ui/BoxMiddleClickOptions.ui:1
+#: ui/BoxMiddleClickOptions.ui:19
msgid "Shift+Click action"
-msgstr "Дія для Shift+Клік"
+msgstr "Дія для Shift+клацання"
-#: ui/BoxMiddleClickOptions.ui:2
+#: ui/BoxMiddleClickOptions.ui:20
msgid ""
"When set to minimize, double clicking minimizes all the windows of the "
"application."
msgstr ""
-"Якщо вибрано \"Згортання вікна\", подвійний клік згорне всі вікна програми."
+"Якщо вибрано \"Згортання вікна\", то подвійне клацання буде згортати всі "
+"вікна програми."
-#: ui/BoxMiddleClickOptions.ui:3 ui/SettingsAction.ui:9
+#: ui/BoxMiddleClickOptions.ui:25 ui/BoxMiddleClickOptions.ui:54
+#: ui/BoxMiddleClickOptions.ui:83 ui/SettingsAction.ui:40
msgid "Raise windows"
msgstr "Підняття вікон"
-#: ui/BoxMiddleClickOptions.ui:4
+#: ui/BoxMiddleClickOptions.ui:26 ui/BoxMiddleClickOptions.ui:55
+#: ui/BoxMiddleClickOptions.ui:84
msgid "Minimize window"
msgstr "Згортання вікна"
-#: ui/BoxMiddleClickOptions.ui:5 ui/SettingsAction.ui:10
+#: ui/BoxMiddleClickOptions.ui:27 ui/BoxMiddleClickOptions.ui:56
+#: ui/BoxMiddleClickOptions.ui:85 ui/SettingsAction.ui:41
msgid "Launch new instance"
msgstr "Запуск нового екземпляра"
-#: ui/BoxMiddleClickOptions.ui:6 ui/SettingsAction.ui:5
+#: ui/BoxMiddleClickOptions.ui:28 ui/BoxMiddleClickOptions.ui:57
+#: ui/BoxMiddleClickOptions.ui:86 ui/SettingsAction.ui:35
msgid "Cycle through windows"
msgstr "Циклічне перемикання вікон"
-#: ui/BoxMiddleClickOptions.ui:7 ui/SettingsAction.ui:4
+#: ui/BoxMiddleClickOptions.ui:29 ui/BoxMiddleClickOptions.ui:58
+#: ui/BoxMiddleClickOptions.ui:87 ui/SettingsAction.ui:34
msgid "Cycle windows + minimize"
msgstr "Циклічне перемикання + згортання вікон"
-#: ui/BoxMiddleClickOptions.ui:8 ui/SettingsAction.ui:6
+#: ui/BoxMiddleClickOptions.ui:30 ui/BoxMiddleClickOptions.ui:59
+#: ui/BoxMiddleClickOptions.ui:88 ui/SettingsAction.ui:36
msgid "Toggle single / Preview multiple"
-msgstr "Згортання одного / мініатюри декількох"
+msgstr "Видимість одного / мініатюри кількох"
-#: ui/BoxMiddleClickOptions.ui:9 ui/SettingsAction.ui:7
+#: ui/BoxMiddleClickOptions.ui:31 ui/BoxMiddleClickOptions.ui:60
+#: ui/BoxMiddleClickOptions.ui:89 ui/SettingsAction.ui:37
msgid "Toggle single / Cycle multiple"
-msgstr "Згортання одного / перемикання декількох"
+msgstr "Видимість одного / перемикання кількох"
-#: ui/BoxMiddleClickOptions.ui:11
+#: ui/BoxMiddleClickOptions.ui:32 ui/BoxMiddleClickOptions.ui:61
+#: ui/BoxMiddleClickOptions.ui:90 ui/SettingsAction.ui:38
+msgid "Toggle single / Spread multiple"
+msgstr "Видимість одного / показ кількох"
+
+#: ui/BoxMiddleClickOptions.ui:48
msgid "Middle-Click action"
-msgstr "Дія при кліку середньою кнопкою"
+msgstr "Дія під час клацання середньою"
-#: ui/BoxMiddleClickOptions.ui:12
+#: ui/BoxMiddleClickOptions.ui:49
msgid "Behavior for Middle-Click."
-msgstr "Поведінка при кліку середньою кнопкою"
+msgstr "Поведінка під час клацання середньою."
-#: ui/BoxMiddleClickOptions.ui:13
+#: ui/BoxMiddleClickOptions.ui:77
msgid "Shift+Middle-Click action"
-msgstr "Дія при Shift+Клік середньою кнопкою"
+msgstr "Дія під час Shift+клацання середньою"
-#: ui/BoxMiddleClickOptions.ui:14
+#: ui/BoxMiddleClickOptions.ui:78
msgid "Behavior for Shift+Middle-Click."
-msgstr "Поведінка при Shift+Клік середньою кнопкою"
+msgstr "Поведінка під час Shift+клацання середньою."
-#: ui/BoxOverlayShortcut.ui:1
-msgid "Hotkeys prefix"
-msgstr "Префікс гарячих клавіш"
-
-#: ui/BoxOverlayShortcut.ui:2
+#: ui/BoxOverlayShortcut.ui:23
msgid "Hotkeys will either be Super+Number or Super+Alt+Num"
msgstr "Гарячими клавішами будуть або Super+Число, або Super+Alt+Num"
-#: ui/BoxOverlayShortcut.ui:3
+#: ui/BoxOverlayShortcut.ui:24
+msgid "Hotkeys prefix"
+msgstr "Префікс гарячих клавіш"
+
+#: ui/BoxOverlayShortcut.ui:29
msgid "Super"
msgstr "Super"
-#: ui/BoxOverlayShortcut.ui:4
+#: ui/BoxOverlayShortcut.ui:30
msgid "Super + Alt"
msgstr "Super + Alt"
-#: ui/BoxOverlayShortcut.ui:5
-msgid "Number overlay"
-msgstr "Накладання номерів"
-
-#: ui/BoxOverlayShortcut.ui:6
+#: ui/BoxOverlayShortcut.ui:38
msgid ""
"Temporarily show the application numbers over the icons when using the "
"hotkeys."
-msgstr "Накладати на піктограми номери при використанні гарячих клавіш."
+msgstr ""
+"Тимчасово накладати на піктограми номери програм під час використання "
+"гарячих клавіш."
-#: ui/BoxOverlayShortcut.ui:7
+#: ui/BoxOverlayShortcut.ui:39
+msgid "Number overlay"
+msgstr "Накладання номерів"
+
+#: ui/BoxOverlayShortcut.ui:44
msgid "Never"
msgstr "Ніколи"
-#: ui/BoxOverlayShortcut.ui:8
+#: ui/BoxOverlayShortcut.ui:45
msgid "Show temporarily"
-msgstr "Тимчасовий показ"
+msgstr "Тимчасово"
-#: ui/BoxOverlayShortcut.ui:9
+#: ui/BoxOverlayShortcut.ui:46
msgid "Always visible"
-msgstr "Постійний показ"
+msgstr "Завжди"
-#: ui/BoxOverlayShortcut.ui:10
+#: ui/BoxOverlayShortcut.ui:54
msgid "Hide timeout (ms)"
-msgstr "Час зникнення (мс)"
+msgstr "Затримка приховування (мс)"
-#: ui/BoxOverlayShortcut.ui:11
+#: ui/BoxOverlayShortcut.ui:66
msgid "Shortcut to show the overlay for 2 seconds"
-msgstr "Комбінація для 2-секундного показу накладання"
+msgstr "Клавіатурне скорочення для активації накладання на 2 секунди"
-#: ui/BoxOverlayShortcut.ui:13
+#: ui/BoxOverlayShortcut.ui:69
msgid "e.g. q"
msgstr "напр., q"
-#: ui/BoxOverlayShortcut.ui:14
-msgid "Show window previews on hotkey"
-msgstr "Гаряча клавіша викликає показ мініатюр вікон"
+#: ui/BoxOverlayShortcut.ui:78
+msgid ""
+"On secondary monitors, show the overlay on icons matching the primary monitor"
+msgstr ""
+"На додаткових моніторах показувати те саме накладання на піктограми, що й на "
+"основному моніторі"
-#: ui/BoxOverlayShortcut.ui:15
+#: ui/BoxOverlayShortcut.ui:79
+msgid "Show the overlay on all monitors"
+msgstr "Показувати накладання на всіх моніторах"
+
+#: ui/BoxOverlayShortcut.ui:89
msgid "Show previews when the application have multiple instances"
-msgstr "Показувати мініатюри, коли запущено декілька екземплярів програми"
+msgstr "Показувати мініатюри, коли запущено кілька екземплярів програми"
-#: ui/BoxOverlayShortcut.ui:16
+#: ui/BoxOverlayShortcut.ui:90
+msgid "Show window previews on hotkey"
+msgstr "Показувати мініатюри вікон після натискання гарячої клавіші"
+
+#: ui/BoxOverlayShortcut.ui:100
+msgid "Select which keyboard number keys are used to activate the hotkeys"
+msgstr ""
+"Оберіть, які цифри на клавіатурі використовувати для активації гарячих клавіш"
+
+#: ui/BoxOverlayShortcut.ui:101
msgid "Hotkeys are activated with"
msgstr "Гарячі клавіші активуються"
-#: ui/BoxOverlayShortcut.ui:17
-msgid "Select which keyboard number keys are used to activate the hotkeys"
-msgstr ""
-"Оберіть, які цифрові клавіші використовувати для активації гарячих клавіш"
-
-#: ui/BoxOverlayShortcut.ui:18
+#: ui/BoxOverlayShortcut.ui:106
msgid "Number row"
msgstr "Цифровим рядом"
-#: ui/BoxOverlayShortcut.ui:19
+#: ui/BoxOverlayShortcut.ui:107
msgid "Numeric keypad"
msgstr "Цифровою клавіатурою"
-#: ui/BoxOverlayShortcut.ui:20
+#: ui/BoxOverlayShortcut.ui:108
msgid "Both"
msgstr "Обома"
-#: ui/BoxScrollIconOptions.ui:1 ui/BoxScrollPanelOptions.ui:1
+#: ui/BoxScrollIconOptions.ui:25 ui/BoxScrollPanelOptions.ui:25
msgid "Delay between mouse scroll events (ms)"
msgstr "Затримка між подіями гортання мишею (мс)"
-#: ui/BoxScrollIconOptions.ui:2 ui/BoxScrollPanelOptions.ui:2
+#: ui/BoxScrollIconOptions.ui:26 ui/BoxScrollPanelOptions.ui:26
msgid "Use this value to limit the number of captured mouse scroll events."
-msgstr "Це значення обмежує кількість захоплених подій гортання мишею"
+msgstr "Це значення обмежує кількість захоплених подій гортання мишею."
-#: ui/BoxScrollPanelOptions.ui:3
+#: ui/BoxScrollPanelOptions.ui:42
msgid "Show popup when changing workspace"
-msgstr "Показувати сповіщення щодо зміни робочого простору"
+msgstr "Показувати сповіщення про зміну робочого простору"
-#: ui/BoxScrollPanelOptions.ui:4
+#: ui/BoxScrollPanelOptions.ui:43
msgid "This affects workspace popup when scrolling on the panel only."
msgstr ""
"Це впливає на сповіщення зміни робочого простору лише під час гортання над "
-"панеллю"
+"панеллю."
-#: ui/BoxSecondaryMenuOptions.ui:1
+#: ui/BoxSecondaryMenuOptions.ui:19
msgid "Integrate AppMenu items"
-msgstr "Вбудувати елементи Меню"
+msgstr "Вбудувати пункти Меню програм"
-#: ui/BoxSecondaryMenuOptions.ui:2
-msgid "Show Details menu item"
+#: ui/BoxSecondaryMenuOptions.ui:30
+msgid "App Details menu item"
msgstr "Пункт меню Подробиці щодо програми"
-#: ui/BoxShowApplicationsOptions.ui:1
+#: ui/BoxSecondaryMenuOptions.ui:31
+msgid "App Details is only available when Gnome Software is installed"
+msgstr ""
+"Пункт Подробиці щодо програми видимий лише коли встановлено "
+"«Програми» GNOME"
+
+#: ui/BoxShowApplicationsOptions.ui:25
msgid "Show Applications icon"
msgstr "Піктограма Показати програми"
-#: ui/BoxShowApplicationsOptions.ui:2
+#: ui/BoxShowApplicationsOptions.ui:60
msgid "Show Applications icon side padding (px)"
-msgstr "Відступи піктограми «Показати програми» (пкс)"
+msgstr "Бічний відступ піктограми «Показати програми» (пкс)"
-#: ui/BoxShowApplicationsOptions.ui:4
+#: ui/BoxShowApplicationsOptions.ui:73
msgid "Override escape key and return to desktop"
-msgstr "Перепризначення клавіші «Escape» та повернення до стільниці"
+msgstr "Клавіша «Escape» повертає до стільниці"
-#: ui/BoxShowDesktopOptions.ui:1
+#: ui/BoxShowDesktopOptions.ui:53
msgid "Override Show Desktop line color"
-msgstr "Заміна кольору смужки «Показати Стільницю»"
+msgstr "Замінити колір смужки «Показати Стільницю»"
-#: ui/BoxShowDesktopOptions.ui:2
+#: ui/BoxShowDesktopOptions.ui:77
msgid "Reveal the desktop when hovering the Show Desktop button"
-msgstr "Показувати стільницю при наведенні на кнопку «Показати Стільницю»"
+msgstr "Показувати стільницю під час наведення на кнопку «Показати Стільницю»"
-#: ui/BoxShowDesktopOptions.ui:3
+#: ui/BoxShowDesktopOptions.ui:90
msgid "Delay before revealing the desktop (ms)"
-msgstr "Затримка перед показом стільниці"
+msgstr "Затримка перед появою стільниці"
-#: ui/BoxShowDesktopOptions.ui:4
+#: ui/BoxShowDesktopOptions.ui:106
msgid "Fade duration (ms)"
msgstr "Час зникнення (мс)"
-#: ui/BoxWindowPreviewOptions.ui:1
+#: ui/BoxWindowPreviewOptions.ui:89
msgid "Time (ms) before showing"
-msgstr "Затримка (мс) перед показом (100 за замовчуванням)"
+msgstr "Затримка (мс) перед появою"
-#: ui/BoxWindowPreviewOptions.ui:2
+#: ui/BoxWindowPreviewOptions.ui:90
msgid "(400 is default)"
msgstr "(типово - 400)"
-#: ui/BoxWindowPreviewOptions.ui:3
+#: ui/BoxWindowPreviewOptions.ui:105
msgid "Time (ms) before hiding"
-msgstr "Затримка (мс) перед показом (100 за замовчуванням)"
+msgstr "Затримка (мс) перед приховуванням"
-#: ui/BoxWindowPreviewOptions.ui:4
+#: ui/BoxWindowPreviewOptions.ui:106
msgid "(100 is default)"
msgstr "(типово - 100)"
-#: ui/BoxWindowPreviewOptions.ui:5
+#: ui/BoxWindowPreviewOptions.ui:117
msgid "Immediate on application icon click"
-msgstr "Відразу після кліку на піктограму програми"
+msgstr "Відразу після клацання на піктограмі програми"
-#: ui/BoxWindowPreviewOptions.ui:6
+#: ui/BoxWindowPreviewOptions.ui:138
msgid "Animation time (ms)"
msgstr "Час зникнення (мс)"
-#: ui/BoxWindowPreviewOptions.ui:7
+#: ui/BoxWindowPreviewOptions.ui:159
msgid "Middle click on the preview to close the window"
-msgstr "Клік середньою кнопкою на мініатюрі закриває вікно"
+msgstr "Клацання середньою на мініатюрі закриває вікно"
-#: ui/BoxWindowPreviewOptions.ui:8
+#: ui/BoxWindowPreviewOptions.ui:176
msgid "Window previews preferred size (px)"
msgstr "Бажаний розмір мініатюр вікон (пкс)"
-#: ui/BoxWindowPreviewOptions.ui:9
+#: ui/BoxWindowPreviewOptions.ui:192
msgid "Window previews aspect ratio X (width)"
msgstr "Співвідношення сторін мініатюр вікон по осі X (ширина)"
-#: ui/BoxWindowPreviewOptions.ui:10
+#: ui/BoxWindowPreviewOptions.ui:197 ui/BoxWindowPreviewOptions.ui:238
msgid "1"
msgstr "1"
-#: ui/BoxWindowPreviewOptions.ui:11
+#: ui/BoxWindowPreviewOptions.ui:198 ui/BoxWindowPreviewOptions.ui:239
msgid "2"
msgstr "2"
-#: ui/BoxWindowPreviewOptions.ui:12
+#: ui/BoxWindowPreviewOptions.ui:199 ui/BoxWindowPreviewOptions.ui:240
msgid "3"
msgstr "3"
-#: ui/BoxWindowPreviewOptions.ui:13
+#: ui/BoxWindowPreviewOptions.ui:200 ui/BoxWindowPreviewOptions.ui:241
msgid "4"
msgstr "4"
-#: ui/BoxWindowPreviewOptions.ui:14
+#: ui/BoxWindowPreviewOptions.ui:201 ui/BoxWindowPreviewOptions.ui:242
+#: ui/BoxWindowPreviewOptions.ui:306
msgid "5"
msgstr "5"
-#: ui/BoxWindowPreviewOptions.ui:15
+#: ui/BoxWindowPreviewOptions.ui:202 ui/BoxWindowPreviewOptions.ui:243
msgid "6"
msgstr "6"
-#: ui/BoxWindowPreviewOptions.ui:16
+#: ui/BoxWindowPreviewOptions.ui:203 ui/BoxWindowPreviewOptions.ui:244
msgid "7"
msgstr "7"
-#: ui/BoxWindowPreviewOptions.ui:17
+#: ui/BoxWindowPreviewOptions.ui:204 ui/BoxWindowPreviewOptions.ui:245
msgid "8"
msgstr "8"
-#: ui/BoxWindowPreviewOptions.ui:18
+#: ui/BoxWindowPreviewOptions.ui:205 ui/BoxWindowPreviewOptions.ui:246
msgid "9"
msgstr "9"
-#: ui/BoxWindowPreviewOptions.ui:19
+#: ui/BoxWindowPreviewOptions.ui:206 ui/BoxWindowPreviewOptions.ui:247
msgid "10"
msgstr "10"
-#: ui/BoxWindowPreviewOptions.ui:20
+#: ui/BoxWindowPreviewOptions.ui:207 ui/BoxWindowPreviewOptions.ui:248
msgid "11"
msgstr "11"
-#: ui/BoxWindowPreviewOptions.ui:21
+#: ui/BoxWindowPreviewOptions.ui:208 ui/BoxWindowPreviewOptions.ui:249
msgid "12"
msgstr "12"
-#: ui/BoxWindowPreviewOptions.ui:22
+#: ui/BoxWindowPreviewOptions.ui:209 ui/BoxWindowPreviewOptions.ui:250
msgid "13"
msgstr "13"
-#: ui/BoxWindowPreviewOptions.ui:23
+#: ui/BoxWindowPreviewOptions.ui:210 ui/BoxWindowPreviewOptions.ui:251
msgid "14"
msgstr "14"
-#: ui/BoxWindowPreviewOptions.ui:24
+#: ui/BoxWindowPreviewOptions.ui:211 ui/BoxWindowPreviewOptions.ui:252
msgid "15"
msgstr "15"
-#: ui/BoxWindowPreviewOptions.ui:25
+#: ui/BoxWindowPreviewOptions.ui:212 ui/BoxWindowPreviewOptions.ui:253
msgid "16"
msgstr "16"
-#: ui/BoxWindowPreviewOptions.ui:26
+#: ui/BoxWindowPreviewOptions.ui:213 ui/BoxWindowPreviewOptions.ui:254
msgid "17"
msgstr "17"
-#: ui/BoxWindowPreviewOptions.ui:27
+#: ui/BoxWindowPreviewOptions.ui:214 ui/BoxWindowPreviewOptions.ui:255
msgid "18"
msgstr "18"
-#: ui/BoxWindowPreviewOptions.ui:28
+#: ui/BoxWindowPreviewOptions.ui:215 ui/BoxWindowPreviewOptions.ui:256
msgid "19"
msgstr "19"
-#: ui/BoxWindowPreviewOptions.ui:29
+#: ui/BoxWindowPreviewOptions.ui:216 ui/BoxWindowPreviewOptions.ui:257
msgid "20"
msgstr "20"
-#: ui/BoxWindowPreviewOptions.ui:30
+#: ui/BoxWindowPreviewOptions.ui:217 ui/BoxWindowPreviewOptions.ui:258
msgid "21"
msgstr "21"
-#: ui/BoxWindowPreviewOptions.ui:31
+#: ui/BoxWindowPreviewOptions.ui:223 ui/BoxWindowPreviewOptions.ui:264
msgid "Fixed"
-msgstr "Фіксоване"
+msgstr "Стале"
-#: ui/BoxWindowPreviewOptions.ui:32
+#: ui/BoxWindowPreviewOptions.ui:233
msgid "Window previews aspect ratio Y (height)"
msgstr "Співвідношення сторін мініатюр вікон по осі У (висота)"
-#: ui/BoxWindowPreviewOptions.ui:33
+#: ui/BoxWindowPreviewOptions.ui:274
msgid "Window previews padding (px)"
-msgstr "Відступи мініатюр вікон (пкс)"
+msgstr "Відступи між мініатюрами вікон (пкс)"
-#: ui/BoxWindowPreviewOptions.ui:34
+#: ui/BoxWindowPreviewOptions.ui:296
msgid "Use custom opacity for the previews background"
-msgstr "Використати інше значення непрозорості для фону мініатюр"
+msgstr "Використати власне значення непрозорості для тла мініатюр"
-#: ui/BoxWindowPreviewOptions.ui:35
+#: ui/BoxWindowPreviewOptions.ui:297
msgid ""
"If disabled, the previews background have the same opacity as the panel."
msgstr ""
-"Якщо вимкнено, то фон мініатюр використає те саме значення непрозорості, що "
-"й панель."
+"Якщо вимкнено, то тло мініатюр буде використовувати те саме значення "
+"непрозорості, що й панель."
-#: ui/BoxWindowPreviewOptions.ui:36
+#: ui/BoxWindowPreviewOptions.ui:322
msgid "Close button and header position"
-msgstr "Позиція кнопки закриття та заголовку"
+msgstr "Розміщення заголовку та кнопки закриття"
-#: ui/BoxWindowPreviewOptions.ui:39
+#: ui/BoxWindowPreviewOptions.ui:352
msgid "Display window preview headers"
msgstr "Показувати заголовки до мініатюр вікон"
-#: ui/BoxWindowPreviewOptions.ui:40
+#: ui/BoxWindowPreviewOptions.ui:363
msgid "Icon size (px) of the window preview"
msgstr "Розмір піктограми (пкс) для мініатюри вікна"
-#: ui/BoxWindowPreviewOptions.ui:41
+#: ui/BoxWindowPreviewOptions.ui:364
msgid "If disabled, the previews icon size will be based on headerbar size"
msgstr ""
"Якщо вимкнено, то розмір піктограм в мініатюрах буде залежати від розміру "
"заголовка"
-#: ui/BoxWindowPreviewOptions.ui:42
+#: ui/BoxWindowPreviewOptions.ui:385
msgid "Font size (px) of the preview titles"
-msgstr "Розмір шрифту (пкс) "
+msgstr "Розмір шрифту (пкс) в заголовках до мініатюр"
-#: ui/BoxWindowPreviewOptions.ui:43
+#: ui/BoxWindowPreviewOptions.ui:401
msgid "Font weight of the preview titles"
msgstr "Товщина шрифту в заголовках до мініатюр"
-#: ui/BoxWindowPreviewOptions.ui:49
+#: ui/BoxWindowPreviewOptions.ui:419
msgid "Font color of the preview titles"
msgstr "Колір шрифту в заголовках до мініатюр"
-#: ui/BoxWindowPreviewOptions.ui:50
+#: ui/BoxWindowPreviewOptions.ui:437
msgid "Enable window peeking"
-msgstr "Активувати показ вікон"
+msgstr "Активувати перегляд вікон"
-#: ui/BoxWindowPreviewOptions.ui:51
+#: ui/BoxWindowPreviewOptions.ui:438
msgid ""
"When hovering over a window preview for some time, the window gets "
"distinguished."
msgstr ""
-"Показ певного вікна через деякий час після утримання курсора над його "
-"мініатюрою."
+"Після утримання курсора над вікном мініатюри деякий час, вікно буде "
+"виокремлено."
-#: ui/BoxWindowPreviewOptions.ui:52
+#: ui/BoxWindowPreviewOptions.ui:449
msgid "Enter window peeking mode timeout (ms)"
-msgstr "Затримка перед активацією режиму показу (мс)"
+msgstr "Затримка перед активацією режиму перегляду вікон (мс)"
-#: ui/BoxWindowPreviewOptions.ui:53
+#: ui/BoxWindowPreviewOptions.ui:450
msgid ""
"Time of inactivity while hovering over a window preview needed to enter the "
"window peeking mode."
msgstr ""
-"Час бездіяльності після наведення курсора на мініатюру для активації режиму "
-"показу"
+"Час бездіяльності після наведення курсора на мініатюру перед активацією "
+"режиму перегляду вікон."
-#: ui/BoxWindowPreviewOptions.ui:54
+#: ui/BoxWindowPreviewOptions.ui:455
msgid "50"
msgstr "50"
-#: ui/BoxWindowPreviewOptions.ui:55
+#: ui/BoxWindowPreviewOptions.ui:466
msgid "Window peeking mode opacity"
-msgstr "Непрозорість в режимі показу вікон"
+msgstr "Непрозорість в режимі перегляду вікон"
-#: ui/BoxWindowPreviewOptions.ui:56
+#: ui/BoxWindowPreviewOptions.ui:467
msgid ""
"All windows except for the peeked one have their opacity set to the same "
"value."
-msgstr "Всі вікна, окрім того, що "
+msgstr ""
+"Всі вікна, окрім того, що показується, мають однакове значення непрозорості."
-#: ui/SettingsAbout.ui:1
+#: ui/SettingsAbout.ui:8
msgid "About"
-msgstr "Інформація"
+msgstr "Деталі"
-#: ui/SettingsAbout.ui:2
+#: ui/SettingsAbout.ui:11
msgid "Info"
msgstr "Інформація"
-#: ui/SettingsAbout.ui:3
+#: ui/SettingsAbout.ui:14
msgid "Version"
msgstr "Версія"
-#: ui/SettingsAbout.ui:4
+#: ui/SettingsAbout.ui:22
msgid "Source"
msgstr "Вихідний код"
-#: ui/SettingsAbout.ui:5
+#: ui/SettingsAbout.ui:26
msgid "GitHub"
msgstr "GitHub"
-#: ui/SettingsAbout.ui:6
+#: ui/SettingsAbout.ui:37
msgid "Export and Import"
msgstr "Експорт та імпорт"
-#: ui/SettingsAbout.ui:7
-msgid "Export and import settings"
-msgstr "Експорт та імпорт налаштувань"
-
-#: ui/SettingsAbout.ui:8
+#: ui/SettingsAbout.ui:40
msgid ""
"Use the buttons below to create a settings file from your current "
"preferences that can be imported on a different machine."
@@ -1016,15 +1095,19 @@ msgstr ""
"Скористайтеся кнопками нижче, щоб створити файл налаштувань з вашими "
"поточними вподобаннями, який можна буде імпортувати на іншій машині."
-#: ui/SettingsAbout.ui:9
+#: ui/SettingsAbout.ui:41
+msgid "Export and import settings"
+msgstr "Експорт та імпорт налаштувань"
+
+#: ui/SettingsAbout.ui:56
msgid "Export to file"
msgstr "Експорт до файлу"
-#: ui/SettingsAbout.ui:10
+#: ui/SettingsAbout.ui:62
msgid "Import from file"
msgstr "Імпорт з файлу"
-#: ui/SettingsAbout.ui:11
+#: ui/SettingsAbout.ui:77
msgid ""
"This program comes with ABSOLUTELY NO WARRANTY.\n"
"See the GNU General Public License, version 2 or later, щоб дізнатися "
"більше."
-#: ui/SettingsAction.ui:1
+#: ui/SettingsAction.ui:8
msgid "Action"
msgstr "Дії"
-#: ui/SettingsAction.ui:2
+#: ui/SettingsAction.ui:11 ui/SettingsAction.ui:15
msgid "Click action"
-msgstr "Дія при кліку"
+msgstr "Дія під час клацання"
-#: ui/SettingsAction.ui:3
+#: ui/SettingsAction.ui:14
msgid "Behaviour when clicking on the icon of a running application."
-msgstr "Поведінка при кліку на піктограмі запущеної програми"
+msgstr "Поведінка під час клацання на піктограмі запущеної програми."
-#: ui/SettingsAction.ui:8
+#: ui/SettingsAction.ui:39
msgid "Toggle windows"
msgstr "Згортання вікон"
-#: ui/SettingsAction.ui:11
+#: ui/SettingsAction.ui:51
msgid "Scroll action"
-msgstr "Дія при гортанні"
+msgstr "Дія під час гортання"
-#: ui/SettingsAction.ui:12
-msgid "Scroll panel action"
-msgstr "Дія при гортанні над панеллю"
-
-#: ui/SettingsAction.ui:13
+#: ui/SettingsAction.ui:54
msgid "Behavior when mouse scrolling over the panel."
-msgstr "Поведінка при гортанні над панеллю"
+msgstr "Поведінка під час гортанні над панеллю."
-#: ui/SettingsAction.ui:14
+#: ui/SettingsAction.ui:55
+msgid "Scroll panel action"
+msgstr "Дія під час гортання над панеллю"
+
+#: ui/SettingsAction.ui:79 ui/SettingsAction.ui:112
msgid "Do nothing"
msgstr "Нічого не робити"
-#: ui/SettingsAction.ui:15
+#: ui/SettingsAction.ui:80
msgid "Switch workspace"
msgstr "Перемкнути робочий простір"
-#: ui/SettingsAction.ui:16
+#: ui/SettingsAction.ui:81 ui/SettingsAction.ui:113
msgid "Cycle windows"
msgstr "Циклічне перемикання вікон"
-#: ui/SettingsAction.ui:17
+#: ui/SettingsAction.ui:82
msgid "Change volume"
msgstr "Зміна гучності"
-#: ui/SettingsAction.ui:18
-msgid "Scroll icon action"
-msgstr "Дія при гортанні над піктограмою"
-
-#: ui/SettingsAction.ui:19
+#: ui/SettingsAction.ui:90
msgid "Behavior when mouse scrolling over an application icon."
-msgstr "Поведінка під час гортання над піктограмою програми"
+msgstr "Поведінка під час гортання над піктограмою програми."
-#: ui/SettingsAction.ui:20
+#: ui/SettingsAction.ui:91
+msgid "Scroll icon action"
+msgstr "Дія під час гортання над піктограмою"
+
+#: ui/SettingsAction.ui:114
msgid "Same as panel"
msgstr "Та сама, що і для панелі"
-#: ui/SettingsAction.ui:21
+#: ui/SettingsAction.ui:124
msgid "Hotkey overlay"
-msgstr "Накладання для гарячих клавіш"
+msgstr "Накладання гарячих клавіш"
-#: ui/SettingsAction.ui:22
-msgid "Use hotkeys to activate apps"
-msgstr "Використовувати гарячі клавіші для активації програм"
-
-#: ui/SettingsAction.ui:23
+#: ui/SettingsAction.ui:127
msgid ""
"Enable Super+(0-9) as shortcuts to activate apps. It can also be used "
"together with Shift and Ctrl."
@@ -1107,343 +1186,397 @@ msgstr ""
"Використовувати клавіші Super+(0-9) для активації програм. Також можна "
"комбінувати з клавішами Shift та Ctrl."
-#: ui/SettingsBehavior.ui:1
+#: ui/SettingsAction.ui:128
+msgid "Use hotkeys to activate apps"
+msgstr "Використовувати гарячі клавіші для активації програм"
+
+#: ui/SettingsAction.ui:154
+msgid "Application icons context menu"
+msgstr "Контекстне меню піктограм програм"
+
+#: ui/SettingsAction.ui:157
+msgid "(right-click menu)"
+msgstr "(меню правої клавіші)"
+
+#: ui/SettingsAction.ui:158
+msgid "Secondary menu"
+msgstr "Контекстне меню"
+
+#: ui/SettingsAction.ui:179
+msgid "Panel context menu entries"
+msgstr "Пункти контекстного меню панелі"
+
+#: ui/SettingsAction.ui:190
+msgid "Add entry"
+msgstr "Додати пункт"
+
+#: ui/SettingsBehavior.ui:5
msgid "Behavior"
msgstr "Поведінка"
-#: ui/SettingsBehavior.ui:2
+#: ui/SettingsBehavior.ui:11
msgid "Applications"
msgstr "Програми"
-#: ui/SettingsBehavior.ui:3
+#: ui/SettingsBehavior.ui:15
msgid "Show favorite applications"
msgstr "Показувати улюблені програми"
-#: ui/SettingsBehavior.ui:4
+#: ui/SettingsBehavior.ui:26
msgid "Show favorite applications on secondary panels"
msgstr "Показувати улюблені програми на додаткових панелях"
-#: ui/SettingsBehavior.ui:5
+#: ui/SettingsBehavior.ui:37
msgid "Show running applications"
msgstr "Показувати запущені програми"
-#: ui/SettingsBehavior.ui:6
+#: ui/SettingsBehavior.ui:48
msgid "Ungroup applications"
msgstr "Розгрупувати програми"
-#: ui/SettingsBehavior.ui:7
+#: ui/SettingsBehavior.ui:73
msgid "Show notification counter badge"
msgstr "Показувати лічильник сповіщень"
-#: ui/SettingsBehavior.ui:8
+#: ui/SettingsBehavior.ui:90
msgid "Hover"
msgstr "Наведення"
-#: ui/SettingsBehavior.ui:9
+#: ui/SettingsBehavior.ui:94
msgid "Show window previews on hover"
-msgstr "Показувати мініатюри вікон при наведенні"
+msgstr "Показувати мініатюри вікон під час наведення"
-#: ui/SettingsBehavior.ui:10
+#: ui/SettingsBehavior.ui:119
msgid "Show tooltip on hover"
-msgstr "Показувати підказки при наведенні"
+msgstr "Показувати підказки під час наведення"
-#: ui/SettingsBehavior.ui:11
+#: ui/SettingsBehavior.ui:134
msgid "Isolate"
msgstr "Ізоляція"
-#: ui/SettingsBehavior.ui:12
+#: ui/SettingsBehavior.ui:138
msgid "Isolate Workspaces"
msgstr "Ізолювати робочі простори"
-#: ui/SettingsBehavior.ui:13
+#: ui/SettingsBehavior.ui:149
msgid "Isolate monitors"
msgstr "Ізолювати монітори"
-#: ui/SettingsBehavior.ui:14
+#: ui/SettingsBehavior.ui:164
msgid "Overview"
msgstr "Огляд"
-#: ui/SettingsBehavior.ui:15
+#: ui/SettingsBehavior.ui:168
msgid "Click empty space to close overview"
-msgstr "Клік на пустому місці закриває «Огляд»"
+msgstr "Клацання на пустому місці закриває «Огляд»"
-#: ui/SettingsBehavior.ui:16
+#: ui/SettingsBehavior.ui:179
msgid "Disable show overview on startup"
msgstr "Не показувати «Огляд» під час запуску"
-#: ui/SettingsFineTune.ui:1
+#: ui/SettingsFineTune.ui:38
msgid "Fine-Tune"
msgstr "Доналаштування"
-#: ui/SettingsFineTune.ui:2
+#: ui/SettingsFineTune.ui:41
msgid "Font size"
msgstr "Розмір шрифту"
-#: ui/SettingsFineTune.ui:3
-msgid "Tray Font Size"
-msgstr "Розмір шрифту лотка"
-
-#: ui/SettingsFineTune.ui:4
+#: ui/SettingsFineTune.ui:44 ui/SettingsFineTune.ui:60
msgid "(0 = theme default)"
msgstr "(0 = як в темі)"
-#: ui/SettingsFineTune.ui:5
-msgid "LeftBox Font Size"
-msgstr "Розмір шрифту лівого блоку"
+#: ui/SettingsFineTune.ui:45
+msgid "Tray Font Size"
+msgstr "Розмір шрифту лотка"
-#: ui/SettingsFineTune.ui:6
+#: ui/SettingsFineTune.ui:61
+msgid "LeftBox Font Size"
+msgstr "Розмір шрифту лівого блока"
+
+#: ui/SettingsFineTune.ui:78
msgid "Padding"
msgstr "Внутрішні відступи"
-#: ui/SettingsFineTune.ui:7
-msgid "Tray Item Padding"
-msgstr "Відступи між елементами лотка"
-
-#: ui/SettingsFineTune.ui:8
+#: ui/SettingsFineTune.ui:81 ui/SettingsFineTune.ui:97
+#: ui/SettingsFineTune.ui:113
msgid "(-1 = theme default)"
msgstr "(-1 = як в темі)"
-#: ui/SettingsFineTune.ui:9
+#: ui/SettingsFineTune.ui:82
+msgid "Tray Item Padding"
+msgstr "Відступи між елементами лотка"
+
+#: ui/SettingsFineTune.ui:98
msgid "Status Icon Padding"
msgstr "Відступи між піктограмами в рядку стану"
-#: ui/SettingsFineTune.ui:10
+#: ui/SettingsFineTune.ui:114
msgid "LeftBox Padding"
-msgstr "Відступи лівого блоку"
+msgstr "Відступи лівого блока"
-#: ui/SettingsFineTune.ui:11
+#: ui/SettingsFineTune.ui:131
msgid "Animate"
msgstr "Анімації"
-#: ui/SettingsFineTune.ui:12
+#: ui/SettingsFineTune.ui:134
msgid "Animate switching applications"
-msgstr "Анімувати перемикання між програмами"
+msgstr "Анімація перемикання між програмами"
-#: ui/SettingsFineTune.ui:13
+#: ui/SettingsFineTune.ui:144
msgid "Animate launching new windows"
-msgstr "Анімувати запуск нових вікон"
+msgstr "Анімація запуску нових вікон"
-#: ui/SettingsFineTune.ui:14
+#: ui/SettingsFineTune.ui:156
msgid "Gnome functionality"
msgstr "Функціонал GNOME"
-#: ui/SettingsFineTune.ui:15
-msgid "Keep original gnome-shell dash"
-msgstr "Зберегти оригінальну панель програм gnome-shell"
-
-#: ui/SettingsFineTune.ui:16
+#: ui/SettingsFineTune.ui:159
msgid "(overview)"
msgstr "(огляд)"
-#: ui/SettingsFineTune.ui:17
+#: ui/SettingsFineTune.ui:160
+msgid "Keep original gnome-shell dash"
+msgstr "Зберегти оригінальну панель програм оболонки GNOME"
+
+#: ui/SettingsFineTune.ui:170
msgid "Keep original gnome-shell top panel"
-msgstr "Зберегти оригінальну верхню панель gnome-shell"
+msgstr "Зберегти оригінальну верхню панель оболонки GNOME"
-#: ui/SettingsFineTune.ui:18
-msgid "Activate panel menu buttons on click only"
-msgstr "Кнопки меню на панелі активуються лише при кліку"
-
-#: ui/SettingsFineTune.ui:19
+#: ui/SettingsFineTune.ui:180
msgid "(e.g. date menu)"
msgstr "(напр., меню дати)"
-#: ui/SettingsFineTune.ui:20
+#: ui/SettingsFineTune.ui:181
+msgid "Activate panel menu buttons on click only"
+msgstr "Активувати кнопки меню панелі лише під час клацання"
+
+#: ui/SettingsFineTune.ui:191
msgid "Force Activities hot corner on primary monitor"
msgstr "Примусово розмістити гарячий кут «Діяльності» на основному моніторі"
-#: ui/SettingsFineTune.ui:21
-msgid "App icon secondary menu"
-msgstr "Контекстне меню піктограм програм"
-
-#: ui/SettingsFineTune.ui:22
-msgid "(right-click menu)"
-msgstr "(меню правої кнопки)"
-
-#: ui/SettingsPosition.ui:1
+#: ui/SettingsPosition.ui:19
msgid "Position"
msgstr "Розміщення"
-#: ui/SettingsPosition.ui:2
+#: ui/SettingsPosition.ui:22
msgid "Panel"
msgstr "Панель"
-#: ui/SettingsPosition.ui:3
+#: ui/SettingsPosition.ui:25
msgid "Display the main panel on"
msgstr "Головна панель присутня на"
-#: ui/SettingsPosition.ui:4
+#: ui/SettingsPosition.ui:35
msgid "Display panels on all monitors"
-msgstr "Панель присутня на всіх моніторах"
+msgstr "Показувати панелі на всіх моніторах"
-#: ui/SettingsPosition.ui:5
-msgid "Panel Intellihide"
-msgstr "Інтелектуальне приховування панелі"
-
-#: ui/SettingsPosition.ui:6
+#: ui/SettingsPosition.ui:49
msgid "Hide and reveal the panel according to preferences"
-msgstr "Приховувати та виводити панель залежно від налаштувань"
+msgstr "Приховувати та показувати панель залежно від налаштувань"
-#: ui/SettingsPosition.ui:7
+#: ui/SettingsPosition.ui:50
+msgid "Panel Intellihide"
+msgstr "Розумне приховування панелі"
+
+#: ui/SettingsPosition.ui:76
msgid "Order and Position on monitors"
msgstr "Порядок та розміщення на моніторах"
-#: ui/SettingsPosition.ui:8
+#: ui/SettingsPosition.ui:79
msgid "Monitor"
msgstr "Монітор"
-#: ui/SettingsPosition.ui:9
+#: ui/SettingsPosition.ui:90
msgid "Apply changes to all monitors"
msgstr "Застосовувати зміни на всіх моніторах"
-#: ui/SettingsPosition.ui:10
+#: ui/SettingsPosition.ui:111
msgid "Panel screen position"
msgstr "Розміщення панелі на екрані"
-#: ui/SettingsPosition.ui:15
-msgid "Panel thickness"
-msgstr "Товщина панелі"
-
-#: ui/SettingsPosition.ui:16
+#: ui/SettingsPosition.ui:152
msgid "(default is 48)"
msgstr "(типово - 48)"
-#: ui/SettingsPosition.ui:18
-#, no-c-format
-msgid "Panel length (%)"
-msgstr "Довжина панелі (%)"
+#: ui/SettingsPosition.ui:153
+msgid "Panel thickness"
+msgstr "Товщина панелі"
-#: ui/SettingsPosition.ui:19
+#: ui/SettingsPosition.ui:168
msgid "(default is 100)"
msgstr "(типово - 100)"
-#: ui/SettingsPosition.ui:20
+#: ui/SettingsPosition.ui:169
+msgid "Panel length"
+msgstr "Довжина панелі"
+
+#: ui/SettingsPosition.ui:174
+msgid "Dynamic"
+msgstr "Динамічна"
+
+#: ui/SettingsPosition.ui:192
msgid "Anchor"
msgstr "Вирівнювання"
-#: ui/SettingsPosition.ui:24
+#: ui/SettingsPosition.ui:211
msgid "Taskbar Display"
msgstr "Показ панелі завдань"
-#: ui/SettingsStyle.ui:1
+#: ui/SettingsStyle.ui:59
msgid "Style"
msgstr "Стиль"
-#: ui/SettingsStyle.ui:2
+#: ui/SettingsStyle.ui:62
+msgid "Global style"
+msgstr "Глобальний стиль"
+
+#: ui/SettingsStyle.ui:65
+msgid "Border radius"
+msgstr "Радіус межі"
+
+#: ui/SettingsStyle.ui:82
msgid "AppIcon style"
msgstr "Стиль піктограм програм"
-#: ui/SettingsStyle.ui:3
-msgid "App Icon Margin"
-msgstr "Зовнішні відступи піктограм"
-
-#: ui/SettingsStyle.ui:4
+#: ui/SettingsStyle.ui:85
msgid "(default is 8)"
msgstr "(типово - 8)"
-#: ui/SettingsStyle.ui:5
-msgid "App Icon Padding"
-msgstr "Внутрішні відступи піктограм"
+#: ui/SettingsStyle.ui:86
+msgid "App Icon Margin"
+msgstr "Зовнішні відступи піктограм програм"
-#: ui/SettingsStyle.ui:6
+#: ui/SettingsStyle.ui:101
msgid "(default is 4)"
msgstr "(типово - 4)"
-#: ui/SettingsStyle.ui:7
-msgid "Animate hovering app icons"
-msgstr "Анімувати перемикання між програмами"
+#: ui/SettingsStyle.ui:102
+msgid "App Icon Padding"
+msgstr "Відступи між піктограмами програм"
-#: ui/SettingsStyle.ui:8
+#: ui/SettingsStyle.ui:117
+msgid "Animate hovering app icons"
+msgstr "Анімація під час наведення на піктограми програмами"
+
+#: ui/SettingsStyle.ui:141
+msgid "Highlight hovering app icons"
+msgstr "Підсвічування піктограм програм під час наведення"
+
+#: ui/SettingsStyle.ui:165
msgid "Icon style"
msgstr "Стиль піктограм"
-#: ui/SettingsStyle.ui:9
+#: ui/SettingsStyle.ui:170
msgid "Normal"
msgstr "Звичайний"
-#: ui/SettingsStyle.ui:10
+#: ui/SettingsStyle.ui:171
msgid "Symbolic"
msgstr "Символьний"
-#: ui/SettingsStyle.ui:11
-msgid "Running indicator"
-msgstr "Індикатора роботи"
+#: ui/SettingsStyle.ui:172
+msgid "Grayscale"
+msgstr "Відтінки сірого"
-#: ui/SettingsStyle.ui:12
+#: ui/SettingsStyle.ui:182
+msgid "Running indicator"
+msgstr "Індикатор роботи"
+
+#: ui/SettingsStyle.ui:185
msgid "Running indicator position"
msgstr "Розміщення індикатора роботи"
-#: ui/SettingsStyle.ui:17
+#: ui/SettingsStyle.ui:221
msgid "Running indicator style (Focused app)"
-msgstr "Стиль індикатора роботи (програма у фокусі)"
+msgstr "Стиль індикатора роботи (для програми у фокусі)"
-#: ui/SettingsStyle.ui:18
+#: ui/SettingsStyle.ui:239 ui/SettingsStyle.ui:258
msgid "Dots"
msgstr "Крапки"
-#: ui/SettingsStyle.ui:19
+#: ui/SettingsStyle.ui:240 ui/SettingsStyle.ui:259
msgid "Squares"
msgstr "Квадрати"
-#: ui/SettingsStyle.ui:20
+#: ui/SettingsStyle.ui:241 ui/SettingsStyle.ui:260
msgid "Dashes"
msgstr "Рисочки"
-#: ui/SettingsStyle.ui:21
+#: ui/SettingsStyle.ui:242 ui/SettingsStyle.ui:261
msgid "Segmented"
msgstr "Сегментований"
-#: ui/SettingsStyle.ui:22
+#: ui/SettingsStyle.ui:243 ui/SettingsStyle.ui:262
msgid "Solid"
msgstr "Суцільний"
-#: ui/SettingsStyle.ui:23
+#: ui/SettingsStyle.ui:244 ui/SettingsStyle.ui:263
msgid "Ciliora"
-msgstr "Циліора"
+msgstr "Вії"
-#: ui/SettingsStyle.ui:24
+#: ui/SettingsStyle.ui:245 ui/SettingsStyle.ui:264
msgid "Metro"
msgstr "Метро"
-#: ui/SettingsStyle.ui:25
+#: ui/SettingsStyle.ui:253
msgid "Running indicator style (Unfocused apps)"
-msgstr "Стиль індикатора роботи (програма не у фокусі)"
+msgstr "Стиль індикатора роботи (для програми не у фокусі)"
-#: ui/SettingsStyle.ui:26
+#: ui/SettingsStyle.ui:274
msgid "Panel style"
msgstr "Стиль панелі"
-#: ui/SettingsStyle.ui:27
+#: ui/SettingsStyle.ui:277 ui/SettingsStyle.ui:293 ui/SettingsStyle.ui:309
+#: ui/SettingsStyle.ui:325
+msgid "(default is 0)"
+msgstr "(типово - 0)"
+
+#: ui/SettingsStyle.ui:278
+msgid "Side margins"
+msgstr "Бічні зовнішні відступи"
+
+#: ui/SettingsStyle.ui:294
+msgid "Top and bottom margins"
+msgstr "Верхній та нижній зовнішні відступи"
+
+#: ui/SettingsStyle.ui:310
+msgid "Side padding"
+msgstr "Бічні внутрішні відступи"
+
+#: ui/SettingsStyle.ui:326
+msgid "Top and bottom padding"
+msgstr "Верхній та нижній внутрішні відступи"
+
+#: ui/SettingsStyle.ui:345
msgid "Override panel theme background color"
msgstr "Зміна кольору тла панелі (типово - як в темі)"
-#: ui/SettingsStyle.ui:28
+#: ui/SettingsStyle.ui:360
msgid "Override panel theme background opacity"
msgstr "Зміна непрозорості тла панелі (типово - як в темі)"
-#: ui/SettingsStyle.ui:30
-#, no-c-format
+#: ui/SettingsStyle.ui:370
msgid "Panel background opacity (%)"
msgstr "Непрозорість тла панелі (%)"
-#: ui/SettingsStyle.ui:32
-msgid "Dynamic background opacity"
-msgstr "Динамічна непрозорість тла"
-
-#: ui/SettingsStyle.ui:33
+#: ui/SettingsStyle.ui:382
msgid "Change opacity when a window gets close to the panel"
msgstr "Зміна непрозорості, коли вікно наближається до панелі"
-#: ui/SettingsStyle.ui:34
-msgid "Override panel theme gradient"
-msgstr "Зміна градієнта панелі (типово - як в темі)"
+#: ui/SettingsStyle.ui:383
+msgid "Dynamic background opacity"
+msgstr "Динамічна непрозорість тла"
-#: ui/SettingsStyle.ui:36
-#, no-c-format
+#: ui/SettingsStyle.ui:411
+msgid "Override panel theme gradient"
+msgstr "Зміна градієнта панелі"
+
+#: ui/SettingsStyle.ui:421
msgid "Gradient top color and opacity (%)"
msgstr "Колір та непрозорість градієнта вгорі (%)"
-#: ui/SettingsStyle.ui:38
-#, no-c-format
+#: ui/SettingsStyle.ui:439
msgid "Gradient bottom color and opacity (%)"
msgstr "Колір та непрозорість градієнта знизу (%)"
@@ -1452,6 +1585,3 @@ msgstr "Показати значок робочого столу"
msgid "Show Desktop button padding (px)"
msgstr "Відступ Показати кнопку робочого столу (px)"
-
-msgid "Floating rounded theme"
-msgstr "Плаваюча округла тема"
diff --git a/po/vi.po b/po/vi.po
index c68a5e6..cee7b7f 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -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"
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 367a73b..d0fef77 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -1441,9 +1441,6 @@ msgstr "显示桌面图标"
msgid "Show Desktop button padding (px)"
msgstr "“显示桌面按钮”的内边距(px)"
-msgid "Floating rounded theme"
-msgstr "悬浮圆角主题"
-
#, javascript-format
#~ msgid "%d ."
#~ msgstr "%d ."
diff --git a/po/zh_TW.po b/po/zh_TW.po
index 7396ee9..0547580 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -1498,9 +1498,6 @@ msgstr "顯示桌面圖示"
msgid "Show Desktop button padding (px)"
msgstr "顯示桌面按鈕 空間 (像素)"
-msgid "Floating rounded theme"
-msgstr "浮動圓滑主題"
-
#~ msgid "Show Details"
#~ msgstr "顯示詳細資訊"
diff --git a/prefs.js b/prefs.js
deleted file mode 100644
index a40d5fe..0000000
--- a/prefs.js
+++ /dev/null
@@ -1,1170 +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 .
- *
- *
- * 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 GdkPixbuf from 'gi://GdkPixbuf';
-import Gio from 'gi://Gio';
-import GLib from 'gi://GLib';
-import GObject from 'gi://GObject';
-import Gtk from 'gi://Gtk';
-import Gdk from 'gi://Gdk';
-
-import * as PanelSettings from './panelSettings.js';
-import * as Pos from './panelPositions.js';
-
-import {ExtensionPreferences, gettext as _, ngettext} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
-
-const SCALE_UPDATE_TIMEOUT = 500;
-const DEFAULT_PANEL_SIZES = [ 96, 64, 48, 32, 24 ];
-const DEFAULT_MARGIN_SIZES = [ 32, 24, 16, 12, 8, 4, 0 ];
-const DEFAULT_PADDING_SIZES = [ 32, 24, 16, 12, 8, 4, 0, -1 ];
-// Minimum length could be 0, but a higher value may help prevent confusion about where the panel went.
-const LENGTH_MARKS = [ 100, 90, 80, 70, 60, 50, 40, 30, 20, 10 ];
-
-const SCHEMA_PATH = '/org.gnome.shell.extensions.zorin-taskbar/';
-
-/**
- * This function was copied from the activities-config extension
- * https://github.com/nls1729/acme-code/tree/master/activities-config
- * by Norman L. Smith.
- */
-function cssHexString(css) {
- let rrggbb = '#';
- let start;
- for (let loop = 0; loop < 3; loop++) {
- let end = 0;
- let xx = '';
- for (let loop = 0; loop < 2; loop++) {
- while (true) {
- let x = css.slice(end, end + 1);
- if ((x == '(') || (x == ',') || (x == ')'))
- break;
- end++;
- }
- if (loop == 0) {
- end++;
- start = end;
- }
- }
- xx = parseInt(css.slice(start, end)).toString(16);
- if (xx.length == 1)
- xx = '0' + xx;
- rrggbb += xx;
- css = css.slice(end);
- }
- return rrggbb;
-}
-
-function setShortcut(settings, shortcutName) {
- let shortcut_text = settings.get_string(shortcutName + '-text');
- let [success, key, mods] = Gtk.accelerator_parse(shortcut_text);
-
- if (success && Gtk.accelerator_valid(key, mods)) {
- let shortcut = Gtk.accelerator_name(key, mods);
- settings.set_strv(shortcutName, [shortcut]);
- }
- else {
- settings.set_strv(shortcutName, []);
- }
-}
-
-function checkHotkeyPrefix(settings) {
- settings.delay();
-
- let hotkeyPrefix = settings.get_string('hotkey-prefix-text');
- if (hotkeyPrefix == 'Super')
- hotkeyPrefix = '';
- else if (hotkeyPrefix == 'SuperAlt')
- hotkeyPrefix = '';
- let [ , , mods] = Gtk.accelerator_parse(hotkeyPrefix);
- let [ , , shift_mods] = Gtk.accelerator_parse('' + hotkeyPrefix);
- let [ , , ctrl_mods] = Gtk.accelerator_parse('' + hotkeyPrefix);
-
- let numHotkeys = 10;
- for (let i = 1; i <= numHotkeys; i++) {
- let number = i;
- if (number == 10)
- number = 0;
- let key = Gdk.keyval_from_name(number.toString());
- let key_kp = Gdk.keyval_from_name('KP_' + number.toString());
- if (Gtk.accelerator_valid(key, mods)) {
- let shortcut = Gtk.accelerator_name(key, mods);
- let shortcut_kp = Gtk.accelerator_name(key_kp, mods);
-
- // Setup shortcut strings
- settings.set_strv('app-hotkey-' + i, [shortcut]);
- settings.set_strv('app-hotkey-kp-' + i, [shortcut_kp]);
-
- // With
- shortcut = Gtk.accelerator_name(key, shift_mods);
- shortcut_kp = Gtk.accelerator_name(key_kp, shift_mods);
- settings.set_strv('app-shift-hotkey-' + i, [shortcut]);
- settings.set_strv('app-shift-hotkey-kp-' + i, [shortcut_kp]);
-
- // With
- shortcut = Gtk.accelerator_name(key, ctrl_mods);
- shortcut_kp = Gtk.accelerator_name(key_kp, ctrl_mods);
- settings.set_strv('app-ctrl-hotkey-' + i, [shortcut]);
- settings.set_strv('app-ctrl-hotkey-kp-' + i, [shortcut_kp]);
- }
- else {
- // Reset default settings for the relevant keys if the
- // accelerators are invalid
- let keys = ['app-hotkey-' + i, 'app-shift-hotkey-' + i, 'app-ctrl-hotkey-' + i, // Regular numbers
- 'app-hotkey-kp-' + i, 'app-shift-hotkey-kp-' + i, 'app-ctrl-hotkey-kp-' + i]; // Key-pad numbers
- keys.forEach(function(val) {
- settings.set_value(val, settings.get_default_value(val));
- }, this);
- }
- }
-
- settings.apply();
-}
-
-function mergeObjects(main, bck) {
- for (const prop in bck) {
- if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) {
- main[prop] = bck[prop];
- }
- }
-
- return main;
-}
-
-const Preferences = class {
-
- constructor(window, settings, gnomeInterfaceSettings, path) {
- // this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.zorin-taskbar');
- this._rtl = (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL);
- this._builder = new Gtk.Builder();
- this._builder.set_scope(new BuilderScope(this));
- this._settings = settings;
- this._gnomeInterfaceSettings = gnomeInterfaceSettings;
- this._path = path;
-
- this._metadata = ExtensionPreferences.lookupByURL(import.meta.url).metadata;
- this._builder.set_translation_domain(this._metadata['gettext-domain']);
-
- window.set_search_enabled(true);
-
- // dialogs
- this._builder.add_from_file(this._path + '/ui/BoxShowDesktopOptions.ui');
- this._builder.add_from_file(this._path + '/ui/BoxDynamicOpacityOptions.ui');
- this._builder.add_from_file(this._path + '/ui/BoxIntellihideOptions.ui');
- this._builder.add_from_file(this._path + '/ui/BoxShowDateMenuOptions.ui');
- this._builder.add_from_file(this._path + '/ui/BoxWindowPreviewOptions.ui');
- this._builder.add_from_file(this._path + '/ui/BoxGroupAppsOptions.ui');
- this._builder.add_from_file(this._path + '/ui/BoxMiddleClickOptions.ui');
- this._builder.add_from_file(this._path + '/ui/BoxOverlayShortcut.ui');
-
- // pages
- this._builder.add_from_file(this._path + '/ui/SettingsStyle.ui');
- let pageStyle = this._builder.get_object('style');
- window.add(pageStyle);
-
- this._builder.add_from_file(this._path + '/ui/SettingsPosition.ui');
- let pagePosition = this._builder.get_object('position');
- window.add(pagePosition);
-
- this._builder.add_from_file(this._path + '/ui/SettingsBehavior.ui');
- let pageBehavior = this._builder.get_object('behavior');
- window.add(pageBehavior);
-
- this._builder.add_from_file(this._path + '/ui/SettingsAction.ui');
- let pageAction = this._builder.get_object('action');
- window.add(pageAction);
-
- let listbox = this._builder.get_object('taskbar_display_listbox');
- let provider = new Gtk.CssProvider();
- provider.load_from_data('list { background-color: transparent; }', -1);
- let context = listbox.get_style_context();
- context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-
- // set the window as notebook, it is being used as parent for dialogs
- this.notebook = window;
-
- // Timeout to delay the update of the settings
- this._panel_size_timeout = 0;
- this._dot_height_timeout = 0;
- this._opacity_timeout = 0;
- this._addFormatValueCallbacks();
- this._bindSettings();
- }
-
- /**
- * Connect signals
- */
- _connector(builder, object, signal, handler) {
- object.connect(signal, this._SignalHandler[handler].bind(this));
- }
-
- _updateVerticalRelatedOptions() {
- let position = this._getPanelPosition(this._currentMonitorIndex);
- let isVertical = position == Pos.LEFT || position == Pos.RIGHT;
- let showDesktopWidthLabel = this._builder.get_object('show_showdesktop_width_label');
-
- showDesktopWidthLabel.set_title(_('Show Desktop button padding (px)'));
-
- this._displayPanelPositionsForMonitor(this._currentMonitorIndex);
- }
-
- _maybeDisableTopPosition() {
- let keepTopPanel = this._settings.get_boolean('stockgs-keep-top-panel');
- let monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync');
- let topAvailable = !keepTopPanel || (!monitorSync && this._currentMonitorIndex != this.monitors[0]);
- let topRadio = this._builder.get_object('position_top_button');
-
- topRadio.set_sensitive(topAvailable);
- topRadio.set_tooltip_text(!topAvailable ? _('Unavailable when gnome-shell top panel is present') : '');
- }
-
- _getPanelPosition(monitorIndex) {
- return PanelSettings.getPanelPosition(this._settings, monitorIndex);
- }
-
- _setPanelPosition(position) {
- const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync');
- const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex];
- monitorsToSetFor.forEach(monitorIndex => {
- PanelSettings.setPanelPosition(this._settings, monitorIndex, position);
- });
- this._setAnchorLabels(this._currentMonitorIndex);
- }
-
- _setPositionRadios(position) {
- this._ignorePositionRadios = true;
-
- switch (position) {
- case Pos.BOTTOM:
- this._builder.get_object('position_bottom_button').set_active(true);
- break;
- case Pos.TOP:
- this._builder.get_object('position_top_button').set_active(true);
- break;
- case Pos.LEFT:
- this._builder.get_object('position_left_button').set_active(true);
- break;
- case Pos.RIGHT:
- this._builder.get_object('position_right_button').set_active(true);
- break;
- }
-
- this._ignorePositionRadios = false;
- }
-
- /**
- * Set panel anchor combo labels according to whether the monitor's panel is vertical
- * or horizontal, or if all monitors' panels are being configured and they are a mix
- * of vertical and horizontal.
- */
- _setAnchorLabels(currentMonitorIndex) {
- const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync');
- const monitorsToSetFor = monitorSync ? this.monitors : [currentMonitorIndex];
- const allVertical = monitorsToSetFor.every(i => {
- const position = PanelSettings.getPanelPosition(this._settings, i);
- return position === Pos.LEFT || position === Pos.RIGHT
- });
- const allHorizontal = monitorsToSetFor.every(i => {
- const position = PanelSettings.getPanelPosition(this._settings, i);
- return position === Pos.TOP || position === Pos.BOTTOM;
- });
-
- const anchor_combo = this._builder.get_object('panel_anchor_combo');
- anchor_combo.remove_all();
-
- if (allHorizontal) {
- anchor_combo.append(Pos.START, _('Left'));
- anchor_combo.append(Pos.MIDDLE, _('Center'));
- anchor_combo.append(Pos.END, _('Right'));
- } else if (allVertical) {
- anchor_combo.append(Pos.START, _('Top'));
- anchor_combo.append(Pos.MIDDLE, _('Middle'));
- anchor_combo.append(Pos.END, _('Bottom'));
- } else {
- // Setting for a mix of horizontal and vertical panels on different monitors.
- anchor_combo.append(Pos.START, _('Start'));
- anchor_combo.append(Pos.MIDDLE, _('Middle'));
- anchor_combo.append(Pos.END, _('End'));
- }
-
- // Set combo box after re-populating its options. But only if it's for a single-panel
- // configuration, or a multi-panel configuration where they all have the same anchor
- // setting. So don't set the combo box if there is a multi-panel configuration with
- // different anchor settings.
- const someAnchor = PanelSettings.getPanelAnchor(this._settings, currentMonitorIndex);
- if (monitorsToSetFor.every(i =>
- PanelSettings.getPanelAnchor(this._settings, i) === someAnchor)) {
- const panel_anchor = PanelSettings.getPanelAnchor(this._settings, currentMonitorIndex);
- this._builder.get_object('panel_anchor_combo').set_active_id(panel_anchor);
- }
- }
-
- /**
- * When a monitor is selected, update the widgets for panel position, size, anchoring,
- * and contents so they accurately show the settings for the panel on that monitor.
- */
- _updateWidgetSettingsForMonitor(monitorIndex) {
- // Update display of panel screen position setting
- this._maybeDisableTopPosition();
- const panelPosition = this._getPanelPosition(monitorIndex);
- this._setPositionRadios(panelPosition);
-
- // Update display of thickness, length, and anchor settings
- const panel_size_scale = this._builder.get_object('panel_size_scale');
- const size = PanelSettings.getPanelSize(this._settings, monitorIndex);
- panel_size_scale.set_value(size);
-
- const panel_length_scale = this._builder.get_object('panel_length_scale');
- const length = PanelSettings.getPanelLength(this._settings, monitorIndex);
- panel_length_scale.set_value(length);
- this._setAnchorWidgetSensitivity(length);
-
- this._setAnchorLabels(monitorIndex);
-
- // Update display of panel content settings
- this._displayPanelPositionsForMonitor(monitorIndex);
- }
-
- /**
- * Anchor is only relevant if panel length is less than 100%. Enable or disable
- * anchor widget sensitivity accordingly.
- */
- _setAnchorWidgetSensitivity(panelLength) {
- const isPartialLength = panelLength < 100;
- this._builder.get_object('panel_anchor_label').set_sensitive(isPartialLength);
- this._builder.get_object('panel_anchor_combo').set_sensitive(isPartialLength);
- }
-
- _displayPanelPositionsForMonitor(monitorIndex) {
- let taskbarListBox = this._builder.get_object('taskbar_display_listbox');
-
- while(taskbarListBox.get_first_child())
- {
- taskbarListBox.remove(taskbarListBox.get_first_child());
- }
-
- let labels = {};
- let panelPosition = this._getPanelPosition(monitorIndex);
- let isVertical = panelPosition == Pos.LEFT || panelPosition == Pos.RIGHT;
- let panelElementPositionsSettings = PanelSettings.getSettingsJson(this._settings, 'panel-element-positions');
- let panelElementPositions = panelElementPositionsSettings[monitorIndex] || Pos.defaults;
- let updateElementsSettings = () => {
- let newPanelElementPositions = [];
- let monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync');
- let monitors = monitorSync ? this.monitors : [monitorIndex];
-
- let child = taskbarListBox.get_first_child();
- while (child != null)
- {
- newPanelElementPositions.push({
- element: child.id,
- visible: child.visibleToggleBtn.get_active(),
- position: child.positionCombo.get_active_id()
- });
- child = child.get_next_sibling();
- }
-
- monitors.forEach(m => panelElementPositionsSettings[m] = newPanelElementPositions);
- this._settings.set_string('panel-element-positions', JSON.stringify(panelElementPositionsSettings));
- };
-
-
- labels[Pos.SHOW_APPS_BTN] = _('Show Applications button');
- labels[Pos.ACTIVITIES_BTN] = _('Activities button');
- labels[Pos.TASKBAR] = _('Taskbar');
- labels[Pos.DATE_MENU] = _('Date menu');
- labels[Pos.SYSTEM_MENU] = _('System menu');
- labels[Pos.LEFT_BOX] = _('Left box');
- labels[Pos.CENTER_BOX] = _('Center box');
- labels[Pos.RIGHT_BOX] = _('Right box');
- labels[Pos.DESKTOP_BTN] = _('Desktop button');
-
- panelElementPositions.forEach(el => {
- let row = new Gtk.ListBoxRow();
- let grid = new Gtk.Grid({ margin_start: 12, margin_end: 12, column_spacing: 8 });
- let upDownGrid = new Gtk.Grid({ column_spacing: 2 });
- let upBtn = new Gtk.Button({ tooltip_text: _('Move up') });
- let upImg = new Gtk.Image({ icon_name: 'go-up-symbolic', pixel_size: 12 });
- let downBtn = new Gtk.Button({ tooltip_text: _('Move down') });
- let downImg = new Gtk.Image({ icon_name: 'go-down-symbolic', pixel_size: 12 });
- let visibleToggleBtn = new Gtk.ToggleButton({ label: _('Visible'), active: el.visible });
- let positionCombo = new Gtk.ComboBoxText({ tooltip_text: _('Select element position') });
- let upDownClickHandler = limit => {
- let index = row.get_index();
-
- if (index != limit) {
- taskbarListBox.remove(row);
- taskbarListBox.insert(row, index + (!limit ? -1 : 1));
- updateElementsSettings();
- }
- };
-
- positionCombo.append(Pos.STACKED_TL, isVertical ? _('Stacked to top') : _('Stacked to left'));
- positionCombo.append(Pos.STACKED_BR, isVertical ? _('Stacked to bottom') :_('Stacked to right'));
- positionCombo.append(Pos.CENTERED, _('Centered'));
- positionCombo.append(Pos.CENTERED_MONITOR, _('Monitor Center'));
- positionCombo.set_active_id(el.position);
-
- upBtn.connect('clicked', () => upDownClickHandler(0));
- downBtn.connect('clicked', () => upDownClickHandler(panelElementPositions.length - 1));
- visibleToggleBtn.connect('toggled', () => updateElementsSettings());
- positionCombo.connect('changed', () => updateElementsSettings());
-
- upBtn.set_child(upImg);
- downBtn.set_child(downImg);
-
- upDownGrid.attach(upBtn, 0, 0, 1, 1);
- upDownGrid.attach(downBtn, 1, 0, 1, 1);
-
- grid.attach(upDownGrid, 0, 0, 1, 1);
- grid.attach(new Gtk.Label({ label: labels[el.element], xalign: 0, hexpand: true }), 1, 0, 1, 1);
-
- if (Pos.optionDialogFunctions[el.element]) {
- let cogImg = new Gtk.Image({ icon_name: 'emblem-system-symbolic' });
- let optionsBtn = new Gtk.Button({ tooltip_text: _('More options') });
-
- optionsBtn.get_style_context().add_class('circular');
- optionsBtn.set_child(cogImg);
- grid.attach(optionsBtn, 2, 0, 1, 1);
-
- optionsBtn.connect('clicked', () => this[Pos.optionDialogFunctions[el.element]]());
- }
-
- grid.attach(visibleToggleBtn, 3, 0, 1, 1);
- grid.attach(positionCombo, 4, 0, 1, 1);
-
- row.id = el.element;
- row.visibleToggleBtn = visibleToggleBtn;
- row.positionCombo = positionCombo;
-
- row.set_child(grid);
- taskbarListBox.insert(row, -1);
- });
- }
-
- _createPreferencesDialog(title, content, reset_function = null) {
- let dialog;
-
- dialog = new Gtk.Dialog({ title: title,
- transient_for: this.notebook.get_root(),
- use_header_bar: true,
- modal: true });
-
- // GTK+ leaves positive values for application-defined response ids.
- // Use +1 for the reset action
- if (reset_function != null)
- dialog.add_button(_('Reset to defaults'), 1);
-
- dialog.get_content_area().append(content);
-
- dialog.connect('response', (dialog, id) => {
- if (id == 1) {
- // restore default settings
- if (reset_function)
- reset_function();
- } else {
- // remove the settings content so it doesn't get destroyed;
- dialog.get_content_area().remove(content);
- dialog.destroy();
- }
- return;
- });
-
- return dialog;
- }
-
- _showDateMenuOptions() {
- let box = this._builder.get_object('box_date_menu_options');
-
- let dialog = this._createPreferencesDialog(_('Date Menu options'), box, () =>
- {
- // restore default settings
- this._gnomeInterfaceSettings.set_value('clock-show-date', this._gnomeInterfaceSettings.get_default_value('clock-show-date'));
- this._gnomeInterfaceSettings.set_value('clock-show-weekday', this._gnomeInterfaceSettings.get_default_value('clock-show-weekday'));
- this._gnomeInterfaceSettings.set_value('clock-show-seconds', this._gnomeInterfaceSettings.get_default_value('clock-show-seconds'));
- });
-
- dialog.show();
- dialog.set_default_size(1, 1);
- }
-
- _showDesktopButtonOptions() {
- let box = this._builder.get_object('box_show_showdesktop_options');
-
- let dialog = this._createPreferencesDialog(_('Show Desktop options'), box, () =>
- {
- // restore default settings
- this._settings.set_value('show-showdesktop-icon', this._settings.get_default_value('show-showdesktop-icon'));
-
- this._settings.set_value('showdesktop-button-width', this._settings.get_default_value('showdesktop-button-width'));
- this._builder.get_object('show_showdesktop_width_spinbutton').set_value(this._settings.get_int('showdesktop-button-width'));
-
- this._settings.set_value('show-showdesktop-hover', this._settings.get_default_value('show-showdesktop-hover'));
- });
-
- this._builder.get_object('show_showdesktop_width_spinbutton').set_value(this._settings.get_int('showdesktop-button-width'));
- this._builder.get_object('show_showdesktop_width_spinbutton').connect('value-changed', (widget) => {
- this._settings.set_int('showdesktop-button-width', widget.get_value());
- });
-
- dialog.show();
- dialog.set_default_size(1, 1);
- }
-
- _addFormatValueCallbacks() {
- // position
- this._builder.get_object('panel_size_scale')
- .set_format_value_func((scale, value) => {
- return value + ' px';
- });
- }
-
- _bindSettings() {
- // size options
- let panel_size_scale = this._builder.get_object('panel_size_scale');
- panel_size_scale.set_range(DEFAULT_PANEL_SIZES[DEFAULT_PANEL_SIZES.length - 1], DEFAULT_PANEL_SIZES[0]);
- DEFAULT_PANEL_SIZES.slice(1, -1).forEach(function(val) {
- panel_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString());
- });
-
- // Correct for rtl languages
- if (this._rtl) {
- // Flip value position: this is not done automatically
- panel_size_scale.set_value_pos(Gtk.PositionType.LEFT);
- // I suppose due to a bug, having a more than one mark and one above a value of 100
- // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable
- // and then manually inverting it
- panel_size_scale.set_flippable(false);
- panel_size_scale.set_inverted(true);
- }
-
- //multi-monitor
- this.monitors = this._settings.get_value('available-monitors').deep_unpack();
-
- let dtpPrimaryMonitorIndex = 0;
-
- this._currentMonitorIndex = this.monitors[dtpPrimaryMonitorIndex];
-
- this._settings.connect('changed::panel-positions', () => this._updateVerticalRelatedOptions());
- this._updateVerticalRelatedOptions();
-
- for (let i = 0; i < this.monitors.length; ++i) {
- //the gnome-shell primary index is the first one in the "available-monitors" setting
- let label = !i ? _('Primary monitor') : _('Monitor ') + (i + 1);
-
- this._builder.get_object('taskbar_position_monitor_combo').append_text(label);
- }
-
- this._builder.get_object('taskbar_position_monitor_combo').set_active(dtpPrimaryMonitorIndex);
-
- this._settings.bind('panel-element-positions-monitors-sync',
- this._builder.get_object('taskbar_position_sync_button'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('panel-element-positions-monitors-sync',
- this._builder.get_object('taskbar_position_monitor_combo'),
- 'sensitive',
- Gio.SettingsBindFlags.INVERT_BOOLEAN);
-
- this._builder.get_object('taskbar_position_monitor_combo').connect('changed', (widget) => {
- this._currentMonitorIndex = this.monitors[widget.get_active()];
- this._updateWidgetSettingsForMonitor(this._currentMonitorIndex);
- });
-
- this._settings.bind('multi-monitors',
- this._builder.get_object('multimon_multi_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- if (this.monitors.length === 1) {
- this._builder.get_object('multimon_multi_switch').set_sensitive(false);
- }
-
- const panel_length_scale = this._builder.get_object('panel_length_scale');
- panel_length_scale.connect('value-changed', (widget) => {
- const value = widget.get_value();
- const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync');
- const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex];
- monitorsToSetFor.forEach(monitorIndex => {
- PanelSettings.setPanelLength(this._settings, monitorIndex, value);
- });
-
- this._setAnchorWidgetSensitivity(value);
- });
-
- this._builder.get_object('panel_anchor_combo').connect('changed', (widget) => {
- const value = widget.get_active_id();
- // Value can be null while anchor labels are being swapped out
- if (value !== null) {
- const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync');
- const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex];
- monitorsToSetFor.forEach(monitorIndex => {
- PanelSettings.setPanelAnchor(this._settings, monitorIndex, value);
- });
- }
- });
-
- this._updateWidgetSettingsForMonitor(this._currentMonitorIndex);
-
- //panel style
- this._settings.bind('floating-rounded-theme',
- this._builder.get_object('floating_rounded_theme_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- //dynamic opacity
- this._settings.bind('trans-use-custom-opacity',
- this._builder.get_object('trans_opacity_override_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('trans-use-custom-opacity',
- this._builder.get_object('trans_opacity_box'),
- 'sensitive',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('trans-use-custom-opacity',
- this._builder.get_object('trans_opacity_box2'),
- 'sensitive',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._builder.get_object('trans_opacity_override_switch').connect('notify::active', (widget) => {
- if (!widget.get_active())
- this._builder.get_object('trans_dyn_switch').set_active(false);
- });
-
- this._builder.get_object('trans_opacity_spinbutton').set_value(this._settings.get_double('trans-panel-opacity') * 100);
- this._builder.get_object('trans_opacity_spinbutton').connect('value-changed', (widget) => {
- this._settings.set_double('trans-panel-opacity', widget.get_value() * 0.01);
- });
-
- this._settings.bind('trans-use-dynamic-opacity',
- this._builder.get_object('trans_dyn_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('trans-use-dynamic-opacity',
- this._builder.get_object('trans_dyn_options_button'),
- 'sensitive',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('trans-dynamic-behavior',
- this._builder.get_object('trans_options_window_type_combo'),
- 'active-id',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._builder.get_object('trans_options_min_opacity_spinbutton').set_value(this._settings.get_double('trans-dynamic-anim-target') * 100);
- this._builder.get_object('trans_options_min_opacity_spinbutton').connect('value-changed', (widget) => {
- this._settings.set_double('trans-dynamic-anim-target', widget.get_value() * 0.01);
- });
-
- this._builder.get_object('trans_dyn_options_button').connect('clicked', () => {
- let box = this._builder.get_object('box_dynamic_opacity_options');
-
- let dialog = this._createPreferencesDialog(_('Dynamic opacity options'), box, () =>
- {
- // restore default settings
- this._settings.set_value('trans-dynamic-behavior', this._settings.get_default_value('trans-dynamic-behavior'));
-
- this._settings.set_value('trans-dynamic-anim-target', this._settings.get_default_value('trans-dynamic-anim-target'));
- this._builder.get_object('trans_options_min_opacity_spinbutton').set_value(this._settings.get_double('trans-dynamic-anim-target') * 100);
- });
-
- dialog.show();
- dialog.set_default_size(1, 1);
-
- });
-
- this._settings.bind('intellihide',
- this._builder.get_object('intellihide_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('intellihide',
- this._builder.get_object('intellihide_options_button'),
- 'sensitive',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('intellihide-hide-from-windows',
- this._builder.get_object('intellihide_window_hide_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('intellihide-hide-from-windows',
- this._builder.get_object('intellihide_behaviour_options'),
- 'sensitive',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('intellihide-behaviour',
- this._builder.get_object('intellihide_behaviour_combo'),
- 'active-id',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('intellihide-use-pressure',
- this._builder.get_object('intellihide_use_pressure_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('intellihide-show-in-fullscreen',
- this._builder.get_object('intellihide_show_in_fullscreen_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('intellihide-only-secondary',
- this._builder.get_object('intellihide_only_secondary_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('multi-monitors',
- this._builder.get_object('grid_intellihide_only_secondary'),
- 'sensitive',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._builder.get_object('multimon_multi_switch').connect('notify::active', (widget) => {
- if (!widget.get_active())
- this._builder.get_object('intellihide_only_secondary_switch').set_active(false);
- });
-
- this._settings.bind('intellihide-key-toggle-text',
- this._builder.get_object('intellihide_toggle_entry'),
- 'text',
- Gio.SettingsBindFlags.DEFAULT);
- this._settings.connect('changed::intellihide-key-toggle-text', () => setShortcut(this._settings, 'intellihide-key-toggle'));
-
- this._builder.get_object('intellihide_options_button').connect('clicked', () => {
- let box = this._builder.get_object('box_intellihide_options');
-
- let dialog = this._createPreferencesDialog(_('Intellihide options'), box, () =>
- {
- // restore default settings
- this._settings.set_value('intellihide-hide-from-windows', this._settings.get_default_value('intellihide-hide-from-windows'));
- this._settings.set_value('intellihide-behaviour', this._settings.get_default_value('intellihide-behaviour'));
- this._settings.set_value('intellihide-use-pressure', this._settings.get_default_value('intellihide-use-pressure'));
- this._settings.set_value('intellihide-show-in-fullscreen', this._settings.get_default_value('intellihide-show-in-fullscreen'));
- this._settings.set_value('intellihide-only-secondary', this._settings.get_default_value('intellihide-only-secondary'));
-
- this._settings.set_value('intellihide-key-toggle-text', this._settings.get_default_value('intellihide-key-toggle-text'));
- });
-
- dialog.show();
- dialog.set_default_size(1, 1);
-
- });
-
- // Behavior panel
-
- this._gnomeInterfaceSettings.bind('clock-show-date',
- this._builder.get_object('date_menu_date_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._gnomeInterfaceSettings.bind('clock-show-weekday',
- this._builder.get_object('date_menu_weekday_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._gnomeInterfaceSettings.bind('clock-show-seconds',
- this._builder.get_object('date_menu_seconds_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('show-showdesktop-icon',
- this._builder.get_object('show_showdesktop_icon_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('show-showdesktop-hover',
- this._builder.get_object('show_showdesktop_hide_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('show-window-previews',
- this._builder.get_object('show_window_previews_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('show-window-previews',
- this._builder.get_object('show_window_previews_button'),
- 'sensitive',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('show-tooltip',
- this._builder.get_object('show_tooltip_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('show-favorites',
- this._builder.get_object('show_favorite_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('show-favorites-all-monitors',
- this._builder.get_object('multimon_multi_show_favorites_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('show-favorites',
- this._builder.get_object('multimon_multi_show_favorites_switch'),
- 'sensitive',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('show-running-apps',
- this._builder.get_object('show_runnning_apps_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._builder.get_object('show_window_previews_button').connect('clicked', () => {
- let scrolledWindow = this._builder.get_object('box_window_preview_options');
-
- let dialog = this._createPreferencesDialog(_('Window preview options'), scrolledWindow, () =>
- {
- // restore default settings
- this._settings.set_value('peek-mode', this._settings.get_default_value('peek-mode'));
-
- this._settings.set_value('window-preview-size', this._settings.get_default_value('window-preview-size'));
- this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size'));
-
- this._settings.set_value('preview-middle-click-close', this._settings.get_default_value('preview-middle-click-close'));
- });
-
- this._settings.bind('preview-middle-click-close',
- this._builder.get_object('preview_middle_click_close_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('peek-mode',
- this._builder.get_object('peek_mode_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size'));
- this._builder.get_object('preview_size_spinbutton').connect('value-changed', (widget) => {
- this._settings.set_int('window-preview-size', widget.get_value());
- });
-
- dialog.show();
-
- });
-
- this._settings.bind('group-apps',
- this._builder.get_object('group_apps_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN);
-
- this._settings.bind('group-apps',
- this._builder.get_object('show_group_apps_options_button'),
- 'sensitive',
- Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN);
-
- this._settings.bind('progress-show-count',
- this._builder.get_object('show_notification_badge_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('group-apps-use-fixed-width',
- this._builder.get_object('group_apps_use_fixed_width_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('group-apps-use-launchers',
- this._builder.get_object('group_apps_use_launchers_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._builder.get_object('display_multitasking_settings').connect('activated', () => {
- try {
- const output = GLib.spawn_command_line_async('gnome-control-center multitasking');
- } catch (e) {
- logError(e);
- }
- });
-
- this._builder.get_object('show_group_apps_options_button').connect('clicked', () => {
- let box = this._builder.get_object('box_group_apps_options');
-
- let dialog = this._createPreferencesDialog(_('Ungrouped application options'), box, () =>
- {
- // restore default settings
- this._settings.set_value('group-apps-label-max-width', this._settings.get_default_value('group-apps-label-max-width'));
- this._builder.get_object('group_apps_label_max_width_spinbutton').set_value(this._settings.get_int('group-apps-label-max-width'));
-
- this._settings.set_value('group-apps-use-fixed-width', this._settings.get_default_value('group-apps-use-fixed-width'));
- this._settings.set_value('group-apps-use-launchers', this._settings.get_default_value('group-apps-use-launchers'));
- });
-
- this._builder.get_object('group_apps_label_max_width_spinbutton').set_value(this._settings.get_int('group-apps-label-max-width'));
- this._builder.get_object('group_apps_label_max_width_spinbutton').connect('value-changed', (widget) => {
- this._settings.set_int('group-apps-label-max-width', widget.get_value());
- });
-
- dialog.show();
- dialog.set_default_size(600, 1);
-
- });
-
- this._builder.get_object('click_action_combo').set_active_id(this._settings.get_string('click-action'));
- this._builder.get_object('click_action_combo').connect('changed', (widget) => {
- this._settings.set_string('click-action', widget.get_active_id());
- });
-
- this._builder.get_object('shift_click_action_combo').connect('changed', (widget) => {
- this._settings.set_string('shift-click-action', widget.get_active_id());
- });
-
- this._builder.get_object('middle_click_action_combo').connect('changed', (widget) => {
- this._settings.set_string('middle-click-action', widget.get_active_id());
- });
- this._builder.get_object('shift_middle_click_action_combo').connect('changed', (widget) => {
- this._settings.set_string('shift-middle-click-action', widget.get_active_id());
- });
-
- // Create dialog for middle-click options
- this._builder.get_object('middle_click_options_button').connect('clicked', () => {
- let box = this._builder.get_object('box_middle_click_options');
-
- let dialog = this._createPreferencesDialog(_('Customize middle-click behavior'), box, () =>
- {
- // restore default settings for the relevant keys
- let keys = ['shift-click-action', 'middle-click-action', 'shift-middle-click-action'];
- keys.forEach(function(val) {
- this._settings.set_value(val, this._settings.get_default_value(val));
- }, this);
- this._builder.get_object('shift_click_action_combo').set_active_id(this._settings.get_string('shift-click-action'));
- this._builder.get_object('middle_click_action_combo').set_active_id(this._settings.get_string('middle-click-action'));
- this._builder.get_object('shift_middle_click_action_combo').set_active_id(this._settings.get_string('shift-middle-click-action'));
- });
-
- this._builder.get_object('shift_click_action_combo').set_active_id(this._settings.get_string('shift-click-action'));
-
- this._builder.get_object('middle_click_action_combo').set_active_id(this._settings.get_string('middle-click-action'));
-
- this._builder.get_object('shift_middle_click_action_combo').set_active_id(this._settings.get_string('shift-middle-click-action'));
-
- this._settings.bind('shift-click-action',
- this._builder.get_object('shift_click_action_combo'),
- 'active-id',
- Gio.SettingsBindFlags.DEFAULT);
- this._settings.bind('middle-click-action',
- this._builder.get_object('middle_click_action_combo'),
- 'active-id',
- Gio.SettingsBindFlags.DEFAULT);
- this._settings.bind('shift-middle-click-action',
- this._builder.get_object('shift_middle_click_action_combo'),
- 'active-id',
- Gio.SettingsBindFlags.DEFAULT);
-
- dialog.show();
- dialog.set_default_size(700, 1);
-
- });
-
- this._builder.get_object('scroll_icon_combo').set_active_id(this._settings.get_string('scroll-icon-action'));
- this._builder.get_object('scroll_icon_combo').connect('changed', (widget) => {
- this._settings.set_string('scroll-icon-action', widget.get_active_id());
- });
-
- this._settings.bind('hot-keys',
- this._builder.get_object('hot_keys_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
- this._settings.bind('hot-keys',
- this._builder.get_object('overlay_button'),
- 'sensitive',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._builder.get_object('overlay_combo').connect('changed', (widget) => {
- this._settings.set_string('hotkeys-overlay-combo', widget.get_active_id());
- });
-
- this._settings.bind('shortcut-previews',
- this._builder.get_object('shortcut_preview_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._builder.get_object('shortcut_num_keys_combo').set_active_id(this._settings.get_string('shortcut-num-keys'));
- this._builder.get_object('shortcut_num_keys_combo').connect('changed', (widget) => {
- this._settings.set_string('shortcut-num-keys', widget.get_active_id());
- });
-
- this._settings.connect('changed::hotkey-prefix-text', () => {checkHotkeyPrefix(this._settings);});
-
- this._builder.get_object('hotkey_prefix_combo').set_active_id(this._settings.get_string('hotkey-prefix-text'));
-
- this._settings.bind('hotkey-prefix-text',
- this._builder.get_object('hotkey_prefix_combo'),
- 'active-id',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._builder.get_object('overlay_combo').set_active_id(this._settings.get_string('hotkeys-overlay-combo'));
-
- this._settings.bind('hotkeys-overlay-combo',
- this._builder.get_object('overlay_combo'),
- 'active-id',
- Gio.SettingsBindFlags.DEFAULT);
-
- this._settings.bind('shortcut-text',
- this._builder.get_object('shortcut_entry'),
- 'text',
- Gio.SettingsBindFlags.DEFAULT);
- this._settings.connect('changed::shortcut-text', () => {setShortcut(this._settings, 'shortcut');});
-
- // Create dialog for number overlay options
- this._builder.get_object('overlay_button').connect('clicked', () => {
- let box = this._builder.get_object('box_overlay_shortcut');
-
- let dialog = this._createPreferencesDialog(_('Advanced hotkeys options'), box, () =>
- {
- // restore default settings for the relevant keys
- let keys = ['hotkey-prefix-text', 'shortcut-text', 'hotkeys-overlay-combo', 'shortcut-previews'];
- keys.forEach(function(val) {
- this._settings.set_value(val, this._settings.get_default_value(val));
- }, this);
- });
-
- dialog.show();
- dialog.set_default_size(600, 1);
-
- });
-
- // Fine-tune panel
-
- let sizeScales = [
- {objectName: 'panel_length_scale', valueName: '', range: LENGTH_MARKS }
- ];
-
- for(const idx in sizeScales) {
- let size_scale = this._builder.get_object(sizeScales[idx].objectName);
- let range = sizeScales[idx].range;
- size_scale.set_range(range[range.length - 1], range[0]);
- let value;
- if (sizeScales[idx].objectName === 'panel_length_scale') {
- value = PanelSettings.getPanelLength(this._settings, this._currentMonitorIndex);
- } else {
- value = this._settings.get_int(sizeScales[idx].valueName);
- }
- size_scale.set_value(value);
- // Add marks from range arrays, omitting the first and last values.
- range.slice(1, -1).forEach(function(val) {
- size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString());
- });
-
- // Corrent for rtl languages
- if (this._rtl) {
- // Flip value position: this is not done automatically
- size_scale.set_value_pos(Gtk.PositionType.LEFT);
- // I suppose due to a bug, having a more than one mark and one above a value of 100
- // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable
- // and then manually inverting it
- size_scale.set_flippable(false);
- size_scale.set_inverted(true);
- }
- }
-
- this._settings.bind('stockgs-keep-top-panel',
- this._builder.get_object('stockgs_top_panel_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
-
-
-
- this._settings.connect('changed::stockgs-keep-top-panel', () => this._maybeDisableTopPosition());
-
- this._maybeDisableTopPosition();
-
- this._settings.bind('stockgs-panelbtn-click-only',
- this._builder.get_object('stockgs_panelbtn_switch'),
- 'active',
- Gio.SettingsBindFlags.DEFAULT);
- }
-}
-
-
-const BuilderScope = GObject.registerClass({
- Implements: [Gtk.BuilderScope],
-}, class BuilderScope extends GObject.Object {
-
- _init(preferences) {
- this._preferences = preferences;
- super._init();
- }
-
- vfunc_create_closure(builder, handlerName, flags, connectObject) {
- if (flags & Gtk.BuilderClosureFlags.SWAPPED)
- throw new Error('Unsupported template signal flag "swapped"');
-
- if (typeof this[handlerName] === 'undefined')
- throw new Error(`${handlerName} is undefined`);
-
- return this[handlerName].bind(connectObject || this);
- }
-
- on_btn_click(connectObject) {
- connectObject.set_label("Clicked");
- }
-
- position_bottom_button_clicked_cb(button) {
- if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.BOTTOM);
- }
-
- position_top_button_clicked_cb(button) {
- if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.TOP);
- }
-
- position_left_button_clicked_cb(button) {
- if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.LEFT);
- }
-
- position_right_button_clicked_cb(button) {
- if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.RIGHT);
- }
-
- panel_size_scale_value_changed_cb(scale) {
- // Avoid settings the size continuously
- if (this._preferences._panel_size_timeout > 0)
- GLib.Source.remove(this._preferences._panel_size_timeout);
-
- this._preferences._panel_size_timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, SCALE_UPDATE_TIMEOUT, () => {
- const value = scale.get_value();
- const monitorSync = this._preferences._settings.get_boolean('panel-element-positions-monitors-sync');
- const monitorsToSetFor = monitorSync ? this._preferences.monitors : [this._preferences._currentMonitorIndex];
- monitorsToSetFor.forEach(monitorIndex => {
- PanelSettings.setPanelSize(this._preferences._settings, monitorIndex, value);
- });
-
- this._preferences._panel_size_timeout = 0;
- return GLib.SOURCE_REMOVE;
- });
- }
-});
-
-export default class ZorinTaskbarPreferences extends ExtensionPreferences {
- fillPreferencesWindow(window) {
- window._settings = this.getSettings('org.gnome.shell.extensions.zorin-taskbar');
- window._gnomeInterfaceSettings = this.getSettings('org.gnome.desktop.interface');
-
- // use default width or window
- window.set_default_size(0, 625);
-
- let preferences = new Preferences(window, window._settings, window._gnomeInterfaceSettings, this.path);
- }
-}
diff --git a/progress.js b/progress.js
deleted file mode 100644
index db457c6..0000000
--- a/progress.js
+++ /dev/null
@@ -1,601 +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 .
- *
- *
- * Credits:
- * This file is based on code from the Dash to Dock extension by micheleg
- * and code from the Dash to Panel extension
- */
-
-import Cairo from 'cairo';
-import Gio from 'gi://Gio';
-import Clutter from 'gi://Clutter';
-import Pango from 'gi://Pango';
-import St from 'gi://St';
-import * as Utils from './utils.js';
-import {SETTINGS} from './extension.js';
-
-import {EventEmitter} from 'resource:///org/gnome/shell/misc/signals.js';
-
-
-export const ProgressManager = class extends EventEmitter {
-
- constructor() {
- super();
-
- this._entriesByDBusName = {};
-
- this._launcher_entry_dbus_signal_id =
- Gio.DBus.session.signal_subscribe(null, // sender
- 'com.canonical.Unity.LauncherEntry', // iface
- null, // member
- null, // path
- null, // arg0
- Gio.DBusSignalFlags.NONE,
- this._onEntrySignalReceived.bind(this));
-
- this._dbus_name_owner_changed_signal_id =
- Gio.DBus.session.signal_subscribe('org.freedesktop.DBus', // sender
- 'org.freedesktop.DBus', // interface
- 'NameOwnerChanged', // member
- '/org/freedesktop/DBus', // path
- null, // arg0
- Gio.DBusSignalFlags.NONE,
- this._onDBusNameOwnerChanged.bind(this));
-
- this._acquireUnityDBus();
- }
-
- destroy() {
- if (this._launcher_entry_dbus_signal_id) {
- Gio.DBus.session.signal_unsubscribe(this._launcher_entry_dbus_signal_id);
- }
-
- if (this._dbus_name_owner_changed_signal_id) {
- Gio.DBus.session.signal_unsubscribe(this._dbus_name_owner_changed_signal_id);
- }
-
- this._releaseUnityDBus();
- }
-
- size() {
- return Object.keys(this._entriesByDBusName).length;
- }
-
- lookupByDBusName(dbusName) {
- return this._entriesByDBusName.hasOwnProperty(dbusName) ? this._entriesByDBusName[dbusName] : null;
- }
-
- lookupById(appId) {
- let ret = [];
- for (let dbusName in this._entriesByDBusName) {
- let entry = this._entriesByDBusName[dbusName];
- if (entry && entry.appId() == appId) {
- ret.push(entry);
- }
- }
-
- return ret;
- }
-
- addEntry(entry) {
- let existingEntry = this.lookupByDBusName(entry.dbusName());
- if (existingEntry) {
- existingEntry.update(entry);
- } else {
- this._entriesByDBusName[entry.dbusName()] = entry;
- this.emit('progress-entry-added', entry);
- }
- }
-
- removeEntry(entry) {
- delete this._entriesByDBusName[entry.dbusName()]
- this.emit('progress-entry-removed', entry);
- }
-
- _acquireUnityDBus() {
- if (!this._unity_bus_id) {
- Gio.DBus.session.own_name('com.canonical.Unity',
- Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null);
- }
- }
-
- _releaseUnityDBus() {
- if (this._unity_bus_id) {
- Gio.DBus.session.unown_name(this._unity_bus_id);
- this._unity_bus_id = 0;
- }
- }
-
- _onEntrySignalReceived(connection, sender_name, object_path,
- interface_name, signal_name, parameters, user_data) {
- if (!parameters || !signal_name)
- return;
-
- if (signal_name == 'Update') {
- if (!sender_name) {
- return;
- }
-
- this._handleUpdateRequest(sender_name, parameters);
- }
- }
-
- _onDBusNameOwnerChanged(connection, sender_name, object_path,
- interface_name, signal_name, parameters, user_data) {
- if (!parameters || !this.size())
- return;
-
- let [name, before, after] = parameters.deep_unpack();
-
- if (!after) {
- if (this._entriesByDBusName.hasOwnProperty(before)) {
- this.removeEntry(this._entriesByDBusName[before]);
- }
- }
- }
-
- _handleUpdateRequest(senderName, parameters) {
- if (!senderName || !parameters) {
- return;
- }
-
- let [appUri, properties] = parameters.deep_unpack();
- let appId = appUri.replace(/(^\w+:|^)\/\//, '');
- let entry = this.lookupByDBusName(senderName);
-
- if (entry) {
- entry.setDBusName(senderName);
- entry.update(properties);
- } else {
- let entry = new AppProgress(senderName, appId, properties);
- this.addEntry(entry);
- }
- }
-};
-
-export class AppProgress extends EventEmitter {
-
- constructor(dbusName, appId, properties) {
- super();
-
- this._dbusName = dbusName;
- this._appId = appId;
- this._count = 0;
- this._countVisible = false;
- this._progress = 0.0;
- this._progressVisible = false;
- this._urgent = false;
- this.update(properties);
- }
-
- appId() {
- return this._appId;
- }
-
- dbusName() {
- return this._dbusName;
- }
-
- count() {
- return this._count;
- }
-
- setCount(count) {
- if (this._count != count) {
- this._count = count;
- this.emit('count-changed', this._count);
- }
- }
-
- countVisible() {
- return this._countVisible;
- }
-
- setCountVisible(countVisible) {
- if (this._countVisible != countVisible) {
- this._countVisible = countVisible;
- this.emit('count-visible-changed', this._countVisible);
- }
- }
-
- progress() {
- return this._progress;
- }
-
- setProgress(progress) {
- if (this._progress != progress) {
- this._progress = progress;
- this.emit('progress-changed', this._progress);
- }
- }
-
- progressVisible() {
- return this._progressVisible;
- }
-
- setProgressVisible(progressVisible) {
- if (this._progressVisible != progressVisible) {
- this._progressVisible = progressVisible;
- this.emit('progress-visible-changed', this._progressVisible);
- }
- }
-
- urgent() {
- return this._urgent;
- }
-
- setUrgent(urgent) {
- if (this._urgent != urgent) {
- this._urgent = urgent;
- this.emit('urgent-changed', this._urgent);
- }
- }
-
- setDBusName(dbusName) {
- if (this._dbusName != dbusName) {
- let oldName = this._dbusName;
- this._dbusName = dbusName;
- this.emit('dbus-name-changed', oldName);
- }
- }
-
- update(other) {
- if (other instanceof AppProgress) {
- this.setDBusName(other.dbusName())
- this.setCount(other.count());
- this.setCountVisible(other.countVisible());
- this.setProgress(other.progress());
- this.setProgressVisible(other.progressVisible())
- this.setUrgent(other.urgent());
- } else {
- for (let property in other) {
- if (other.hasOwnProperty(property)) {
- if (property == 'count') {
- this.setCount(other[property].get_int64());
- } else if (property == 'count-visible') {
- this.setCountVisible(SETTINGS.get_boolean('progress-show-count') && other[property].get_boolean());
- } else if (property == 'progress') {
- this.setProgress(other[property].get_double());
- } else if (property == 'progress-visible') {
- this.setProgressVisible(SETTINGS.get_boolean('progress-show-bar') && other[property].get_boolean());
- } else if (property == 'urgent') {
- this.setUrgent(other[property].get_boolean());
- } else {
- // Not implemented yet
- }
- }
- }
- }
- }
-}
-
-
-export const ProgressIndicator = class {
-
- constructor(source, progressManager) {
- this._source = source;
- this._progressManager = progressManager;
- this._signalsHandler = new Utils.GlobalSignalsHandler();
-
- this._sourceDestroyId = this._source.connect('destroy', () => {
- this._signalsHandler.destroy();
- });
-
- this._notificationBadgeLabel = new St.Label({ style_class: 'badge' });
- this._notificationBadgeBin = new St.Bin({
- child: this._notificationBadgeLabel,
- 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 Utils.ColorUtils.Color({red: 204, green: 204, blue: 204, alpha: 255});
-
- [hasColor, color] = node.lookup_color('-progress-bar-border', false);
- if (hasColor)
- this._progressbar_border = color;
- else
- this._progressbar_border = new Utils.ColorUtils.Color({red: 230, green: 230, blue: 230, alpha: 255});
-
- this._updateProgressOverlay();
- }
-
- _hideProgressOverlay() {
- if (this._progressOverlayArea)
- this._progressOverlayArea.destroy();
-
- this._progressOverlayArea = null;
- this._progressbar_background = null;
- this._progressbar_border = null;
- }
-
- _updateProgressOverlay() {
-
- if (this._progressOverlayArea) {
- this._progressOverlayArea.queue_repaint();
- }
- }
-
- _drawProgressOverlay(area) {
- let scaleFactor = Utils.getScaleFactor();
- let [surfaceWidth, surfaceHeight] = area.get_surface_size();
- let cr = area.get_context();
-
- let iconSize = this._source.icon.iconSize * scaleFactor;
-
- let x = Math.floor((surfaceWidth - iconSize) / 2);
- let y = Math.floor((surfaceHeight - iconSize) / 2);
-
- let lineWidth = Math.floor(1.0 * scaleFactor);
- let padding = Math.floor(iconSize * 0.05);
- let width = iconSize - 2.0*padding;
- let height = Math.floor(Math.min(18.0*scaleFactor, 0.20*iconSize));
- x += padding;
- y += iconSize - height - padding;
-
- cr.setLineWidth(lineWidth);
-
- // Draw the outer stroke
- let stroke = new Cairo.LinearGradient(0, y, 0, y + height);
- let fill = null;
- stroke.addColorStopRGBA(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;
- }
- }
-};
diff --git a/proximity.js b/proximity.js
deleted file mode 100644
index 29d7492..0000000
--- a/proximity.js
+++ /dev/null
@@ -1,260 +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 .
- *
- * 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
-};
-
-export class ProximityWatch {
-
- constructor(actor, monitorIndex, mode, xThreshold, yThreshold, handler) {
- this.actor = actor;
- this.monitorIndex = monitorIndex
- this.overlap = false;
- this.mode = mode;
- this.threshold = [xThreshold, yThreshold];
- this.handler = handler;
-
- this._allocationChangedId = actor.connect('notify::allocation', () => this._updateWatchRect());
-
- this._updateWatchRect();
- }
-
- destroy() {
- this.actor.disconnect(this._allocationChangedId);
- }
-
- _updateWatchRect() {
- let [actorX, actorY] = this.actor.get_position();
-
- this.rect = new Mtk.Rectangle({
- x: actorX - this.threshold[0],
- y: actorY - this.threshold[1],
- width: this.actor.width + this.threshold[0] * 2,
- height: this.actor.height + this.threshold[1] * 2
- });
- }
-};
-
-export const ProximityManager = class {
-
- constructor() {
- this._counter = 1;
- this._watches = {};
- this._focusedWindowInfo = null;
-
- this._signalsHandler = new Utils.GlobalSignalsHandler();
- this._timeoutsHandler = new Utils.TimeoutsHandler();
-
- this._bindSignals();
- this._setFocusedWindow();
- }
-
- createWatch(actor, monitorIndex, mode, xThreshold, yThreshold, handler) {
- let watch = new ProximityWatch(actor, monitorIndex, mode, xThreshold, yThreshold, handler);
-
- this._watches[this._counter] = watch;
- this.update();
-
- return this._counter++;
- }
-
- removeWatch(id) {
- if (this._watches[id]) {
- this._watches[id].destroy();
- delete this._watches[id];
- }
- }
-
- update() {
- this._queueUpdate(true);
- }
-
- destroy() {
- this._signalsHandler.destroy();
- this._timeoutsHandler.destroy();
- this._disconnectFocusedWindow();
- Object.keys(this._watches).forEach(id => this.removeWatch(id));
- }
-
- _bindSignals() {
- this._signalsHandler.add(
- [
- global.window_manager,
- 'switch-workspace',
- () => this._queueUpdate()
- ],
- [
- Main.overview,
- 'hidden',
- () => this._queueUpdate()
- ],
- [
- global.display,
- 'notify::focus-window',
- () => {
- this._setFocusedWindow();
- this._queueUpdate();
- }
- ],
- [
- global.display,
- 'restacked',
- () => this._queueUpdate()
- ]
- );
- }
-
- _setFocusedWindow() {
- this._disconnectFocusedWindow();
-
- let focusedWindow = global.display.focus_window;
-
- if (focusedWindow) {
- let focusedWindowInfo = this._getFocusedWindowInfo(focusedWindow);
-
- if (focusedWindowInfo && this._checkIfHandledWindowType(focusedWindowInfo.metaWindow)) {
- focusedWindowInfo.allocationId = focusedWindowInfo.window.connect('notify::allocation', () => this._queueUpdate());
- focusedWindowInfo.destroyId = focusedWindowInfo.window.connect('destroy', () => this._disconnectFocusedWindow(true));
-
- this._focusedWindowInfo = focusedWindowInfo;
- }
- }
- }
-
- _getFocusedWindowInfo(focusedWindow) {
- let window = focusedWindow.get_compositor_private();
- let focusedWindowInfo;
-
- if (window) {
- focusedWindowInfo = { window: window };
- focusedWindowInfo.metaWindow = focusedWindow;
-
- if (focusedWindow.is_attached_dialog()) {
- let mainMetaWindow = focusedWindow.get_transient_for();
-
- if (focusedWindowInfo.metaWindow.get_frame_rect().height < mainMetaWindow.get_frame_rect().height) {
- focusedWindowInfo.window = mainMetaWindow.get_compositor_private();
- focusedWindowInfo.metaWindow = mainMetaWindow;
- }
- }
- }
-
- return focusedWindowInfo;
- }
-
- _disconnectFocusedWindow(destroy) {
- if (this._focusedWindowInfo && !destroy) {
- this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.allocationId);
- this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.destroyId);
- }
-
- this._focusedWindowInfo = null;
- }
-
- _getHandledWindows() {
- return Utils.getCurrentWorkspace()
- .list_windows()
- .filter(mw => this._checkIfHandledWindow(mw));
- }
-
- _checkIfHandledWindow(metaWindow) {
- return metaWindow &&
- !metaWindow.minimized &&
- !metaWindow.customJS_ding &&
- 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)));
- }
-};
diff --git a/schemas/org.gnome.shell.extensions.zorin-taskbar.gschema.xml b/schemas/org.gnome.shell.extensions.zorin-taskbar.gschema.xml
index eb5b221..6570540 100644
--- a/schemas/org.gnome.shell.extensions.zorin-taskbar.gschema.xml
+++ b/schemas/org.gnome.shell.extensions.zorin-taskbar.gschema.xml
@@ -18,6 +18,7 @@
+
@@ -71,7 +72,7 @@
'{}'
- Percentages of screen edge for panel to span
+ Percentages of screen edge for panel to span, -1 for dynamic length (dock mode)
Length of the panels, in percent (JSON).
@@ -99,11 +100,6 @@
Style of the running indicator (unfocused)
Style of the running indicator for the icon for applications which are not currently focused
-
- false
- Running indicator dominant color
- Whether to use the app icon's dominant color for .app-well-running-dot
-
false
Keep top panel
@@ -119,6 +115,10 @@
Lock the taskbar
Specifies if the user can modify the taskbar
+
+ 0
+ Panel margin
+
false
Custom background color
@@ -171,9 +171,13 @@
false
- Intellihide pressure
+ Allow revealing the panel while in fullscreen
Allow the panel to be revealed while an application is in fullscreen mode
+
+ false
+ Reveal the panel on notification
+
false
Intellihide only secondary
@@ -189,10 +193,9 @@
Keybinding toggle intellihide
Keybinding to reveal the panel while in intellihide mode
-
- false
- Floating rounded theme
- Display the panel with a floating rounded theme
+
+ -1
+ Persisted intellihide hold status. -1 means the option is disabled
[]
@@ -279,11 +282,6 @@
Display panels on all monitors
Specifies if a panel is shown on every monitors
-
- []
- Available monitors
- Available gnome-shell (Mutter) monitors, internal use
-
false
Provide monitor isolation
@@ -292,7 +290,7 @@
true
Display the favorites on all monitors
- Specifies if every panel should display the favorite applications. If false, the favorite appplications are only displayed on the primary monitor.
+ Specifies if every panel should display the favorite applications. If false, the favorite applications are only displayed on the primary monitor.
true
@@ -337,6 +335,10 @@
Middle click preview to close window
Middle click on the window preview to close that window
+
+ 0
+ Border radius of panel elements
+
"<Super>q"
Keybinding to show the dock and the number overlay.
@@ -802,5 +804,9 @@
Show badge count on app icon
Whether to show badge count overlay on app icon, for supported applications.
+
+ ''
+ The preferences page name to display
+
diff --git a/src/appIcons.js b/src/appIcons.js
new file mode 100644
index 0000000..40b4f8e
--- /dev/null
+++ b/src/appIcons.js
@@ -0,0 +1,2030 @@
+/*
+ * 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 .
+ *
+ *
+ * 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 GLib from 'gi://GLib'
+import Gio from 'gi://Gio'
+import Graphene from 'gi://Graphene'
+import GObject from 'gi://GObject'
+import Mtk from 'gi://Mtk'
+import Shell from 'gi://Shell'
+import St from 'gi://St'
+
+import * as AppDisplay from 'resource:///org/gnome/shell/ui/appDisplay.js'
+import * as AppMenu from 'resource:///org/gnome/shell/ui/appMenu.js'
+import * as Dash from 'resource:///org/gnome/shell/ui/dash.js'
+import * as DND from 'resource:///org/gnome/shell/ui/dnd.js'
+import * as Main from 'resource:///org/gnome/shell/ui/main.js'
+import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'
+import * as Util from 'resource:///org/gnome/shell/misc/util.js'
+import * as BoxPointer from 'resource:///org/gnome/shell/ui/boxpointer.js'
+import { EventEmitter } from 'resource:///org/gnome/shell/misc/signals.js'
+
+import { Hold } from './intellihide.js'
+import * as Utils from './utils.js'
+import * as PanelSettings from './panelSettings.js';
+import * as Taskbar from './taskbar.js'
+import {
+ DTP_EXTENSION,
+ SETTINGS,
+ DESKTOPSETTINGS,
+ EXTENSION_PATH,
+ tracker,
+} from './extension.js'
+import {
+ gettext as _,
+ ngettext,
+} from 'resource:///org/gnome/shell/extensions/extension.js'
+
+//timeout names
+const T2 = 'mouseScrollTimeout'
+const T3 = 'showDotsTimeout'
+const T4 = 'overviewWindowDragEndTimeout'
+const T5 = 'switchWorkspaceTimeout'
+const T6 = 'displayProperIndicatorTimeout'
+
+const SCROLL_ICON_DELAY = 400
+const DOT_SIZE = 3
+
+//right padding defined for .overview-label in stylesheet.css
+const TITLE_RIGHT_PADDING = 8
+const DOUBLE_CLICK_DELAY_MS = 450
+
+let LABEL_GAP = 5
+let MAX_INDICATORS = 4
+export const DEFAULT_PADDING_SIZE = 0
+
+let DOT_STYLE = {
+ DOTS: 'DOTS',
+ SQUARES: 'SQUARES',
+ DASHES: 'DASHES',
+ SEGMENTED: 'SEGMENTED',
+ CILIORA: 'CILIORA',
+ METRO: 'METRO',
+ SOLID: 'SOLID',
+}
+
+let DOT_POSITION = {
+ TOP: 'TOP',
+ BOTTOM: 'BOTTOM',
+ LEFT: 'LEFT',
+ RIGHT: 'RIGHT',
+}
+
+let recentlyClickedAppLoopId = 0
+let recentlyClickedApp = null
+let recentlyClickedAppWindows = null
+let recentlyClickedAppIndex = 0
+let recentlyClickedAppMonitorIndex
+
+/**
+ * Extend AppIcon
+ *
+ * - Apply a css class based on the number of windows of each application (#N);
+ * - Draw a dot for each window of the application based on the default "dot" style which is hidden (#N);
+ * a class of the form "running#N" is applied to the AppWellIcon actor.
+ * like the original .running one.
+ * - add a .focused style to the focused app
+ * - Customize click actions.
+ * - Update minimization animation target
+ *
+ */
+
+export const TaskbarAppIcon = GObject.registerClass(
+ {},
+ class TaskbarAppIcon extends AppDisplay.AppIcon {
+ _init(appInfo, panel, iconParams, previewMenu, iconAnimator) {
+ this.dtpPanel = panel
+ this._nWindows = 0
+ this.window = appInfo.window
+ this.isLauncher = appInfo.isLauncher
+ this._previewMenu = previewMenu
+ this.iconAnimator = iconAnimator
+ this.lastClick = 0
+ this._appicon_normalstyle = ''
+ this._appicon_hoverstyle = ''
+ this._appicon_pressedstyle = ''
+
+ super._init(appInfo.app, iconParams)
+
+ this._signalsHandler = new Utils.GlobalSignalsHandler()
+ this._timeoutsHandler = new Utils.TimeoutsHandler()
+
+ // Fix touchscreen issues before the listener is added by the parent constructor.
+ this._onTouchEvent = function (actor, event) {
+ if (event.type() == Clutter.EventType.TOUCH_BEGIN) {
+ // Open the popup menu on long press.
+ this._setPopupTimeout()
+ } else if (
+ this._menuTimeoutId != 0 &&
+ (event.type() == Clutter.EventType.TOUCH_END ||
+ event.type() == Clutter.EventType.TOUCH_CANCEL)
+ ) {
+ // Activate/launch the application.
+ this.activate(1)
+ this._removeMenuTimeout()
+ }
+ // Disable dragging via touch screen as it's buggy as hell. Not perfect for tablet users, but the alternative is way worse.
+ // Also, EVENT_PROPAGATE launches applications twice with this solution, so this.activate(1) above must only be called if there's already a window.
+ return Clutter.EVENT_STOP
+ }
+ // Hack for missing TOUCH_END event.
+ this._onLeaveEvent = function () {
+ this.fake_release()
+ if (this._menuTimeoutId != 0) this.activate(1) // Activate/launch the application if TOUCH_END didn't fire.
+ this._removeMenuTimeout()
+ }
+
+ this._dot.set_width(0)
+ this._isGroupApps = SETTINGS.get_boolean('group-apps')
+
+ this._container = new St.Widget({
+ style_class: 'dtp-container',
+ layout_manager: new Clutter.BinLayout(),
+ })
+ this._dotsContainer = new St.Widget({
+ style_class: 'dtp-dots-container',
+ layout_manager: new Clutter.BinLayout(),
+ })
+ this._dtpIconContainer = new St.Widget({
+ layout_manager: new Clutter.BinLayout(),
+ style: getIconContainerStyle(panel.checkIfVertical()),
+ })
+
+ this.remove_child(this._iconContainer)
+ this.icon._iconBin.set_pivot_point(0.5, 0.5)
+
+ this._dtpIconContainer.add_child(this._iconContainer)
+
+ if (appInfo.window) {
+ let box = Utils.createBoxLayout()
+
+ this._windowTitle = new St.Label({
+ y_align: Clutter.ActorAlign.CENTER,
+ x_align: Clutter.ActorAlign.START,
+ style_class: 'overview-label',
+ })
+
+ this._updateWindowTitle()
+ this._updateWindowTitleStyle()
+
+ box.add_child(this._dtpIconContainer)
+ box.add_child(this._windowTitle)
+
+ this._dotsContainer.add_child(box)
+ } else {
+ this._dotsContainer.add_child(this._dtpIconContainer)
+ }
+
+ this._container.add_child(this._dotsContainer)
+ this.set_child(this._container)
+
+ if (panel.checkIfVertical()) {
+ this.set_width(panel.geom.innerSize)
+ }
+
+ // Monitor windows-changes instead of app state.
+ // Keep using the same Id and function callback (that is extended)
+ if (this._stateChangedId > 0) {
+ this.app.disconnect(this._stateChangedId)
+ this._stateChangedId = 0
+ }
+
+ this._setAppIconPadding()
+ this._showDots()
+ this._numberOverlay()
+
+ this._signalsHandler.add(
+ [
+ this,
+ 'notify::mapped',
+ () =>
+ this.mapped && !this.dtpPanel.intellihide.enabled
+ ? this._handleNotifications()
+ : null,
+ ],
+ [
+ Utils.getStageTheme(),
+ 'changed',
+ this._updateWindowTitleStyle.bind(this),
+ ],
+ [
+ global.display,
+ 'notify::focus-window',
+ this._onFocusAppChanged.bind(this),
+ ],
+ [this.app, 'windows-changed', this.onWindowsChanged.bind(this)],
+ )
+
+ if (!this.window) {
+ if (SETTINGS.get_boolean('isolate-monitors')) {
+ this._signalsHandler.add([
+ Utils.DisplayWrapper.getScreen(),
+ ['window-entered-monitor', 'window-left-monitor'],
+ this.onWindowEnteredOrLeft.bind(this),
+ ])
+ }
+
+ this._signalsHandler.add([
+ Utils.DisplayWrapper.getScreen(),
+ 'in-fullscreen-changed',
+ () => {
+ if (
+ global.display.focus_window?.get_monitor() ==
+ this.dtpPanel.monitor.index &&
+ !this.dtpPanel.monitor.inFullscreen
+ ) {
+ this._resetDots(true)
+ this._displayProperIndicator()
+ }
+ },
+ ])
+ } else {
+ this._signalsHandler.add(
+ [this.window, 'notify::title', this._updateWindowTitle.bind(this)],
+ [
+ this.window,
+ 'notify::minimized',
+ this._updateWindowTitleStyle.bind(this),
+ ],
+ )
+ }
+
+ this._signalsHandler.add(
+ [this, 'scroll-event', this._onMouseScroll.bind(this)],
+ [
+ Main.overview,
+ 'window-drag-end',
+ this._onOverviewWindowDragEnd.bind(this),
+ ],
+ [
+ global.window_manager,
+ 'switch-workspace',
+ this._onSwitchWorkspace.bind(this),
+ ],
+ [
+ this,
+ 'notify::hover',
+ () => {
+ this._onAppIconHoverChanged()
+ this._onAppIconHoverChanged_GtkWorkaround()
+ },
+ ],
+ [
+ this,
+ 'notify::pressed',
+ this._onAppIconPressedChanged_GtkWorkaround.bind(this),
+ ],
+ [
+ this.dtpPanel.panelManager.notificationsMonitor,
+ `update-${this.app.id}`,
+ this._handleNotifications.bind(this),
+ ],
+ [
+ SETTINGS,
+ 'changed::progress-show-count',
+ this._handleNotifications.bind(this),
+ ],
+ [
+ SETTINGS,
+ [
+ 'changed::panel-positions',
+ 'changed::dot-style-focused',
+ 'changed::dot-style-unfocused',
+ ],
+ this._settingsChangeRefresh.bind(this),
+ ],
+ [
+ SETTINGS,
+ [
+ 'changed::group-apps-label-max-width',
+ 'changed::group-apps-use-fixed-width',
+ ],
+ this._updateWindowTitleStyle.bind(this),
+ ],
+ )
+ }
+
+ getDragActor() {
+ return this.app.create_icon_texture(this.dtpPanel.taskbar.iconSize)
+ }
+
+ shouldShowTooltip() {
+ if (
+ !SETTINGS.get_boolean('show-tooltip') ||
+ (!this.isLauncher &&
+ SETTINGS.get_boolean('show-window-previews') &&
+ this.getAppIconInterestingWindows().length > 0)
+ ) {
+ return false
+ } else {
+ return (
+ this.hover &&
+ !this.window &&
+ (!this._menu || !this._menu.isOpen) &&
+ this._previewMenu.getCurrentAppIcon() !== this
+ )
+ }
+ }
+
+ _onAppIconHoverChanged() {
+ if (
+ !SETTINGS.get_boolean('show-window-previews') ||
+ (!this.window && !this._nWindows)
+ ) {
+ return
+ }
+
+ if (this.hover) {
+ this._previewMenu.requestOpen(this)
+ } else {
+ this._previewMenu.requestClose()
+ }
+ }
+
+ _onDestroy() {
+ super._onDestroy()
+
+ this._timeoutsHandler.destroy()
+ this._signalsHandler.destroy()
+
+ this._previewMenu.close(true)
+ }
+
+ onWindowsChanged() {
+ this._updateWindows()
+ this.updateIcon()
+
+ if (this._isGroupApps) this._setIconStyle()
+ }
+
+ onWindowEnteredOrLeft(display, number, metaWindow) {
+ if (number > 0 && tracker.get_window_app(metaWindow) == this.app) {
+ this._updateWindows()
+ this._displayProperIndicator()
+ }
+ }
+
+ updateTitleStyle() {
+ this._updateWindowTitleStyle()
+ }
+
+ // Update indicator and target for minimization animation
+ updateIcon() {
+ // If (for unknown reason) the actor is not on the stage the reported size
+ // and position are random values, which might exceeds the integer range
+ // resulting in an error when assigned to the a rect. This is a more like
+ // a workaround to prevent flooding the system with errors.
+ if (this.get_stage() == null) return
+
+ let rect = new Mtk.Rectangle()
+
+ ;[rect.x, rect.y] = this.get_transformed_position()
+ ;[rect.width, rect.height] = this.get_transformed_size()
+
+ let windows = this.window
+ ? [this.window]
+ : this.getAppIconInterestingWindows(true)
+ windows.forEach(function (w) {
+ w.set_icon_geometry(rect)
+ })
+ }
+
+ _onAppIconHoverChanged_GtkWorkaround() {
+ if (this.hover && this._appicon_hoverstyle) {
+ this._container.set_style(this._appicon_hoverstyle)
+ } else if (this._appicon_normalstyle) {
+ this._container.set_style(this._appicon_normalstyle)
+ } else {
+ this._container.set_style('')
+ }
+ }
+
+ _onAppIconPressedChanged_GtkWorkaround() {
+ if (this.pressed && this._appicon_pressedstyle) {
+ this._container.set_style(this._appicon_pressedstyle)
+ } else if (this.hover && this._appicon_hoverstyle) {
+ this._container.set_style(this._appicon_hoverstyle)
+ } else if (this._appicon_normalstyle) {
+ this._container.set_style(this._appicon_normalstyle)
+ } else {
+ this._container.set_style('')
+ }
+ }
+
+ _onMouseScroll(actor, event) {
+ let scrollAction = SETTINGS.get_string('scroll-icon-action')
+
+ if (
+ scrollAction === 'NOTHING' ||
+ (!this.window && !this._nWindows)
+ ) {
+ return
+ }
+
+ let direction = Utils.getMouseScrollDirection(event)
+
+ if (direction && !this._timeoutsHandler.getId(T2)) {
+ this._timeoutsHandler.add([
+ T2,
+ SCROLL_ICON_DELAY,
+ () => {},
+ ])
+
+ let windows = this.getAppIconInterestingWindows()
+
+ windows.sort(Taskbar.sortWindowsCompareFunction)
+ Utils.activateSiblingWindow(windows, direction, this.window)
+ }
+ }
+
+ _showDots() {
+ // Just update style if dots already exist
+ if (this._focusedDots && this._unfocusedDots) {
+ this._updateWindows()
+ return
+ }
+
+ if (!this._isGroupApps) {
+ this._focusedDots = new St.Widget({
+ layout_manager: new Clutter.BinLayout(),
+ x_expand: true,
+ y_expand: true,
+ visible: false,
+ })
+
+ let mappedId = this.connect('notify::mapped', () => {
+ this._displayProperIndicator()
+ this.disconnect(mappedId)
+ })
+ } else {
+ ;(this._focusedDots = new St.DrawingArea()),
+ (this._unfocusedDots = new St.DrawingArea())
+
+ this._focusedDots.connect('repaint', () => {
+ if (!this._dashItemContainer.animatingOut)
+ // don't draw and trigger more animations if the icon is in the middle of
+ // being removed from the panel
+ this._drawRunningIndicator(
+ this._focusedDots,
+ SETTINGS.get_string('dot-style-focused'),
+ true,
+ )
+ })
+
+ this._unfocusedDots.connect('repaint', () => {
+ if (!this._dashItemContainer.animatingOut)
+ this._drawRunningIndicator(
+ this._unfocusedDots,
+ SETTINGS.get_string('dot-style-unfocused'),
+ false,
+ )
+ })
+
+ this._dotsContainer.add_child(this._unfocusedDots)
+
+ this._updateWindows()
+
+ this._timeoutsHandler.add([
+ T3,
+ 0,
+ () => {
+ this._resetDots()
+ this._displayProperIndicator()
+ },
+ ])
+ }
+
+ this._dotsContainer.add_child(this._focusedDots)
+ }
+
+ _resetDots(ignoreSizeReset) {
+ let position = PanelSettings.getPanelPosition(SETTINGS, this.dtpPanel.monitor.index)
+ let isHorizontalDots =
+ position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM
+ let sizeProp = isHorizontalDots ? 'width' : 'height'
+ let focusedDotStyle = SETTINGS.get_string('dot-style-focused')
+ let unfocusedDotStyle = SETTINGS.get_string('dot-style-unfocused')
+
+ this._focusedIsWide = this._isWideDotStyle(focusedDotStyle)
+ this._unfocusedIsWide = this._isWideDotStyle(unfocusedDotStyle)
+ ;[, this._containerSize] =
+ this._container[`get_preferred_${sizeProp}`](-1)
+
+ if (!ignoreSizeReset) {
+ ;[this._focusedDots, this._unfocusedDots].forEach((d) => {
+ d.set_size(-1, -1)
+ d.x_expand = d.y_expand = false
+
+ d[sizeProp] = 1
+ d[(isHorizontalDots ? 'y' : 'x') + '_expand'] = true
+ })
+ }
+ }
+
+ _settingsChangeRefresh() {
+ if (this._isGroupApps) {
+ this._updateWindows()
+ this._resetDots()
+ this._focusedDots.queue_repaint()
+ this._unfocusedDots.queue_repaint()
+ }
+
+ this._displayProperIndicator()
+ }
+
+ _updateWindowTitleStyle() {
+ if (this._windowTitle) {
+ let useFixedWidth = SETTINGS.get_boolean('group-apps-use-fixed-width')
+ let scaleFactor = Utils.getScaleFactor()
+ let maxLabelWidth =
+ SETTINGS.get_int('group-apps-label-max-width') * scaleFactor
+ let variableWidth =
+ !useFixedWidth ||
+ this.dtpPanel.checkIfVertical() ||
+ this.dtpPanel.taskbar.fullScrollView
+
+ this._windowTitle[maxLabelWidth > 0 ? 'show' : 'hide']()
+ this._windowTitle.set_width(
+ variableWidth
+ ? -1
+ : maxLabelWidth + TITLE_RIGHT_PADDING * scaleFactor,
+ )
+
+ this._windowTitle.clutter_text.natural_width = useFixedWidth
+ ? maxLabelWidth
+ : 0
+ this._windowTitle.clutter_text.natural_width_set = useFixedWidth
+
+ this._windowTitle.set_style(
+ useFixedWidth ? '' : 'max-width: ' + maxLabelWidth + 'px;'
+ )
+ }
+ }
+
+ _updateWindowTitle() {
+ if (this._windowTitle.text != this.window.title) {
+ this._windowTitle.text = (
+ this.window.title ? this.window.title : this.app.get_name()
+ )
+ .replace(/\r?\n|\r/g, '')
+ .trim()
+
+ if (this._focusedDots) {
+ this._displayProperIndicator()
+ }
+ }
+ }
+
+ _setIconStyle(isFocused) {
+ let inlineStyle = 'margin: 0;'
+
+ if (this._dotsContainer.get_style() != inlineStyle) {
+ this._dotsContainer.set_style(inlineStyle)
+ }
+ }
+
+ _checkIfFocusedApp() {
+ return tracker.focus_app == this.app
+ }
+
+ _checkIfMonitorHasFocus() {
+ return (
+ global.display.focus_window &&
+ (!SETTINGS.get_boolean('multi-monitors') || // only check same monitor index if multi window is enabled.
+ !SETTINGS.get_boolean('isolate-monitors') ||
+ global.display.focus_window.get_monitor() ===
+ this.dtpPanel.monitor.index)
+ )
+ }
+
+ _setAppIconPadding() {
+ const padding = getIconPadding(this.dtpPanel)
+ const margin = Taskbar.APPICON_MARGIN
+ let vertical = this.dtpPanel.checkIfVertical()
+
+ this.set_style(
+ `padding: ${vertical ? margin : 0}px ${vertical ? 0 : margin}px;`,
+ )
+ this._iconContainer.set_style('padding: ' + padding + 'px;')
+ }
+
+ popupMenu() {
+ this._removeMenuTimeout()
+ this.fake_release()
+
+ if (!this._menu) {
+ this._menu = new TaskbarSecondaryMenu(this, this.dtpPanel.geom.position)
+ this._menu.setApp(this.app)
+
+ this._signalsHandler.add(
+ [
+ this._menu,
+ 'open-state-changed',
+ (menu, isPoppedUp) => {
+ if (!isPoppedUp) this._onMenuPoppedDown()
+ else this._previewMenu.close(true)
+ },
+ ],
+ [Main.overview, 'hiding', () => this._menu.close()],
+ )
+
+ // We want to keep the item hovered while the menu is up
+ this._menu.blockSourceEvents = true
+
+ Main.uiGroup.add_child(this._menu.actor)
+ this._menuManager.addMenu(this._menu)
+ }
+ this._menu.updateQuitText()
+
+ this.emit('menu-state-changed', true)
+
+ this.set_hover(true)
+ this._menu.open(BoxPointer.PopupAnimation.FULL)
+ this._menuManager.ignoreRelease()
+ this.emit('sync-tooltip')
+
+ return false
+ }
+
+ _onFocusAppChanged() {
+ this._displayProperIndicator()
+ }
+
+ _onOverviewWindowDragEnd() {
+ this._timeoutsHandler.add([
+ T4,
+ 0,
+ () => {
+ if (SETTINGS.get_boolean('isolate-workspaces')) this._updateWindows()
+
+ this._displayProperIndicator()
+ },
+ ])
+ }
+
+ _onSwitchWorkspace() {
+ if (this._isGroupApps) {
+ this._timeoutsHandler.add([T5, 0, () => this._displayProperIndicator()])
+ } else {
+ this._displayProperIndicator()
+ }
+ }
+
+ _displayProperIndicator() {
+ let isFocused = this._isFocusedWindow()
+ let position = PanelSettings.getPanelPosition(SETTINGS, this.dtpPanel.monitor.index)
+ let isHorizontalDots =
+ position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM
+
+ this._setIconStyle(isFocused)
+
+ if (!this._isGroupApps) {
+ if (
+ this.window &&
+ isFocused
+ ) {
+ let align =
+ Clutter.ActorAlign[
+ position == DOT_POSITION.TOP || position == DOT_POSITION.LEFT
+ ? 'START'
+ : 'END'
+ ]
+
+ this._focusedDots.set_size(0, 0)
+ this._focusedDots[isHorizontalDots ? 'height' : 'width'] =
+ this._getRunningIndicatorSize()
+
+ this._focusedDots.y_align = this._focusedDots.x_align =
+ Clutter.ActorAlign.FILL
+ this._focusedDots[(isHorizontalDots ? 'y' : 'x') + '_align'] = align
+ this._focusedDots.background_color =
+ this._getRunningIndicatorColor(isFocused)
+ this._focusedDots.show()
+ } else if (this._focusedDots.visible) {
+ this._focusedDots.hide()
+ }
+ } else {
+ let sizeProp = isHorizontalDots ? 'width' : 'height'
+ let newFocusedDotsSize = 0
+ let newFocusedDotsOpacity = 0
+ let newUnfocusedDotsSize = 0
+ let newUnfocusedDotsOpacity = 0
+
+ isFocused = this._checkIfFocusedApp() && this._checkIfMonitorHasFocus()
+
+ this._timeoutsHandler.add([
+ T6,
+ 0,
+ () => {
+ if (isFocused) this.add_style_class_name('focused')
+ else this.remove_style_class_name('focused')
+ },
+ ])
+
+ if (this._focusedIsWide) {
+ newFocusedDotsSize =
+ isFocused && this._nWindows > 0 ? this._containerSize : 0
+ newFocusedDotsOpacity = 255
+ } else {
+ newFocusedDotsSize = this._containerSize
+ newFocusedDotsOpacity = isFocused && this._nWindows > 0 ? 255 : 0
+ }
+
+ if (this._unfocusedIsWide) {
+ newUnfocusedDotsSize =
+ !isFocused && this._nWindows > 0 ? this._containerSize : 0
+ newUnfocusedDotsOpacity = 255
+ } else {
+ newUnfocusedDotsSize = this._containerSize
+ newUnfocusedDotsOpacity = !isFocused && this._nWindows > 0 ? 255 : 0
+ }
+
+ // Only animate if...
+ // going from a wide style to a narrow style indicator or vice-versa
+ // OR going from an open app to a closed app or vice versa
+ let animate =
+ this._focusedIsWide != this._unfocusedIsWide ||
+ this._focusedDots[sizeProp] != newUnfocusedDotsSize ||
+ this._unfocusedDots[sizeProp] != newFocusedDotsSize
+ let duration = animate ? Taskbar.DASH_ANIMATION_TIME : 0.001
+
+ this._animateDotDisplay(
+ this._focusedDots,
+ newFocusedDotsSize,
+ this._unfocusedDots,
+ newUnfocusedDotsOpacity,
+ sizeProp,
+ duration,
+ )
+ this._animateDotDisplay(
+ this._unfocusedDots,
+ newUnfocusedDotsSize,
+ this._focusedDots,
+ newFocusedDotsOpacity,
+ sizeProp,
+ duration,
+ )
+ }
+ }
+
+ _animateDotDisplay(
+ dots,
+ newSize,
+ otherDots,
+ newOtherOpacity,
+ sizeProp,
+ duration,
+ ) {
+ Utils.stopAnimations(dots)
+
+ let tweenOpts = {
+ time: duration,
+ transition: 'easeInOutCubic',
+ onComplete: () => {
+ if (newOtherOpacity > 0) otherDots.opacity = newOtherOpacity
+ },
+ }
+
+ if (newOtherOpacity == 0) otherDots.opacity = newOtherOpacity
+
+ tweenOpts[sizeProp] = newSize
+
+ Utils.animate(dots, tweenOpts)
+ }
+
+ _isFocusedWindow() {
+ let focusedWindow = global.display.focus_window
+
+ while (focusedWindow) {
+ if (focusedWindow == this.window) {
+ return true
+ }
+
+ focusedWindow = focusedWindow.get_transient_for()
+ }
+
+ return false
+ }
+
+ _isWideDotStyle(dotStyle) {
+ return (
+ dotStyle == DOT_STYLE.SEGMENTED ||
+ dotStyle == DOT_STYLE.CILIORA ||
+ dotStyle == DOT_STYLE.METRO ||
+ dotStyle == DOT_STYLE.SOLID
+ )
+ }
+
+ _isThemeProvidingIndicator() {
+ // This is an attempt to determine if the theme is providing their own
+ // running indicator by way of a border image on the icon, for example in
+ // the theme Ciliora
+ return (
+ this.icon.get_stage() && this.icon.get_theme_node().get_border_image()
+ )
+ }
+
+ activate(button, modifiers, handleAsGrouped) {
+ let event = Clutter.get_current_event()
+
+ modifiers = event ? event.get_state() : modifiers || 0
+
+ // Only consider SHIFT and CONTROL as modifiers (exclude SUPER, CAPS-LOCK, etc.)
+ modifiers =
+ modifiers &
+ (Clutter.ModifierType.SHIFT_MASK | Clutter.ModifierType.CONTROL_MASK)
+
+ let ctrlPressed = modifiers & Clutter.ModifierType.CONTROL_MASK
+
+ if (ctrlPressed) {
+ // CTRL-click or hotkey with ctrl
+ return this._launchNewInstance(true)
+ }
+
+ // We check what type of click we have and if the modifier SHIFT is
+ // being used. We then define what buttonAction should be for this
+ // event.
+ let buttonAction = 0
+ let doubleClick
+
+ if (button && button == 2) {
+ if (modifiers & Clutter.ModifierType.SHIFT_MASK)
+ buttonAction = SETTINGS.get_string('shift-middle-click-action')
+ else buttonAction = SETTINGS.get_string('middle-click-action')
+ }
+ // fixed issue #1676 by checking for button 0 or 1 to also handle touchscreen
+ // input, probably not the proper fix as i'm not aware button 0 should exist
+ // but from using this fix for months it seems to not create any issues
+ else if (button === 0 || button === 1) {
+ let now = global.get_current_time()
+
+ doubleClick = now - this.lastClick < DOUBLE_CLICK_DELAY_MS
+ this.lastClick = now
+
+ if (modifiers & Clutter.ModifierType.SHIFT_MASK)
+ buttonAction = SETTINGS.get_string('shift-click-action')
+ else buttonAction = SETTINGS.get_string('click-action')
+ }
+
+ let closePreview = () =>
+ this._previewMenu.close(true)
+ let appCount = this.getAppIconInterestingWindows().length
+ let previewedAppIcon = this._previewMenu.getCurrentAppIcon()
+
+ if (this.window || buttonAction != 'TOGGLE-SHOWPREVIEW') closePreview()
+
+ // We check if the app is running, and that the # of windows is > 0 in
+ // case we use workspace isolation,
+ let appIsRunning =
+ this.app.state == Shell.AppState.RUNNING && appCount > 0
+
+ // We customize the action only when the application is already running
+ if (appIsRunning && !this.isLauncher) {
+ if (this.window && !handleAsGrouped) {
+ //ungrouped applications behaviors
+ switch (buttonAction) {
+ case 'LAUNCH':
+ this._launchNewInstance()
+ break
+
+ case 'QUIT':
+ this.window.delete(global.get_current_time())
+ break
+
+ default:
+ if (
+ !Main.overview._shown &&
+ (buttonAction == 'MINIMIZE' ||
+ buttonAction == 'TOGGLE-SHOWPREVIEW' ||
+ buttonAction == 'TOGGLE-CYCLE' ||
+ buttonAction == 'TOGGLE-SPREAD' ||
+ buttonAction == 'CYCLE-MIN') &&
+ (this._isFocusedWindow() ||
+ (buttonAction == 'MINIMIZE' &&
+ (button == 2 ||
+ modifiers & Clutter.ModifierType.SHIFT_MASK)))
+ ) {
+ this.window.minimize()
+ } else {
+ Main.activateWindow(this.window)
+ }
+ }
+ } else {
+ //grouped application behaviors
+ let monitor = this.dtpPanel.monitor
+ let appHasFocus =
+ this._checkIfFocusedApp() && this._checkIfMonitorHasFocus()
+
+ switch (buttonAction) {
+ case 'RAISE':
+ activateAllWindows(this.app, monitor)
+ break
+
+ case 'LAUNCH':
+ this._launchNewInstance()
+ break
+
+ case 'MINIMIZE':
+ // In overview just activate the app, unless the acion is explicitely
+ // requested with a keyboard modifier
+ if (!Main.overview._shown || modifiers) {
+ // If we have button=2 or a modifier, allow minimization even if
+ // the app is not focused
+ if (
+ appHasFocus ||
+ button == 2 ||
+ modifiers & Clutter.ModifierType.SHIFT_MASK
+ ) {
+ // minimize all windows on double click and always in the case of primary click without
+ // additional modifiers
+ let all_windows = (button == 1 && !modifiers) || doubleClick
+ minimizeWindow(this.app, all_windows, monitor)
+ } else activateAllWindows(this.app, monitor)
+ } else this.app.activate()
+ break
+
+ case 'CYCLE':
+ if (!Main.overview._shown) {
+ if (appHasFocus)
+ cycleThroughWindows(this.app, false, false, monitor)
+ else {
+ activateFirstWindow(this.app, monitor)
+ }
+ } else this.app.activate()
+ break
+ case 'CYCLE-MIN':
+ if (!Main.overview._shown) {
+ if (
+ appHasFocus ||
+ (recentlyClickedApp == this.app &&
+ recentlyClickedAppWindows[
+ recentlyClickedAppIndex % recentlyClickedAppWindows.length
+ ] == 'MINIMIZE')
+ )
+ cycleThroughWindows(this.app, false, true, monitor)
+ else {
+ activateFirstWindow(this.app, monitor)
+ }
+ } else this.app.activate()
+ break
+ case 'TOGGLE-SHOWPREVIEW':
+ if (!Main.overview._shown) {
+ if (appCount == 1) {
+ closePreview()
+
+ if (appHasFocus) minimizeWindow(this.app, false, monitor)
+ else activateFirstWindow(this.app, monitor)
+ } else {
+ if (doubleClick) {
+ // minimize all windows if double clicked
+ closePreview()
+ minimizeWindow(this.app, true, monitor)
+ } else if (previewedAppIcon != this) {
+ this._previewMenu.open(this)
+ }
+
+ this.emit('sync-tooltip')
+ }
+ } else this.app.activate()
+ break
+ case 'TOGGLE-CYCLE':
+ if (!Main.overview._shown) {
+ if (appCount == 1) {
+ if (appHasFocus) minimizeWindow(this.app, false, monitor)
+ else activateFirstWindow(this.app, monitor)
+ } else {
+ cycleThroughWindows(this.app, false, false, monitor)
+ }
+ } else this.app.activate()
+ break
+ case 'QUIT':
+ closeAllWindows(this.app, monitor)
+ break
+ case 'TOGGLE-SPREAD':
+ if (appCount == 1) {
+ if (appHasFocus && !Main.overview._shown)
+ minimizeWindow(this.app, false, monitor)
+ else activateFirstWindow(this.app, monitor)
+ } else
+ // return so the overview stays open if it already is
+ return this.dtpPanel.panelManager.showFocusedAppInOverview(
+ this.app,
+ )
+ }
+ }
+ } else {
+ this._launchNewInstance()
+ }
+
+ global.display.emit('grab-op-begin', null, null)
+ Main.overview.hide()
+ }
+
+ _launchNewInstance(ctrlPressed) {
+ if (
+ (ctrlPressed || this.app.state == Shell.AppState.RUNNING) &&
+ this.app.can_open_new_window()
+ ) {
+ this.animateLaunch()
+ this.app.open_new_window(-1)
+ } else {
+ let windows = this.window ? [this.window] : this.app.get_windows()
+
+ if (windows.length) {
+ Main.activateWindow(windows[0])
+ } else {
+ this.animateLaunch()
+ this.app.activate()
+ }
+ }
+ }
+
+ _updateWindows() {
+ let windows = [this.window]
+
+ if (!this.window) {
+ windows = this.getAppIconInterestingWindows()
+
+ this._nWindows = windows.length
+
+ for (let i = 1; i <= MAX_INDICATORS; i++) {
+ let className = 'running' + i
+ if (i != this._nWindows) this.remove_style_class_name(className)
+ else this.add_style_class_name(className)
+ }
+ }
+
+ this._previewMenu.update(this, windows)
+ }
+
+ _getRunningIndicatorCount() {
+ return Math.min(this._nWindows, MAX_INDICATORS)
+ }
+
+ _getRunningIndicatorSize() {
+ return DOT_SIZE * Utils.getScaleFactor()
+ }
+
+ _getRunningIndicatorColor(isFocused) {
+ let color
+ const fallbackColor = new Utils.ColorUtils.Color({
+ red: 82,
+ green: 148,
+ blue: 226,
+ alpha: 255,
+ })
+
+ // Re-use the style - background color, and border width and color -
+ // of the default dot
+ let themeNode = this._dot.get_theme_node()
+ color = themeNode.get_background_color()
+
+ // theme didn't provide one, use a default
+ if (color.alpha == 0) color = fallbackColor
+
+ return color
+ }
+
+ _drawRunningIndicator(area, type, isFocused) {
+ let n = this._getRunningIndicatorCount()
+
+ if (!n) {
+ return
+ }
+
+ let position = PanelSettings.getPanelPosition(SETTINGS, this.dtpPanel.monitor.index)
+ let isHorizontalDots =
+ position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM
+ let bodyColor = this._getRunningIndicatorColor(isFocused)
+ let [areaWidth, areaHeight] = area.get_surface_size()
+ let cr = area.get_context()
+ let size = this._getRunningIndicatorSize()
+
+ let areaSize = areaWidth
+ let startX = 0
+ let startY = 0
+
+ if (isHorizontalDots) {
+ if (position == DOT_POSITION.BOTTOM) {
+ startY = areaHeight - size
+ }
+ } else {
+ areaSize = areaHeight
+
+ if (position == DOT_POSITION.RIGHT) {
+ startX = areaWidth - size
+ }
+ }
+
+ if (type == DOT_STYLE.SOLID || type == DOT_STYLE.METRO) {
+ if (type == DOT_STYLE.SOLID || n <= 1) {
+ cr.translate(startX, startY)
+ cr.setSourceColor(bodyColor)
+ cr.newSubPath()
+ cr.rectangle.apply(
+ cr,
+ [0, 0].concat(
+ isHorizontalDots ? [areaSize, size] : [size, areaSize],
+ ),
+ )
+ cr.fill()
+ } else {
+ let blackenedLength = (1 / 48) * areaSize // need to scale with the SVG for the stacked highlight
+ let darkenedLength = isFocused
+ ? (2 / 48) * areaSize
+ : (10 / 48) * areaSize
+ let blackenedColor = new Utils.ColorUtils.Color({
+ red: bodyColor.red * 0.3,
+ green: bodyColor.green * 0.3,
+ blue: bodyColor.blue * 0.3,
+ alpha: bodyColor.alpha,
+ })
+ let darkenedColor = new Utils.ColorUtils.Color({
+ red: bodyColor.red * 0.7,
+ green: bodyColor.green * 0.7,
+ blue: bodyColor.blue * 0.7,
+ alpha: bodyColor.alpha,
+ })
+ let solidDarkLength = areaSize - darkenedLength
+ let solidLength = solidDarkLength - blackenedLength
+
+ cr.translate(startX, startY)
+
+ cr.setSourceColor(bodyColor)
+ cr.newSubPath()
+ cr.rectangle.apply(
+ cr,
+ [0, 0].concat(
+ isHorizontalDots ? [solidLength, size] : [size, solidLength],
+ ),
+ )
+ cr.fill()
+ cr.setSourceColor(blackenedColor)
+ cr.newSubPath()
+ cr.rectangle.apply(
+ cr,
+ isHorizontalDots
+ ? [solidLength, 0, 1, size]
+ : [0, solidLength, size, 1],
+ )
+ cr.fill()
+ cr.setSourceColor(darkenedColor)
+ cr.newSubPath()
+ cr.rectangle.apply(
+ cr,
+ isHorizontalDots
+ ? [solidDarkLength, 0, darkenedLength, size]
+ : [0, solidDarkLength, size, darkenedLength],
+ )
+ cr.fill()
+ }
+ } else {
+ let spacing = Math.ceil(areaSize / 18) // separation between the indicators
+ let length
+ let radius
+ let dist
+ let indicatorSize
+ let translate
+ let preDraw = () => {}
+ let draw
+ let drawDash = (i, dashLength) => {
+ dist = i * dashLength + i * spacing
+ cr.rectangle.apply(
+ cr,
+ isHorizontalDots
+ ? [dist, 0, dashLength, size]
+ : [0, dist, size, dashLength],
+ )
+ }
+
+ switch (type) {
+ // Using the code from Ciliora Round style in pull request https://github.com/home-sweet-gnome/dash-to-panel/pull/1720
+ case DOT_STYLE.CILIORA:
+ spacing = size
+ radius = size / 2
+ length = areaSize - size * (n - 1) - spacing * (n - 1)
+ translate = () => cr.translate(startX, startY)
+ preDraw = () => {
+ cr.newSubPath()
+ cr.arc.apply(
+ cr,
+ (isHorizontalDots ? [radius, radius] : [radius, radius]).concat([radius, 0, 2 * Math.PI])
+ )
+ cr.arc.apply(
+ cr,
+ (isHorizontalDots ? [length - radius, radius] : [radius, length - radius]).concat([radius, 0, 2 * Math.PI])
+ )
+ cr.rectangle.apply(
+ cr,
+ (isHorizontalDots ? [radius, 0, length - size, size] : [0, radius, size, length - size])
+ )
+ }
+ draw = (i) => {
+ dist = length + i * spacing + (i - 1) * size + radius
+ cr.arc.apply(
+ cr,
+ (isHorizontalDots ? [dist, radius] : [radius, dist]).concat([radius, 0, 2 * Math.PI]),
+ )
+ }
+ break
+ case DOT_STYLE.DOTS: {
+ radius = size / 2
+
+ translate = () => {
+ indicatorSize = Math.floor(
+ (areaSize - n * size - (n - 1) * spacing) / 2,
+ )
+ cr.translate.apply(
+ cr,
+ isHorizontalDots
+ ? [indicatorSize, startY]
+ : [startX, indicatorSize],
+ )
+ }
+ draw = (i) => {
+ dist = (2 * i + 1) * radius + i * spacing
+ cr.arc.apply(
+ cr,
+ (isHorizontalDots ? [dist, radius] : [radius, dist]).concat([
+ radius,
+ 0,
+ 2 * Math.PI,
+ ]),
+ )
+ }
+ break
+ }
+ case DOT_STYLE.SQUARES:
+ translate = () => {
+ indicatorSize = Math.floor(
+ (areaSize - n * size - (n - 1) * spacing) / 2,
+ )
+ cr.translate.apply(
+ cr,
+ isHorizontalDots
+ ? [indicatorSize, startY]
+ : [startX, indicatorSize],
+ )
+ }
+ draw = (i) => {
+ dist = i * size + i * spacing
+ cr.rectangle.apply(
+ cr,
+ (isHorizontalDots ? [dist, 0] : [0, dist]).concat([size, size]),
+ )
+ }
+ break
+ case DOT_STYLE.DASHES:
+ length = Math.floor(areaSize / 4) - spacing
+ translate = () => {
+ indicatorSize = Math.floor(
+ (areaSize - n * length - (n - 1) * spacing) / 2,
+ )
+ cr.translate.apply(
+ cr,
+ isHorizontalDots
+ ? [indicatorSize, startY]
+ : [startX, indicatorSize],
+ )
+ }
+ draw = (i) => drawDash(i, length)
+ break
+ case DOT_STYLE.SEGMENTED:
+ length = Math.ceil((areaSize - (n - 1) * spacing) / n)
+ translate = () => cr.translate(startX, startY)
+ draw = (i) => drawDash(i, length)
+ break
+ }
+
+ translate()
+
+ cr.setSourceColor(bodyColor)
+ preDraw()
+ for (let i = 0; i < n; i++) {
+ cr.newSubPath()
+ draw(i)
+ }
+ cr.fill()
+ }
+
+ cr.$dispose()
+ }
+
+ _handleNotifications() {
+ if (!this._nWindows && !this.window) return
+
+ let monitor = this.dtpPanel.panelManager.notificationsMonitor
+ let state = monitor.getState(this.app)
+ let count = 0
+
+ if (!state) return
+
+ if (SETTINGS.get_boolean('progress-show-count')) {
+ this.iconAnimator[`${state.urgent ? 'add' : 'remove'}Animation`](
+ this.icon._iconBin,
+ 'dance',
+ )
+
+ if (state.total) {
+ count = state.total > 9 ? '9+' : state.total
+ this.dtpPanel.intellihide.revealAndHold(Hold.NOTIFY)
+ } else this.dtpPanel.intellihide.release(Hold.NOTIFY)
+ }
+
+ this._notificationsCount = count
+
+ this._maybeUpdateNumberOverlay()
+ }
+
+ _maybeUpdateNumberOverlay() {
+ let visible = this._numberOverlayBin.visible
+ let shouldBeVisible =
+ (this._hotkeysOverlayActiveMode &&
+ this._numberHotkeysOverlayLabel > -1) ||
+ this._notificationsCount
+
+ let showNotifications =
+ this._notificationsCount &&
+ this._hotkeysOverlayActiveMode !== 'TEMPORARILY'
+ let label = showNotifications
+ ? this._notificationsCount
+ : this._numberHotkeysOverlayLabel
+
+ this._numberOverlayLabel[
+ `${showNotifications ? 'add' : 'remove'}_style_class_name`
+ ]('notification-badge')
+
+ if (showNotifications) {
+ this._numberOverlayLabel.set_x_align(Clutter.ActorAlign.END)
+ this._numberOverlayLabel.set_y_align(Clutter.ActorAlign.START)
+ this._numberOverlayLabel.set_x_expand(true)
+ this._numberOverlayLabel.set_y_expand(true)
+ } else {
+ this._numberOverlayLabel.set_x_align(Clutter.ActorAlign.START)
+ this._numberOverlayLabel.set_y_align(Clutter.ActorAlign.START)
+ this._numberOverlayLabel.set_x_expand(false)
+ this._numberOverlayLabel.set_y_expand(false)
+ }
+
+ if (shouldBeVisible && label !== this._numberOverlayLabel.get_text()) {
+ this._numberOverlayLabel.set_text(label.toString())
+ this._updateNumberOverlay()
+ }
+
+ if (visible && !shouldBeVisible) this._numberOverlayBin.hide()
+ else if (!visible && shouldBeVisible) this._numberOverlayBin.show()
+ }
+
+ _numberOverlay() {
+ // Add label for a numeric visual aid (hotkeys or notification)
+ this._numberOverlayLabel = new St.Label({ style_class: 'badge' })
+ this._numberOverlayBin = new St.Bin({
+ child: this._numberOverlayLabel,
+ y: 2,
+ })
+ this._numberOverlayLabel.add_style_class_name('number-overlay')
+ this._numberHotkeysOverlayLabel = -1
+ this._numberOverlayBin.hide()
+
+ this._dtpIconContainer.add_child(this._numberOverlayBin)
+ }
+
+ _updateNumberOverlay() {
+ // We apply an overall scale factor that might come from a HiDPI monitor.
+ // Clutter dimensions are in physical pixels, but CSS measures are in logical
+ // pixels, so make sure to consider the scale.
+ // Set the font size to something smaller than the whole icon so it is
+ // still visible. The border radius is large to make the shape circular
+ let panelSize = this.dtpPanel.geom.iconSize
+ let minFontSize = panelSize >= 32 ? 12 : 10
+ let fontSize = Math.round(
+ Math.max(minFontSize, 0.2 * panelSize) / Utils.getScaleFactor(),
+ )
+ let size = Math.round(fontSize * 1.3)
+ let style = `
+ font-size: ${fontSize}px;
+ height: ${size}px;
+ `
+ this._numberOverlayLabel.set_style(style)
+ }
+
+ setHotkeysNumberOverlayLabel(number) {
+ this._numberHotkeysOverlayLabel = number
+ }
+
+ toggleHotkeysNumberOverlay(activateMode) {
+ this._hotkeysOverlayActiveMode =
+ this._numberHotkeysOverlayLabel > -1 && activateMode
+
+ this._maybeUpdateNumberOverlay()
+ }
+
+ handleDragOver(source) {
+ if (source == Main.xdndHandler) {
+ this._previewMenu.close(true)
+
+ if (!this._nWindows && !this.window)
+ return DND.DragMotionResult.MOVE_DROP
+
+ if (this._nWindows == 1 || this.window) {
+ this.window
+ ? Main.activateWindow(this.window)
+ : activateFirstWindow(this.app, this.monitor)
+ } else
+ this.dtpPanel.panelManager.showFocusedAppInOverview(this.app, true)
+
+ return DND.DragMotionResult.MOVE_DROP
+ }
+
+ return DND.DragMotionResult.CONTINUE
+ }
+
+ getAppIconInterestingWindows(isolateMonitors) {
+ return getInterestingWindows(
+ this.app,
+ this.dtpPanel.monitor,
+ isolateMonitors,
+ )
+ }
+ },
+)
+TaskbarAppIcon.prototype.scaleAndFade =
+ TaskbarAppIcon.prototype.undoScaleAndFade = () => {}
+
+export function minimizeWindow(app, param, monitor) {
+ // Param true make all app windows minimize
+ let windows = getInterestingWindows(app, monitor)
+ let current_workspace =
+ Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace()
+ for (let i = 0; i < windows.length; i++) {
+ let w = windows[i]
+ if (
+ w.get_workspace() == current_workspace &&
+ w.showing_on_its_workspace()
+ ) {
+ w.minimize()
+ // Just minimize one window. By specification it should be the
+ // focused window on the current workspace.
+ if (!param) break
+ }
+ }
+}
+
+/*
+ * By default only non minimized windows are activated.
+ * This activates all windows in the current workspace.
+ */
+export function activateAllWindows(app, monitor) {
+ // First activate first window so workspace is switched if needed,
+ // then activate all other app windows in the current workspace.
+ let windows = getInterestingWindows(app, monitor)
+ let w = windows[0]
+ Main.activateWindow(w)
+ let activeWorkspace =
+ Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace_index()
+
+ if (windows.length <= 0) return
+
+ for (let i = windows.length - 1; i >= 0; i--) {
+ if (windows[i].get_workspace().index() == activeWorkspace) {
+ Main.activateWindow(windows[i])
+ }
+ }
+}
+
+export function activateFirstWindow(app, monitor) {
+ let windows = getInterestingWindows(app, monitor)
+ Main.activateWindow(windows[0])
+}
+
+export function cycleThroughWindows(app, reversed, shouldMinimize, monitor) {
+ // Store for a little amount of time last clicked app and its windows
+ // since the order changes upon window interaction
+ let MEMORY_TIME = 3000
+
+ let app_windows = getInterestingWindows(app, monitor)
+
+ if (shouldMinimize) app_windows.push('MINIMIZE')
+
+ if (recentlyClickedAppLoopId > 0) GLib.Source.remove(recentlyClickedAppLoopId)
+
+ recentlyClickedAppLoopId = GLib.timeout_add(
+ GLib.PRIORITY_DEFAULT,
+ MEMORY_TIME,
+ resetRecentlyClickedApp,
+ )
+
+ // If there isn't already a list of windows for the current app,
+ // or the stored list is outdated, use the current windows list.
+ if (
+ !recentlyClickedApp ||
+ recentlyClickedApp.get_id() != app.get_id() ||
+ recentlyClickedAppWindows.length != app_windows.length ||
+ recentlyClickedAppMonitorIndex != monitor.index
+ ) {
+ recentlyClickedApp = app
+ recentlyClickedAppWindows = app_windows
+ recentlyClickedAppIndex = 0
+ recentlyClickedAppMonitorIndex = monitor.index
+ }
+
+ if (reversed) {
+ recentlyClickedAppIndex--
+ if (recentlyClickedAppIndex < 0)
+ recentlyClickedAppIndex = recentlyClickedAppWindows.length - 1
+ } else {
+ recentlyClickedAppIndex++
+ }
+ let index = recentlyClickedAppIndex % recentlyClickedAppWindows.length
+
+ if (recentlyClickedAppWindows[index] === 'MINIMIZE')
+ minimizeWindow(app, true, monitor)
+ else Main.activateWindow(recentlyClickedAppWindows[index])
+}
+
+export function resetRecentlyClickedApp() {
+ if (recentlyClickedAppLoopId > 0) GLib.Source.remove(recentlyClickedAppLoopId)
+
+ recentlyClickedAppLoopId = 0
+ recentlyClickedApp = null
+ recentlyClickedAppWindows = null
+ recentlyClickedAppIndex = 0
+ recentlyClickedAppMonitorIndex = null
+
+ return GLib.SOURCE_REMOVE
+}
+
+export function closeAllWindows(app, monitor) {
+ let windows = getInterestingWindows(app, monitor)
+ for (let i = 0; i < windows.length; i++)
+ windows[i].delete(global.get_current_time())
+}
+
+// Filter out unnecessary windows, for instance
+// nautilus desktop window.
+export function getInterestingWindows(app, monitor, isolateMonitors) {
+ let windows = (app ? app.get_windows() : Utils.getAllMetaWindows()).filter(
+ (w) => !w.skip_taskbar,
+ )
+
+ // When using workspace or monitor isolation, we filter out windows
+ // that are not in the current workspace or on the same monitor as the appicon
+ if (SETTINGS.get_boolean('isolate-workspaces'))
+ windows = windows.filter(function (w) {
+ return (
+ w.get_workspace() && w.get_workspace() == Utils.getCurrentWorkspace()
+ )
+ })
+
+ if (
+ monitor &&
+ SETTINGS.get_boolean('multi-monitors') &&
+ (isolateMonitors || SETTINGS.get_boolean('isolate-monitors'))
+ ) {
+ windows = windows.filter(function (w) {
+ return w.get_monitor() == monitor.index
+ })
+ }
+
+ return windows
+}
+
+export function cssHexTocssRgba(cssHex, opacity) {
+ let bigint = parseInt(cssHex.slice(1), 16)
+ let r = (bigint >> 16) & 255
+ let g = (bigint >> 8) & 255
+ let b = bigint & 255
+
+ return 'rgba(' + [r, g, b].join(',') + ',' + opacity + ')'
+}
+
+export function getIconPadding(dtpPanel) {
+ let panelSize = dtpPanel.geom.innerSize
+ let padding = Taskbar.APPICON_PADDING
+ let availSize = panelSize - Taskbar.MIN_ICON_SIZE - (panelSize % 2)
+
+ if (padding * 2 > availSize) {
+ padding = availSize * 0.5
+ }
+
+ return padding
+}
+
+/**
+ * Extend AppMenu (AppIconMenu for pre gnome 41)
+ *
+ * - hide 'App Details' according to setting
+ * - show windows header only if show-window-previews is disabled
+ * - Add close windows option based on quitfromdash extension
+ * (https://github.com/deuill/shell-extension-quitfromdash)
+ */
+
+export class TaskbarSecondaryMenu extends AppMenu.AppMenu {
+ constructor(source, side) {
+ super(source, side)
+ // constructor parameter does nos work for some reason
+ this._enableFavorites = true
+ this._showSingleWindows = true
+
+ // replace quit item
+ delete this._quitItem
+ this._quitItem = this.addAction(_('Quit'), () => this._quitFromTaskbar())
+ }
+
+ updateQuitText() {
+ let count = this.sourceActor.window
+ ? 1
+ : getInterestingWindows(this._app, this.sourceActor.dtpPanel.monitor)
+ .length
+
+ if (count > 0) {
+ let quitFromTaskbarMenuText = ''
+ if (count == 1) quitFromTaskbarMenuText = _('Quit')
+ else
+ quitFromTaskbarMenuText = ngettext(
+ 'Quit %d Window',
+ 'Quit %d Windows',
+ count,
+ ).format(count)
+
+ this._quitItem.label.set_text(quitFromTaskbarMenuText)
+ }
+ }
+
+ _quitFromTaskbar() {
+ let time = global.get_current_time()
+ let windows = this.sourceActor.window // ungrouped applications
+ ? [this.sourceActor.window]
+ : getInterestingWindows(this._app, this.sourceActor.dtpPanel.monitor)
+
+ if (windows.length == this._app.get_windows().length)
+ this._app.request_quit()
+
+ GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
+ windows.forEach((w) => !!w.get_compositor_private() && w.delete(time++))
+
+ return GLib.SOURCE_REMOVE
+ })
+ }
+}
+
+/**
+ * This function is used for extendDashItemContainer
+ */
+export function ItemShowLabel() {
+ if (!this._labelText) return
+
+ this.label.set_text(this._labelText)
+ this.label.opacity = 0
+ this.label.show()
+
+ let [stageX, stageY] = this.get_transformed_position()
+ let node = this.label.get_theme_node()
+
+ let itemWidth = this.allocation.x2 - this.allocation.x1
+ let itemHeight = this.allocation.y2 - this.allocation.y1
+
+ let labelWidth = this.label.get_width()
+ let labelHeight = this.label.get_height()
+
+ let position = this._dtpPanel.getPosition()
+ let labelOffset = node.get_length('-x-offset')
+
+ let xOffset = Math.floor((itemWidth - labelWidth) / 2)
+ let x = stageX + xOffset
+ let y = stageY + (itemHeight - labelHeight) * 0.5
+
+ switch (position) {
+ case St.Side.TOP:
+ y = stageY + labelOffset + itemHeight
+ break
+ case St.Side.BOTTOM:
+ y = stageY - labelHeight - labelOffset
+ break
+ case St.Side.LEFT:
+ x = stageX + labelOffset + itemWidth
+ break
+ case St.Side.RIGHT:
+ x = stageX - labelWidth - labelOffset
+ break
+ }
+
+ // keep the label inside the screen border
+ // Only needed for the x coordinate.
+
+ // Leave a few pixel gap
+ let gap = LABEL_GAP
+ let monitor = Main.layoutManager.findMonitorForActor(this)
+ if (x - monitor.x < gap) x += monitor.x - x + labelOffset
+ else if (x + labelWidth > monitor.x + monitor.width - gap)
+ x -= x + labelWidth - (monitor.x + monitor.width) + gap
+
+ this.label.set_position(Math.round(x), Math.round(y))
+
+ let duration = Dash.DASH_ITEM_LABEL_SHOW_TIME
+
+ if (duration > 1) {
+ duration /= 1000
+ }
+
+ Utils.animate(this.label, {
+ opacity: 255,
+ time: duration,
+ transition: 'easeOutQuad',
+ })
+}
+
+/**
+ * A wrapper class around the ShowAppsIcon class.
+ *
+ * - Pass settings to the constructor
+ * - set label position based on dash orientation (Note, I am reusing most machinery of the appIcon class)
+ * - implement a popupMenu based on the AppIcon code (Note, I am reusing most machinery of the appIcon class)
+ *
+ * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973.
+ * thus use this pattern where the real showAppsIcon object is encaptulated, and a reference to it will be properly wired upon
+ * use of this class in place of the original showAppsButton.
+ *
+ */
+export const ShowAppsIconWrapper = class extends EventEmitter {
+ constructor(dtpPanel) {
+ super()
+
+ this.realShowAppsIcon = new Dash.ShowAppsIcon()
+
+ /* the variable equivalent to toggleButton has a different name in the appIcon class
+ (actor): duplicate reference to easily reuse appIcon methods */
+ this.actor = this.realShowAppsIcon.toggleButton
+ this.realShowAppsIcon.show(false)
+
+ // Re-use appIcon methods
+ this._removeMenuTimeout = AppDisplay.AppIcon.prototype._removeMenuTimeout
+ this._setPopupTimeout = AppDisplay.AppIcon.prototype._setPopupTimeout
+ this._onKeyboardPopupMenu =
+ AppDisplay.AppIcon.prototype._onKeyboardPopupMenu
+
+ // No action on clicked (showing of the appsview is controlled elsewhere)
+ this._onClicked = () => this._removeMenuTimeout()
+
+ this.actor.connect('leave-event', this._onLeaveEvent.bind(this))
+ this.actor.connect('button-press-event', this._onButtonPress.bind(this))
+ this.actor.connect('touch-event', this._onTouchEvent.bind(this))
+ this.actor.connect('clicked', this._onClicked.bind(this))
+ this.actor.connect('popup-menu', this._onKeyboardPopupMenu.bind(this))
+
+ this._menu = null
+ this._menuManager = new PopupMenu.PopupMenuManager(this.actor)
+ this._menuTimeoutId = 0
+
+ this.realShowAppsIcon._dtpPanel = dtpPanel
+ Taskbar.extendDashItemContainer(this.realShowAppsIcon)
+
+ this.realShowAppsIcon.icon.createIcon = function (size) {
+ this._iconActor = new St.Icon({
+ icon_name: 'view-app-grid-symbolic',
+ icon_size: size,
+ style_class: 'show-apps-icon',
+ track_hover: true,
+ })
+
+ return this._iconActor
+ }
+
+ this.setShowAppsPadding()
+ }
+
+ _onButtonPress(_actor, event) {
+ let button = event.get_button()
+ if (button == 1) {
+ this._setPopupTimeout()
+ } else if (button == 3) {
+ this.popupMenu()
+ return Clutter.EVENT_STOP
+ }
+ return Clutter.EVENT_PROPAGATE
+ }
+
+ _onLeaveEvent() {
+ this.actor.fake_release()
+ this._removeMenuTimeout()
+ }
+
+ _onTouchEvent(actor, event) {
+ if (event.type() == Clutter.EventType.TOUCH_BEGIN) this._setPopupTimeout()
+
+ return Clutter.EVENT_PROPAGATE
+ }
+
+ _onMenuPoppedDown() {
+ this._menu.sourceActor = this.actor
+ this.actor.sync_hover()
+ this.emit('menu-state-changed', false)
+ }
+
+ setShowAppsPadding() {
+ let padding = getIconPadding(this.realShowAppsIcon._dtpPanel)
+
+ this.actor.set_style(
+ 'padding:' + padding + 'px;',
+ )
+ }
+
+ createMenu() {
+ if (!this._menu) {
+ this._menu = new MyShowAppsIconMenu(
+ this.realShowAppsIcon,
+ this.realShowAppsIcon._dtpPanel,
+ )
+ this._menu.connect('open-state-changed', (menu, isPoppedUp) => {
+ if (!isPoppedUp) this._onMenuPoppedDown()
+ })
+ let id = Main.overview.connect('hiding', () => {
+ this._menu.close()
+ })
+ this._menu.actor.connect('destroy', () => {
+ Main.overview.disconnect(id)
+ })
+
+ // We want to keep the item hovered while the menu is up
+ this._menu.blockSourceEvents = true
+
+ Main.uiGroup.add_child(this._menu.actor)
+ this._menuManager.addMenu(this._menu)
+ }
+ }
+
+ popupMenu(sourceActor = null) {
+ this._removeMenuTimeout()
+ this.actor.fake_release()
+ this.createMenu()
+
+ this._menu.updateItems(
+ sourceActor == null ? this.realShowAppsIcon : sourceActor,
+ )
+
+ this.actor.set_hover(true)
+ this._menu.open(BoxPointer.PopupAnimation.FULL)
+ this._menuManager.ignoreRelease()
+ this.emit('sync-tooltip')
+
+ return false
+ }
+
+ shouldShowTooltip() {
+ return (
+ SETTINGS.get_boolean('show-tooltip') &&
+ this.actor.hover &&
+ (!this._menu || !this._menu.isOpen)
+ )
+ }
+
+ destroy() {
+ this.realShowAppsIcon.destroy()
+ }
+}
+
+/**
+ * A menu for the showAppsIcon
+ */
+export const MyShowAppsIconMenu = class extends PopupMenu.PopupMenu {
+ constructor(actor, dtpPanel) {
+ super(actor, 0, dtpPanel.getPosition())
+
+ this._dtpPanel = dtpPanel
+
+ this.updateItems(actor)
+ }
+
+ updateItems(sourceActor) {
+ this.sourceActor = sourceActor
+
+ this.removeAll()
+
+ this._appendItem({
+ title: _('System Monitor'),
+ cmd: ['gnome-system-monitor'],
+ })
+
+ this._appendItem({
+ title: _('Files'),
+ cmd: ['nautilus'],
+ })
+
+ this._appendItem({
+ title: _('Settings'),
+ cmd: ['gnome-control-center'],
+ })
+
+ this._appendItem({
+ title: _('Zorin Appearance'),
+ cmd: ['zorin-appearance'],
+ })
+
+ this._appendList(
+ SETTINGS.get_strv('panel-context-menu-commands'),
+ SETTINGS.get_strv('panel-context-menu-titles'),
+ )
+
+ this._appendSeparator()
+
+ let lockTaskbarMenuItem = this._appendMenuItem(
+ SETTINGS.get_boolean('taskbar-locked')
+ ? _('Unlock taskbar')
+ : _('Lock taskbar'),
+ )
+ lockTaskbarMenuItem.connect('activate', () => {
+ SETTINGS.set_boolean(
+ 'taskbar-locked',
+ !SETTINGS.get_boolean('taskbar-locked'),
+ )
+ })
+
+ let settingsMenuItem = this._appendMenuItem(_('Taskbar Settings'))
+ settingsMenuItem.connect('activate', () => DTP_EXTENSION.openPreferences())
+
+ if (this.sourceActor == Main.layoutManager.dummyCursor) {
+ this._appendSeparator()
+ let item = this._appendMenuItem(
+ this._dtpPanel._restoreWindowList
+ ? _('Restore Windows')
+ : _('Show Desktop'),
+ )
+ item.connect(
+ 'activate',
+ this._dtpPanel._onShowDesktopButtonPress.bind(this._dtpPanel),
+ )
+ }
+ }
+
+ // Only add menu entries for commands that exist in path
+ _appendItem(info) {
+ if (GLib.find_program_in_path(info.cmd[0])) {
+ let item = this._appendMenuItem(_(info.title))
+
+ item.connect('activate', function () {
+ Util.spawn(info.cmd)
+ })
+ return item
+ }
+
+ return null
+ }
+
+ _appendList(commandList, titleList) {
+ if (commandList.length != titleList.length) {
+ return
+ }
+
+ for (let entry = 0; entry < commandList.length; entry++) {
+ this._appendItem({
+ title: titleList[entry],
+ cmd: commandList[entry].split(' '),
+ })
+ }
+ }
+
+ _appendSeparator() {
+ let separator = new PopupMenu.PopupSeparatorMenuItem()
+ this.addMenuItem(separator)
+ }
+
+ _appendMenuItem(labelText) {
+ // FIXME: app-well-menu-item style
+ let item = new PopupMenu.PopupMenuItem(labelText)
+ this.addMenuItem(item)
+ return item
+ }
+}
+
+export const getIconContainerStyle = function (isVertical) {
+ let style = 'padding: '
+
+ if (SETTINGS.get_boolean('group-apps')) {
+ style += isVertical ? '0;' : '0 ' + DEFAULT_PADDING_SIZE + 'px;'
+ } else {
+ style += (isVertical ? '' : '0 ') + DEFAULT_PADDING_SIZE + 'px;'
+ }
+
+ return style
+}
diff --git a/src/desktopIconsIntegration.js b/src/desktopIconsIntegration.js
new file mode 100644
index 0000000..669fb6d
--- /dev/null
+++ b/src/desktopIconsIntegration.js
@@ -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)
+ }
+}
diff --git a/src/extension.js b/src/extension.js
new file mode 100644
index 0000000..18c5351
--- /dev/null
+++ b/src/extension.js
@@ -0,0 +1,175 @@
+/*
+ * 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 .
+ *
+ */
+
+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 startupCompleteHandler
+let zorinDashDelayId = 0
+
+export let DTP_EXTENSION = null
+export let SETTINGS = null
+export let TILINGSETTINGS = 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)
+
+ this._realHasOverview = Main.sessionMode.hasOverview
+
+ //create an object that persists until gnome-shell is restarted, even if the extension is disabled
+ PERSISTENTSTORAGE = {}
+ }
+
+ async enable() {
+ DTP_EXTENSION = this
+ SETTINGS = this.getSettings('org.gnome.shell.extensions.zorin-taskbar')
+ try {
+ TILINGSETTINGS = new Gio.Settings({
+ schema_id: 'org.gnome.shell.extensions.zorin-tiling-shell',
+ })
+ } catch (e) {
+ console.log(e)
+ }
+ 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)
+
+ Main.layoutManager.startInOverview = false
+
+ if (Main.layoutManager._startingUp) {
+ Main.sessionMode.hasOverview = false
+ startupCompleteHandler = Main.layoutManager.connect(
+ 'startup-complete',
+ () => (Main.sessionMode.hasOverview = this._realHasOverview),
+ )
+ }
+
+ this.enableGlobalStyles()
+
+ let completeEnable = () => {
+ panelManager = new PanelManager.PanelManager()
+ panelManager.enable()
+ 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)
+
+ panelManager.disable()
+
+ DTP_EXTENSION = null
+ SETTINGS = null
+ DESKTOPSETTINGS = null
+ TERMINALSETTINGS = null
+ panelManager = null
+
+ delete global.zorinTaskbar
+
+ this.disableGlobalStyles()
+
+ AppIcons.resetRecentlyClickedApp()
+
+ if (startupCompleteHandler) {
+ Main.layoutManager.disconnect(startupCompleteHandler)
+ startupCompleteHandler = null
+ }
+
+ Main.sessionMode.hasOverview = this._realHasOverview
+ }
+
+ 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),
+ )
+ }
+}
diff --git a/src/intellihide.js b/src/intellihide.js
new file mode 100644
index 0000000..2c2a08b
--- /dev/null
+++ b/src/intellihide.js
@@ -0,0 +1,529 @@
+/*
+ * 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 .
+ *
+ * Credits:
+ * This file is based on code from the Dash to Panel extension
+ */
+
+import Clutter from 'gi://Clutter'
+import Meta from 'gi://Meta'
+import Shell from 'gi://Shell'
+import St from 'gi://St'
+
+import * as GrabHelper from 'resource:///org/gnome/shell/ui/grabHelper.js'
+import * as Layout from 'resource:///org/gnome/shell/ui/layout.js'
+import * as Main from 'resource:///org/gnome/shell/ui/main.js'
+import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js'
+import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.js'
+
+import * as Proximity from './proximity.js'
+import * as Utils from './utils.js'
+import { SETTINGS, 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_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._hoveredOut = false
+ this._windowOverlap = false
+ this._translationProp =
+ 'translation_' + (this._dtpPanel.checkIfVertical() ? 'x' : 'y')
+
+ this._panelBox.translation_y = 0
+ this._panelBox.translation_x = 0
+
+ this._setTrackPanel(true)
+ this._bindGeneralSignals()
+
+ if (SETTINGS.get_boolean('intellihide-hide-from-windows')) {
+ this._proximityWatchId = this._proximityManager.createWatch(
+ this._panelBox.get_parent(),
+ this._dtpPanel.monitor.index,
+ Proximity.Mode[SETTINGS.get_string('intellihide-behaviour')],
+ 0,
+ 0,
+ (overlap) => {
+ this._windowOverlap = overlap
+ this._queueUpdatePanelPosition()
+ },
+ )
+ }
+
+ this._setRevealMechanism()
+
+ 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
+
+ if (this._proximityWatchId) {
+ this._proximityManager.removeWatch(this._proximityWatchId)
+ }
+
+ this._setTrackPanel(false)
+
+ this._signalsHandler.destroy()
+ this._timeoutsHandler.destroy()
+
+ this._removeRevealMechanism()
+
+ this._revealPanel(!reset)
+ }
+
+ destroy() {
+ SETTINGS.disconnect(this._intellihideChangedId)
+ SETTINGS.disconnect(this._intellihideOnlySecondaryChangedId)
+
+ if (this.enabled) {
+ this.disable()
+ }
+ }
+
+ toggle() {
+ this[this._holdStatus & Hold.PERMANENT ? 'release' : 'revealAndHold'](
+ Hold.PERMANENT,
+ )
+ }
+
+ revealAndHold(holdStatus) {
+ if (
+ !this.enabled ||
+ (holdStatus == Hold.NOTIFY &&
+ (!SETTINGS.get_boolean('intellihide-show-on-notification') ||
+ !NOTIFICATIONSSETTINGS.get_boolean('show-banners')))
+ )
+ return
+
+ if (!this._holdStatus) this._revealPanel()
+
+ 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()
+ }
+
+ _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._panelBox.sync_hover()
+ this._onHoverChanged()
+ },
+ ],
+ [
+ SETTINGS,
+ [
+ 'changed::intellihide-use-pressure',
+ 'changed::intellihide-hide-from-windows',
+ 'changed::intellihide-behaviour',
+ ],
+ () => this.reset(),
+ ],
+ [this._panelBox, 'notify::hover', () => this._onHoverChanged()],
+ [
+ this._dtpPanel.taskbar.previewMenu,
+ 'open-state-changed',
+ () => this._queueUpdatePanelPosition(),
+ ],
+ [
+ Main.overview,
+ ['showing', 'hiding'],
+ () => this._queueUpdatePanelPosition(),
+ ],
+ )
+
+ if (Meta.is_wayland_compositor()) {
+ this._signalsHandler.add([
+ this._panelBox,
+ 'notify::visible',
+ () => Utils.setDisplayUnredirect(!this._panelBox.visible),
+ ])
+ }
+ }
+
+ _onHoverChanged() {
+ this._hoveredOut = !this._panelBox.hover
+ this._queueUpdatePanelPosition()
+ }
+
+ _setTrackPanel(enable) {
+ let actorData = Utils.getTrackedActorData(this._panelBox)
+
+ actorData.affectsStruts = !enable
+ actorData.trackFullscreen = !enable
+
+ Main.layoutManager.panelBox.reactive = enable
+ Main.layoutManager.panelBox.track_hover = enable
+
+ this._panelBox.track_hover = enable
+ this._panelBox.reactive = enable
+ this._panelBox.visible = enable ? enable : this._panelBox.visible
+
+ Main.layoutManager._queueUpdateRegions()
+ }
+
+ _setRevealMechanism() {
+ let barriers = Meta.BackendCapabilities.BARRIERS
+
+ if (
+ (global.backend.capabilities & barriers) === barriers &&
+ SETTINGS.get_boolean('intellihide-use-pressure')
+ ) {
+ this._edgeBarrier = this._createBarrier()
+ this._pressureBarrier = new Layout.PressureBarrier(
+ 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._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 (!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) {
+ if (destination === this._animationDestination) return
+
+ Utils.stopAnimations(this._panelBox)
+ this._animationDestination = destination
+
+ if (immediate) {
+ this._panelBox[this._translationProp] = destination
+ this._panelBox.visible = !destination
+ } else if (destination !== this._panelBox[this._translationProp]) {
+ 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
+ }
+}
diff --git a/src/notificationsMonitor.js b/src/notificationsMonitor.js
new file mode 100644
index 0000000..a673299
--- /dev/null
+++ b/src/notificationsMonitor.js
@@ -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 .
+ *
+ * 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))
+ }
+}
diff --git a/src/overview.js b/src/overview.js
new file mode 100644
index 0000000..d7376f6
--- /dev/null
+++ b/src/overview.js
@@ -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 .
+ *
+ * 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.checkIfVertical() ? 'w' : 'h'] *
+ (transitioning
+ ? Math.abs((finalState != 0 ? 0 : 1) - progress)
+ : 1)
+
+ if (isBottom || position == St.Side.RIGHT)
+ box[focusedPanel.fixedCoord.c2] -= size
+ else box[focusedPanel.fixedCoord.c1] += size
+ } else if (isBottom)
+ // The default overview allocation takes into account external
+ // struts, everywhere but the bottom where the dash is usually fixed anyway.
+ // If there is a bottom panel under the dash location, give it some space here
+ box.y2 -= focusedPanel.geom.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
+ }
+}
diff --git a/src/panel.js b/src/panel.js
new file mode 100644
index 0000000..15f5591
--- /dev/null
+++ b/src/panel.js
@@ -0,0 +1,1544 @@
+/*
+ * 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 .
+ *
+ * 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.
+ */
+
+import Clutter from 'gi://Clutter'
+import Gio from 'gi://Gio'
+import GLib from 'gi://GLib'
+import GObject from 'gi://GObject'
+import Graphene from 'gi://Graphene'
+
+import * as AppIcons from './appIcons.js'
+import * as Utils from './utils.js'
+import * as Taskbar from './taskbar.js'
+import * as TaskbarItemContainer from './taskbar.js'
+import * as Pos from './panelPositions.js'
+import * as PanelSettings from './panelSettings.js'
+import * as PanelStyle from './panelStyle.js'
+
+import * as Config from 'resource:///org/gnome/shell/misc/config.js'
+import * as Main from 'resource:///org/gnome/shell/ui/main.js'
+import * as Dash from 'resource:///org/gnome/shell/ui/dash.js'
+import * as DND from 'resource:///org/gnome/shell/ui/dnd.js'
+import * as CtrlAltTab from 'resource:///org/gnome/shell/ui/ctrlAltTab.js'
+import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js'
+import St from 'gi://St'
+import Meta from 'gi://Meta'
+import Pango from 'gi://Pango'
+import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'
+import * as DateMenu from 'resource:///org/gnome/shell/ui/dateMenu.js'
+import * as Volume from 'resource:///org/gnome/shell/ui/status/volume.js'
+
+import * as Intellihide from './intellihide.js'
+import * as Transparency from './transparency.js'
+import {
+ SETTINGS,
+ TILINGSETTINGS,
+ DESKTOPSETTINGS,
+ PERSISTENTSTORAGE,
+ EXTENSION_PATH,
+ tracker,
+ ZORIN_TILING_SHELL_UUID,
+} from './extension.js'
+import {
+ gettext as _,
+ InjectionManager,
+} from 'resource:///org/gnome/shell/extensions/extension.js'
+
+export const panelBoxes = ['_leftBox', '_centerBox', '_rightBox']
+
+//timeout names
+const T4 = 'showDesktopTimeout'
+const T5 = 'trackerFocusAppTimeout'
+const T6 = 'waitPanelBoxAllocation'
+
+const SHOW_SHOWDESKTOP_DELAY = 1000
+const SHOW_SHOWDESKTOP_TIME = 200
+const MIN_PANEL_SIZE = 22
+
+export const Panel = GObject.registerClass(
+ {},
+ class Panel extends St.Widget {
+ _init(panelManager, monitor, panelBox, isStandalone) {
+ super._init({
+ style_class: 'zorintaskbarPanel',
+ layout_manager: new Clutter.BinLayout(),
+ })
+
+ this._timeoutsHandler = new Utils.TimeoutsHandler()
+ this._signalsHandler = new Utils.GlobalSignalsHandler()
+ this._injectionManager = new InjectionManager()
+
+ this.panelManager = panelManager
+ this.panelStyle = new PanelStyle.PanelStyle()
+
+ this.monitor = monitor
+ this.panelBox = panelBox
+
+ // when the original gnome-shell top panel is kept, all panels are "standalone",
+ // so in this case use isPrimary to get the panel on the primary dtp monitor, which
+ // might be different from the system's primary monitor.
+ this.isStandalone = isStandalone
+ this.isPrimary =
+ !isStandalone ||
+ (SETTINGS.get_boolean('stockgs-keep-top-panel') &&
+ monitor == panelManager.dtpPrimaryMonitor)
+
+ this._sessionStyle = null
+ this._unmappedButtons = []
+ this._elementGroups = []
+
+ let systemMenuInfo = Utils.getSystemMenuInfo()
+
+ if (isStandalone) {
+ this.panel = new SecondaryPanel({ name: 'panel', reactive: true })
+ this.statusArea = this.panel.statusArea = {}
+
+ //next 3 functions are needed by other extensions to add elements to the secondary panel
+ this.panel.addToStatusArea = function (role, indicator, position, box) {
+ return Main.panel.addToStatusArea.call(
+ this,
+ role,
+ indicator,
+ position,
+ box,
+ )
+ }
+
+ this.panel._addToPanelBox = function (role, indicator, position, box) {
+ Main.panel._addToPanelBox.call(this, role, indicator, position, box)
+ }
+
+ this.panel._onMenuSet = function (indicator) {
+ Main.panel._onMenuSet.call(this, indicator)
+ }
+
+ this._leftBox = this.panel._leftBox = Utils.createBoxLayout({
+ name: 'panelLeft',
+ })
+ this._centerBox = this.panel._centerBox = Utils.createBoxLayout({
+ name: 'panelCenter',
+ })
+ this._rightBox = this.panel._rightBox = Utils.createBoxLayout({
+ name: 'panelRight',
+ })
+
+ this.menuManager = this.panel.menuManager =
+ new PopupMenu.PopupMenuManager(this.panel)
+
+ this._setPanelMenu(
+ systemMenuInfo.name,
+ systemMenuInfo.constructor,
+ this.panel,
+ )
+ this._setPanelMenu('dateMenu', DateMenu.DateMenuButton, this.panel)
+ this._setPanelMenu(
+ 'activities',
+ Main.panel.statusArea.activities.constructor,
+ this.panel,
+ )
+
+ this.panel.add_child(this._leftBox)
+ this.panel.add_child(this._centerBox)
+ this.panel.add_child(this._rightBox)
+ } else {
+ this.panel = Main.panel
+ this.statusArea = Main.panel.statusArea
+ this.menuManager = Main.panel.menuManager
+
+ panelBoxes.forEach((p) => (this[p] = Main.panel[p]))
+ ;['activities', systemMenuInfo.name, 'dateMenu'].forEach((b) => {
+ let container = this.statusArea[b].container
+ let parent = container.get_parent()
+ let siblings = parent.get_children()
+ let index = siblings.indexOf(container)
+
+ container._dtpOriginalParent = parent
+ container._dtpOriginalIndex =
+ index && index == siblings.length - 1 ? -1 : index
+ parent ? parent.remove_child(container) : null
+ this.panel.add_child(container)
+ })
+ }
+
+ this.geom = this.getGeometry()
+
+ // Create a wrapper around the real showAppsIcon in order to add a popupMenu. Most of
+ // its behavior is handled by the taskbar, but its positioning is done at the panel level
+ this.showAppsIconWrapper = new AppIcons.ShowAppsIconWrapper(this)
+ this.panel.add_child(this.showAppsIconWrapper.realShowAppsIcon)
+
+ this.panel._delegate = this
+
+ this.add_child(this.panel)
+
+ if (Main.panel._onButtonPress || Main.panel._tryDragWindow) {
+ this._signalsHandler.add([
+ this.panel,
+ ['button-press-event', 'touch-event'],
+ this._onButtonPress.bind(this),
+ ])
+ }
+
+ if (Main.panel._onKeyPress) {
+ this._signalsHandler.add([
+ this.panel,
+ 'key-press-event',
+ Main.panel._onKeyPress.bind(this),
+ ])
+ }
+
+ Main.ctrlAltTabManager.addGroup(
+ this,
+ _('Top Bar') + ' ' + monitor.index,
+ 'focus-top-bar-symbolic',
+ { sortGroup: CtrlAltTab.SortGroup.TOP },
+ )
+ }
+
+ enable() {
+ let { name: systemMenuName } = Utils.getSystemMenuInfo()
+
+ if (
+ this.statusArea[systemMenuName] &&
+ this.statusArea[systemMenuName]._volumeOutput
+ ) {
+ Utils.getIndicators(
+ this.statusArea[systemMenuName]._volumeOutput,
+ )._dtpIgnoreScroll = 1
+ }
+
+ this._setPanelBoxStyle()
+ this._maybeSetDockCss()
+ this._setPanelPosition()
+
+ if (!this.isStandalone) {
+ this._injectionManager.overrideMethod(
+ Object.getPrototypeOf(this.panel),
+ 'vfunc_allocate',
+ () => (box) => this._mainPanelAllocate(box),
+ )
+
+ // remove the extra space before the clock when the message-indicator is displayed
+ if (DateMenu.IndicatorPad) {
+ this._injectionManager.overrideMethod(
+ DateMenu.IndicatorPad.prototype,
+ 'vfunc_get_preferred_width',
+ () => () => [0, 0],
+ )
+ this._injectionManager.overrideMethod(
+ DateMenu.IndicatorPad.prototype,
+ 'vfunc_get_preferred_height',
+ () => () => [0, 0],
+ )
+ }
+ }
+
+ if (!DateMenu.IndicatorPad && this.statusArea.dateMenu) {
+ //3.36 switched to a size constraint applied on an anonymous child
+ let indicatorPad = this.statusArea.dateMenu
+ .get_first_child()
+ .get_first_child()
+
+ this._dateMenuIndicatorPadContraints = indicatorPad.get_constraints()
+ indicatorPad.clear_constraints()
+ }
+
+ this.menuManager._oldChangeMenu = this.menuManager._changeMenu
+ this.menuManager._changeMenu = (menu) => {
+ if (!SETTINGS.get_boolean('stockgs-panelbtn-click-only')) {
+ this.menuManager._oldChangeMenu(menu)
+ }
+ }
+
+ this.dynamicTransparency = new Transparency.DynamicTransparency(this)
+
+ this.taskbar = new Taskbar.Taskbar(this)
+
+ this.panel.add_child(this.taskbar.actor)
+
+ this._setShowDesktopButton(true)
+
+ this._setAllocationMap()
+
+ this.panel.add_style_class_name(
+ 'zorintaskbarMainPanel ' + this.getOrientation(),
+ )
+
+ this.intellihide = new Intellihide.Intellihide(this)
+
+ this._signalsHandler.add(
+ // this is to catch changes to the theme or window scale factor
+ [
+ Utils.getStageTheme(),
+ 'changed',
+ () => (this._resetGeometry(), this._setShowDesktopButtonStyle()),
+ ],
+ [
+ // sync hover after a popupmenu is closed
+ this.taskbar,
+ 'menu-closed',
+ () => this.panel.sync_hover(),
+ ],
+ [Main.overview, ['showing', 'hiding'], () => this._adjustForOverview()],
+ [
+ Main.overview,
+ 'hidden',
+ () => {
+ if (this.isPrimary) {
+ //reset the primary monitor when exiting the overview
+ this.panelManager.setFocusedMonitor(this.monitor)
+ }
+ },
+ ],
+ [
+ this.statusArea.activities,
+ 'captured-event',
+ (actor, e) => {
+ if (
+ e.type() == Clutter.EventType.BUTTON_PRESS ||
+ e.type() == Clutter.EventType.TOUCH_BEGIN
+ ) {
+ //temporarily use as primary the monitor on which the activities btn was clicked
+ this.panelManager.setFocusedMonitor(this.monitor)
+ }
+ },
+ ],
+ [
+ this._centerBox,
+ 'child-added',
+ () => this._onBoxActorAdded(this._centerBox),
+ ],
+ [
+ this._rightBox,
+ 'child-added',
+ () => this._onBoxActorAdded(this._rightBox),
+ ],
+ [Main.layoutManager, 'startup-complete', () => this._resetGeometry()],
+ )
+
+ this._bindSettingsChanges()
+
+ this.panelStyle.enable(this)
+
+ if (this.checkIfVertical()) {
+ this._signalsHandler.add([
+ this.panelBox,
+ 'notify::visible',
+ () => {
+ if (this.panelBox.visible) {
+ this._refreshVerticalAlloc()
+ }
+ },
+ ])
+
+ if (this.statusArea.dateMenu) {
+ this._formatVerticalClock()
+
+ this._signalsHandler.add([
+ this.statusArea.dateMenu._clock,
+ 'notify::clock',
+ () => this._formatVerticalClock(),
+ ])
+ }
+ }
+
+ // Since we are usually visible but not usually changing, make sure
+ // most repaint requests don't actually require us to repaint anything.
+ // This saves significant CPU when repainting the screen.
+ this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS)
+
+ if (!Main.layoutManager._startingUp)
+ GLib.idle_add(GLib.PRIORITY_LOW, () => {
+ this._resetGeometry()
+ return GLib.SOURCE_REMOVE
+ })
+ }
+
+ disable() {
+ this.panelStyle.disable()
+
+ this._timeoutsHandler.destroy()
+ this._signalsHandler.destroy()
+
+ this.panel.remove_child(this.taskbar.actor)
+
+ if (this.intellihide) {
+ this.intellihide.destroy()
+ }
+
+ this.dynamicTransparency.destroy()
+
+ this.taskbar.destroy()
+ this.showAppsIconWrapper.destroy()
+
+ this._setPanelBoxStyle(true)
+ this._maybeSetDockCss(true)
+
+ this.menuManager._changeMenu = this.menuManager._oldChangeMenu
+
+ this._unmappedButtons.forEach((a) => this._disconnectVisibleId(a))
+
+ if (this.statusArea.dateMenu) {
+ this.statusArea.dateMenu._clockDisplay.text =
+ this.statusArea.dateMenu._clock.clock
+ this.statusArea.dateMenu._clockDisplay.clutter_text.set_width(-1)
+
+ if (this._dateMenuIndicatorPadContraints) {
+ let indicatorPad = this.statusArea.dateMenu
+ .get_first_child()
+ .get_first_child()
+
+ this._dateMenuIndicatorPadContraints.forEach((c) =>
+ indicatorPad.add_constraint(c),
+ )
+ }
+ }
+
+ this._setVertical(this.panel, false)
+ this._setVertical(this._centerBox, false)
+ this._setVertical(this._rightBox, false)
+
+ let { name: systemMenuName } = Utils.getSystemMenuInfo()
+
+ if (!this.isStandalone) {
+ ;['vertical', 'horizontal', 'zorintaskbarMainPanel'].forEach((c) =>
+ this.panel.remove_style_class_name(c),
+ )
+
+ if (!Main.sessionMode.isLocked) {
+ ;['activities', systemMenuName, 'dateMenu'].forEach((b) => {
+ let container = this.statusArea[b].container
+ let originalParent = container._dtpOriginalParent
+
+ this.panel.remove_child(container)
+
+ if (originalParent) {
+ originalParent.visible = true
+
+ originalParent.insert_child_at_index(
+ container,
+ Math.min(
+ container._dtpOriginalIndex,
+ originalParent.get_children().length - 1,
+ ),
+ )
+ }
+
+ delete container._dtpOriginalParent
+ delete container._dtpOriginalIndex
+ })
+ }
+
+ this._setShowDesktopButton(false)
+
+ delete Utils.getIndicators(
+ this.statusArea[systemMenuName]._volumeOutput,
+ )._dtpIgnoreScroll
+
+ this._injectionManager.clear()
+
+ this.panel._delegate = this.panel
+ } else {
+ this._removePanelMenu('dateMenu')
+ this._removePanelMenu(systemMenuName)
+ this._removePanelMenu('activities')
+ }
+
+ Main.ctrlAltTabManager.removeGroup(this)
+ }
+
+ handleDragOver(source) {
+ if (
+ source == Main.xdndHandler &&
+ Main.overview.shouldToggleByCornerOrButton()
+ ) {
+ this.panelManager.showFocusedAppInOverview(null, true)
+ Main.overview.show()
+ }
+
+ return DND.DragMotionResult.CONTINUE
+ }
+
+ getPosition() {
+ let position = PanelSettings.getPanelPosition(
+ SETTINGS,
+ this.monitor.index,
+ )
+
+ if (position == Pos.TOP) {
+ return St.Side.TOP
+ } else if (position == Pos.RIGHT) {
+ return St.Side.RIGHT
+ } else if (position == Pos.BOTTOM) {
+ return St.Side.BOTTOM
+ }
+
+ return St.Side.LEFT
+ }
+
+ checkIfVertical() {
+ let position = this.getPosition()
+
+ return position == St.Side.LEFT || position == St.Side.RIGHT
+ }
+
+ getOrientation() {
+ return this.checkIfVertical() ? 'vertical' : 'horizontal'
+ }
+
+ updateElementPositions() {
+ let panelPositions = PanelSettings.getPanelElementPositions(
+ SETTINGS,
+ this.monitor.index,
+ )
+
+ this._updateGroupedElements(panelPositions)
+
+ this.panel.hide()
+ this.panel.show()
+ }
+
+ _updateGroupedElements(panelPositions) {
+ let previousPosition = 0
+ let previousCenteredPosition = 0
+ let currentGroup = -1
+
+ this._elementGroups = []
+
+ panelPositions.forEach((pos) => {
+ let allocationMap = this.allocationMap[pos.element]
+
+ if (allocationMap.actor) {
+ allocationMap.actor.visible = pos.visible
+
+ if (!pos.visible) return
+
+ // if the panel length is dynamic, get all visible
+ // elements as a single group
+ let currentPosition = this.geom.dynamic || pos.position
+ let isCentered = Pos.checkIfCentered(currentPosition)
+
+ if (
+ currentPosition == Pos.STACKED_TL &&
+ previousPosition == Pos.STACKED_BR
+ ) {
+ currentPosition = Pos.STACKED_BR
+ }
+
+ if (
+ !previousPosition ||
+ (previousPosition == Pos.STACKED_TL &&
+ currentPosition != Pos.STACKED_TL) ||
+ (previousPosition != Pos.STACKED_BR &&
+ currentPosition == Pos.STACKED_BR) ||
+ (isCentered &&
+ previousPosition != currentPosition &&
+ previousPosition != Pos.STACKED_BR)
+ ) {
+ this._elementGroups[++currentGroup] = {
+ elements: [],
+ index: this._elementGroups.length,
+ expandableIndex: -1,
+ }
+ previousCenteredPosition = 0
+ }
+
+ if (pos.element == Pos.TASKBAR) {
+ this._elementGroups[currentGroup].expandableIndex =
+ this._elementGroups[currentGroup].elements.length
+ }
+
+ if (isCentered && !this._elementGroups[currentGroup].isCentered) {
+ this._elementGroups[currentGroup].isCentered = 1
+ previousCenteredPosition = currentPosition
+ }
+
+ this._elementGroups[currentGroup].position =
+ previousCenteredPosition || currentPosition
+ this._elementGroups[currentGroup].elements.push(allocationMap)
+
+ allocationMap.position = currentPosition
+ previousPosition = currentPosition
+ }
+ })
+ }
+
+ _bindSettingsChanges() {
+ let isVertical = this.checkIfVertical()
+
+ this._signalsHandler.add(
+ [
+ SETTINGS,
+ [
+ 'changed::panel-margin',
+ 'changed::panel-sizes',
+ 'changed::group-apps',
+ ],
+ (settings, settingChanged) => {
+ PanelSettings.clearCache(settingChanged)
+ this._resetGeometry()
+ },
+ ],
+ [
+ SETTINGS,
+ [
+ 'changed::showdesktop-button-width',
+ 'changed::show-showdesktop-icon',
+ ],
+ () => this._setShowDesktopButtonStyle(),
+ ],
+ [
+ DESKTOPSETTINGS,
+ 'changed::clock-format',
+ () => {
+ this._clockFormat = null
+
+ if (isVertical) {
+ this._formatVerticalClock()
+ }
+ },
+ ],
+ )
+
+ if (isVertical) {
+ this._signalsHandler.add([
+ SETTINGS,
+ 'changed::group-apps-label-max-width',
+ () => this._resetGeometry(),
+ ])
+ }
+
+ if (TILINGSETTINGS != null) {
+ this._signalsHandler.add([
+ TILINGSETTINGS,
+ 'changed::outer-gaps',
+ () => this._resetGeometry(),
+ ])
+ }
+ }
+
+ _setPanelMenu(propName, constr, container) {
+ if (!this.statusArea[propName]) {
+ this.statusArea[propName] = this._getPanelMenu(propName, constr)
+ this.menuManager.addMenu(this.statusArea[propName].menu)
+ container.insert_child_at_index(this.statusArea[propName].container, 0)
+ }
+ }
+
+ _removePanelMenu(propName) {
+ if (this.statusArea[propName]) {
+ let parent = this.statusArea[propName].container.get_parent()
+
+ if (parent) {
+ parent.remove_child(this.statusArea[propName].container)
+ }
+
+ //calling this.statusArea[propName].destroy(); is buggy for now, gnome-shell never
+ //destroys those panel menus...
+ //since we can't destroy the menu (hence properly disconnect its signals), let's
+ //store it so the next time a panel needs one of its kind, we can reuse it instead
+ //of creating a new one
+ let panelMenu = this.statusArea[propName]
+
+ this.menuManager.removeMenu(panelMenu.menu)
+ PERSISTENTSTORAGE[propName].push(panelMenu)
+ this.statusArea[propName] = null
+ }
+ }
+
+ _getPanelMenu(propName, constr) {
+ PERSISTENTSTORAGE[propName] = PERSISTENTSTORAGE[propName] || []
+
+ if (!PERSISTENTSTORAGE[propName].length) {
+ PERSISTENTSTORAGE[propName].push(new constr())
+ }
+
+ return PERSISTENTSTORAGE[propName].pop()
+ }
+
+ _adjustForOverview() {
+ let isFocusedMonitor = this.panelManager.checkIfFocusedMonitor(
+ this.monitor,
+ )
+ let isOverview = !!Main.overview.visibleTarget
+ let isOverviewFocusedMonitor = isOverview && isFocusedMonitor
+ let isShown = !isOverview || isOverviewFocusedMonitor
+ let actorData = Utils.getTrackedActorData(this.panelBox)
+
+ // prevent the "chrome" to update the panelbox visibility while in overview
+ actorData.trackFullscreen = !isOverview
+
+ this.panelBox[isShown ? 'show' : 'hide']()
+ }
+
+ _resetGeometry() {
+ this._setPanelBoxStyle()
+ this.geom = this.getGeometry()
+ this._maybeSetDockCss()
+ this._setPanelPosition()
+ this.taskbar.resetAppIcons(true)
+ this.dynamicTransparency.updateExternalStyle()
+
+ if (this.checkIfVertical()) {
+ this.showAppsIconWrapper.realShowAppsIcon.toggleButton.set_width(
+ this.geom.innerSize,
+ )
+ this._refreshVerticalAlloc()
+ }
+ }
+
+ getGeometry() {
+ let isVertical = this.checkIfVertical()
+ let scaleFactor = Utils.getScaleFactor()
+ let panelBoxTheme = this.panelBox.get_theme_node()
+ let sideMargins =
+ panelBoxTheme.get_padding(St.Side.LEFT) +
+ panelBoxTheme.get_padding(St.Side.RIGHT)
+ let topBottomMargins =
+ panelBoxTheme.get_padding(St.Side.TOP) +
+ panelBoxTheme.get_padding(St.Side.BOTTOM)
+ let position = this.getPosition()
+ let panelLength = PanelSettings.getPanelLength(
+ SETTINGS,
+ this.monitor.index,
+ )
+ let anchor = PanelSettings.getPanelAnchor(SETTINGS, this.monitor.index)
+ let dynamic = panelLength == -1 ? Pos.anchorToPosition[anchor] : 0
+ let dockMode = false
+ let length = (dynamic ? 100 : panelLength) / 100
+ let gsTopPanelHeight = 0
+ let x = 0
+ let y = 0
+ let w = 0
+ let h = 0
+ let fixedPadding = 0
+ let varPadding = 0
+ let topOffset = 0
+ let iconSize = 0
+ let innerSize = 0
+ let outerSize = 0
+ let panelSize = PanelSettings.getPanelSize(SETTINGS, this.monitor.index)
+
+ iconSize = innerSize = outerSize = panelSize * scaleFactor
+
+ if (
+ SETTINGS.get_boolean('stockgs-keep-top-panel') &&
+ Main.layoutManager.primaryMonitor == this.monitor
+ ) {
+ gsTopPanelHeight = Main.layoutManager.panelBox.height
+ topOffset = position == St.Side.TOP ? gsTopPanelHeight : 0
+ }
+
+ if (isVertical) {
+ if (!SETTINGS.get_boolean('group-apps')) {
+ // add window title width and side padding of _dtpIconContainer when vertical
+ innerSize = outerSize +=
+ SETTINGS.get_int('group-apps-label-max-width') +
+ (AppIcons.DEFAULT_PADDING_SIZE * 2) / scaleFactor
+ }
+
+ this.sizeFunc = 'get_preferred_height'
+ this.fixedCoord = { c1: 'x1', c2: 'x2' }
+ this.varCoord = { c1: 'y1', c2: 'y2' }
+
+ w = innerSize
+ h = this.monitor.height * length - topBottomMargins - gsTopPanelHeight
+ dockMode = !!dynamic || topBottomMargins > 0 || h < this.monitor.height
+ outerSize += sideMargins
+ } else {
+ this.sizeFunc = 'get_preferred_width'
+ this.fixedCoord = { c1: 'y1', c2: 'y2' }
+ this.varCoord = { c1: 'x1', c2: 'x2' }
+
+ w = this.monitor.width * length - sideMargins
+ h = innerSize
+ dockMode = !!dynamic || sideMargins > 0 || w < this.monitor.width
+ outerSize += topBottomMargins - topOffset
+ }
+
+ if (position == St.Side.TOP) {
+ x = this.monitor.x
+ y = this.monitor.y
+ } else if (position == St.Side.LEFT) {
+ x = this.monitor.x
+ y = this.monitor.y + gsTopPanelHeight
+ } else if (position == St.Side.RIGHT) {
+ x = this.monitor.x + this.monitor.width - w - sideMargins
+ y = this.monitor.y + gsTopPanelHeight
+ } else {
+ //BOTTOM
+ x = this.monitor.x
+ y = this.monitor.y + this.monitor.height - h - topBottomMargins
+ }
+
+ if (length < 1) {
+ // fixed size, less than 100%, so adjust start coordinate
+ if (!isVertical && anchor == Pos.MIDDLE)
+ x += (this.monitor.width - w - sideMargins) * 0.5
+ else if (isVertical && anchor == Pos.MIDDLE)
+ y += (this.monitor.height - h - topBottomMargins) * 0.5
+ else if (!isVertical && anchor == Pos.END)
+ x += this.monitor.width - w - sideMargins
+ else if (isVertical && anchor == Pos.END)
+ y += this.monitor.height - h - topBottomMargins
+ }
+
+ innerSize -= fixedPadding * 2
+ iconSize -= fixedPadding * 2
+
+ return {
+ x,
+ y,
+ w,
+ h,
+ iconSize, // selected panel thickness in settings
+ innerSize, // excludes padding and margins
+ outerSize, // includes padding and margins
+ fixedPadding,
+ varPadding,
+ topOffset, // only if gnome-shell top panel is present and position is TOP
+ position,
+ dynamic,
+ dockMode,
+ }
+ }
+
+ _setAllocationMap() {
+ this.allocationMap = {}
+ let setMap = (name, actor) =>
+ (this.allocationMap[name] = {
+ actor: actor,
+ box: new Clutter.ActorBox(),
+ })
+
+ setMap(Pos.SHOW_APPS_BTN, this.showAppsIconWrapper.realShowAppsIcon)
+ setMap(
+ Pos.ACTIVITIES_BTN,
+ this.statusArea.activities ? this.statusArea.activities.container : 0,
+ )
+ setMap(Pos.LEFT_BOX, this._leftBox)
+ setMap(Pos.TASKBAR, this.taskbar.actor)
+ setMap(Pos.CENTER_BOX, this._centerBox)
+ setMap(Pos.DATE_MENU, this.statusArea.dateMenu.container)
+ setMap(
+ Pos.SYSTEM_MENU,
+ this.statusArea[Utils.getSystemMenuInfo().name].container,
+ )
+ setMap(Pos.RIGHT_BOX, this._rightBox)
+ setMap(Pos.DESKTOP_BTN, this._showDesktopButton)
+ }
+
+ _mainPanelAllocate(box) {
+ this.panel.set_allocation(box)
+ }
+
+ vfunc_allocate(box) {
+ let fixed = 0
+ let centeredMonitorGroup
+ let varSize = box[this.varCoord.c2] - box[this.varCoord.c1]
+ let fixedSize = box[this.fixedCoord.c2] - box[this.fixedCoord.c1]
+ let panelAlloc = new Clutter.ActorBox()
+ let assignGroupSize = (group, update) => {
+ group.size = 0
+ group.tlOffset = 0
+ group.brOffset = 0
+
+ group.elements.forEach((element) => {
+ if (!update) {
+ element.box[this.fixedCoord.c1] =
+ panelAlloc[this.fixedCoord.c1] + this.geom.fixedPadding
+ element.box[this.fixedCoord.c2] =
+ panelAlloc[this.fixedCoord.c2] - this.geom.fixedPadding
+ element.natSize = element.actor[this.sizeFunc](-1)[1]
+ }
+
+ if (!group.isCentered || Pos.checkIfCentered(element.position)) {
+ group.size += element.natSize
+ } else if (element.position == Pos.STACKED_TL) {
+ group.tlOffset += element.natSize
+ } else {
+ // Pos.STACKED_BR
+ group.brOffset += element.natSize
+ }
+ })
+
+ if (group.isCentered) {
+ group.size += Math.max(group.tlOffset, group.brOffset) * 2
+ group.tlOffset = Math.max(group.tlOffset - group.brOffset, 0)
+ }
+ }
+ let allocateGroup = (group, tlLimit, brLimit) => {
+ let startPosition = tlLimit
+ let currentPosition = 0
+
+ if (group.expandableIndex >= 0) {
+ let availableSize = brLimit - tlLimit
+ let expandable = group.elements[group.expandableIndex]
+ let i = 0
+ let l = this._elementGroups.length
+ let tlSize = 0
+ let brSize = 0
+
+ if (
+ centeredMonitorGroup &&
+ (centeredMonitorGroup != group ||
+ expandable.position != Pos.CENTERED_MONITOR)
+ ) {
+ if (
+ centeredMonitorGroup.index < group.index ||
+ (centeredMonitorGroup == group &&
+ expandable.position == Pos.STACKED_TL)
+ ) {
+ i = centeredMonitorGroup.index
+ } else {
+ l = centeredMonitorGroup.index
+ }
+ }
+
+ for (; i < l; ++i) {
+ let refGroup = this._elementGroups[i]
+
+ if (
+ i < group.index &&
+ (!refGroup.fixed || refGroup[this.varCoord.c2] > tlLimit)
+ ) {
+ tlSize += refGroup.size
+ } else if (
+ i > group.index &&
+ (!refGroup.fixed || refGroup[this.varCoord.c1] < brLimit)
+ ) {
+ brSize += refGroup.size
+ }
+ }
+
+ if (group.isCentered) {
+ availableSize -= Math.max(tlSize, brSize) * 2
+ } else {
+ availableSize -= tlSize + brSize
+ }
+
+ if (availableSize < group.size) {
+ expandable.natSize -=
+ (group.size - availableSize) *
+ (group.isCentered && !Pos.checkIfCentered(expandable.position)
+ ? 0.5
+ : 1)
+ assignGroupSize(group, true)
+ }
+ }
+
+ if (group.isCentered) {
+ startPosition = tlLimit + (brLimit - tlLimit - group.size) * 0.5
+ } else if (group.position == Pos.STACKED_BR) {
+ startPosition = brLimit - group.size
+ }
+
+ currentPosition = group.tlOffset + startPosition
+
+ group.elements.forEach((element) => {
+ element.box[this.varCoord.c1] = Math.round(currentPosition)
+ element.box[this.varCoord.c2] = Math.round(
+ (currentPosition += element.natSize),
+ )
+
+ element.actor.allocate(element.box)
+ })
+
+ group[this.varCoord.c1] = startPosition
+ group[this.varCoord.c2] = currentPosition
+ group.fixed = 1
+ ++fixed
+ }
+
+ panelAlloc[this.varCoord.c2] = varSize
+ panelAlloc[this.fixedCoord.c2] = fixedSize
+
+ this._elementGroups.forEach((group) => {
+ group.fixed = 0
+
+ assignGroupSize(group)
+
+ if (group.position == Pos.CENTERED_MONITOR) {
+ centeredMonitorGroup = group
+ }
+ })
+
+ if (this.geom.dynamic && this._elementGroups.length == 1) {
+ let dynamicGroup = this._elementGroups[0] // only one group if dynamic
+ let tl = box[this.varCoord.c1]
+ let br = box[this.varCoord.c2]
+ let groupSize = dynamicGroup.size + this.geom.varPadding * 2
+
+ if (this.geom.dynamic == Pos.STACKED_TL) {
+ br = Math.min(br, tl + groupSize)
+ } else if (this.geom.dynamic == Pos.STACKED_BR) {
+ tl = Math.max(tl, br - groupSize)
+ } else {
+ // CENTERED_MONITOR
+ let half = Math.max(0, Math.floor((br - tl - groupSize) * 0.5))
+
+ tl += half
+ br -= half
+ }
+
+ box[this.varCoord.c1] = tl
+ box[this.varCoord.c2] = br
+
+ panelAlloc[this.varCoord.c2] = Math.min(groupSize, br - tl)
+ }
+
+ this.set_allocation(box)
+ this.panel.allocate(panelAlloc)
+
+ // apply padding to panel's children, after panel allocation
+ panelAlloc[this.varCoord.c1] += this.geom.varPadding
+ panelAlloc[this.varCoord.c2] -= this.geom.varPadding
+
+ if (centeredMonitorGroup) {
+ allocateGroup(
+ centeredMonitorGroup,
+ panelAlloc[this.varCoord.c1],
+ panelAlloc[this.varCoord.c2],
+ )
+ }
+
+ let iterations = 0 //failsafe
+ while (fixed < this._elementGroups.length && ++iterations < 10) {
+ for (let i = 0, l = this._elementGroups.length; i < l; ++i) {
+ let group = this._elementGroups[i]
+
+ if (group.fixed) {
+ continue
+ }
+
+ let prevGroup = this._elementGroups[i - 1]
+ let nextGroup = this._elementGroups[i + 1]
+ let prevLimit =
+ prevGroup && prevGroup.fixed
+ ? prevGroup[this.varCoord.c2]
+ : centeredMonitorGroup && group.index > centeredMonitorGroup.index
+ ? centeredMonitorGroup[this.varCoord.c2]
+ : panelAlloc[this.varCoord.c1]
+ let nextLimit =
+ nextGroup && nextGroup.fixed
+ ? nextGroup[this.varCoord.c1]
+ : centeredMonitorGroup && group.index < centeredMonitorGroup.index
+ ? centeredMonitorGroup[this.varCoord.c1]
+ : panelAlloc[this.varCoord.c2]
+
+ if (group.position == Pos.STACKED_TL) {
+ allocateGroup(group, panelAlloc[this.varCoord.c1], nextLimit)
+ } else if (group.position == Pos.STACKED_BR) {
+ allocateGroup(group, prevLimit, panelAlloc[this.varCoord.c2])
+ } else if (
+ (!prevGroup || prevGroup.fixed) &&
+ (!nextGroup || nextGroup.fixed)
+ ) {
+ // CENTERED
+ allocateGroup(group, prevLimit, nextLimit)
+ }
+ }
+ }
+ }
+
+ _setPanelBoxStyle(disable) {
+ let style = ''
+
+ if (!disable) {
+ let topBottomMargins = SETTINGS.get_int('panel-margin')
+ let sideMargins = topBottomMargins
+
+ style = `padding: ${this.geom.topOffset + topBottomMargins}px ${sideMargins}px ${topBottomMargins}px;`
+
+ if (
+ TILINGSETTINGS != null &&
+ Main.extensionManager._extensionOrder.includes(ZORIN_TILING_SHELL_UUID) &&
+ TILINGSETTINGS.get_uint('outer-gaps') > 0
+ ) {
+ let position = this.getPosition()
+ let margin_offset = TILINGSETTINGS.get_uint('outer-gaps')
+ let value = 0
+
+ if (position == St.Side.TOP) {
+ value = topBottomMargins - margin_offset
+ style += `padding-bottom: ${value > 0 ? value : 0}px;`
+ } else if (position == St.Side.BOTTOM) {
+ value = this.geom.topOffset + topBottomMargins - margin_offset
+ style += `padding-top: ${value > 0 ? value : 0}px;`
+ } else if (position == St.Side.LEFT) {
+ value = sideMargins - margin_offset
+ style += `padding-right: ${value > 0 ? value : 0}px;`
+ } else if (position == St.Side.RIGHT) {
+ value = sideMargins - margin_offset
+ style += `padding-left: ${value > 0 ? value : 0}px;`
+ }
+ }
+ }
+
+ this.panelBox.set_style(style)
+ }
+
+ _maybeSetDockCss(disable) {
+ this.remove_style_class_name('dock')
+
+ if (!disable && this.geom.dockMode) this.add_style_class_name('dock')
+ }
+
+ _setPanelPosition() {
+ let clipContainer = this.panelBox.get_parent()
+
+ this.set_size(this.geom.w, this.geom.h)
+ clipContainer.set_position(this.geom.x, this.geom.y)
+
+ this._setVertical(this.panel, this.checkIfVertical())
+
+ // center the system menu popup relative to its panel button
+ if (this.statusArea.quickSettings?.menu) {
+ this.statusArea.quickSettings.menu._arrowSide = this.geom.position
+ this.statusArea.quickSettings.menu._arrowAlignment = 0.5
+ }
+
+ // styles for theming
+ Object.keys(St.Side).forEach((p) => {
+ let cssName = 'zorintaskbar' + p.charAt(0) + p.slice(1).toLowerCase()
+
+ this.panel[
+ (St.Side[p] == this.geom.position ? 'add' : 'remove') +
+ '_style_class_name'
+ ](cssName)
+ })
+
+ this._setPanelClip(clipContainer)
+
+ Main.layoutManager._updateHotCorners()
+ Main.layoutManager._updatePanelBarrier(this)
+ }
+
+ _setPanelClip(clipContainer) {
+ clipContainer = clipContainer || this.panelBox.get_parent()
+ this._timeoutsHandler.add([
+ T6,
+ 0,
+ () =>
+ Utils.setClip(
+ clipContainer,
+ clipContainer.x,
+ clipContainer.y,
+ this.panelBox.width,
+ this.panelBox.height,
+ 0,
+ this.geom.topOffset,
+ ),
+ ])
+ }
+
+ _onButtonPress(actor, event) {
+ let type = event.type()
+ let isPress = type == Clutter.EventType.BUTTON_PRESS
+ let button = isPress ? event.get_button() : -1
+ let [stageX, stageY] = event.get_coords()
+
+ if (
+ button == 3 &&
+ global.stage.get_actor_at_pos(
+ Clutter.PickMode.REACTIVE,
+ stageX,
+ stageY,
+ ) == this.panel
+ ) {
+ //right click on an empty part of the panel, temporarily borrow and display the showapps context menu
+ Main.layoutManager.setDummyCursorGeometry(stageX, stageY, 0, 0)
+
+ this.showAppsIconWrapper.createMenu()
+ this.showAppsIconWrapper.popupMenu(Main.layoutManager.dummyCursor)
+
+ return Clutter.EVENT_STOP
+ } else {
+ const targetActor = global.stage.get_event_actor(event)
+
+ if (
+ Main.modalCount > 0 ||
+ targetActor != actor ||
+ (!isPress && type != Clutter.EventType.TOUCH_BEGIN) ||
+ (isPress && button != 1)
+ ) {
+ return Clutter.EVENT_PROPAGATE
+ }
+ }
+
+ let params = this.checkIfVertical()
+ ? [stageY, 'y', 'height']
+ : [stageX, 'x', 'width']
+ let dragWindow = this._getDraggableWindowForPosition.apply(
+ this,
+ params.concat(['maximized_' + this.getOrientation() + 'ly']),
+ )
+
+ if (!dragWindow) return Clutter.EVENT_PROPAGATE
+
+ dragWindow.begin_grab_op(
+ Meta.GrabOp.MOVING,
+ event.get_device(),
+ event.get_event_sequence(),
+ event.get_time(),
+ new Graphene.Point({ x: stageX, y: stageY }),
+ )
+
+ return Clutter.EVENT_STOP
+ }
+
+ _getDraggableWindowForPosition(
+ stageCoord,
+ coord,
+ dimension,
+ maximizedProp,
+ ) {
+ let workspace = Utils.getCurrentWorkspace()
+ let allWindowsByStacking = global.display
+ .sort_windows_by_stacking(workspace.list_windows())
+ .reverse()
+
+ return Utils.find(allWindowsByStacking, (metaWindow) => {
+ let rect = metaWindow.get_frame_rect()
+
+ return (
+ metaWindow.get_monitor() == this.monitor.index &&
+ metaWindow.showing_on_its_workspace() &&
+ metaWindow.get_window_type() != Meta.WindowType.DESKTOP &&
+ metaWindow[maximizedProp] &&
+ stageCoord > rect[coord] &&
+ stageCoord < rect[coord] + rect[dimension]
+ )
+ })
+ }
+
+ _onBoxActorAdded(box) {
+ if (this.checkIfVertical()) {
+ this._setVertical(box, true)
+ }
+ }
+
+ _refreshVerticalAlloc() {
+ this._setVertical(this._centerBox, true)
+ this._setVertical(this._rightBox, true)
+ this._formatVerticalClock()
+ }
+
+ _setVertical(actor, isVertical) {
+ let _set = (actor, isVertical) => {
+ if (
+ !actor ||
+ actor instanceof Dash.DashItemContainer ||
+ actor instanceof TaskbarItemContainer.TaskbarItemContainer
+ ) {
+ return
+ }
+
+ if (actor instanceof St.BoxLayout) {
+ Utils.setBoxLayoutVertical(actor, isVertical)
+ } else if (
+ actor != this.statusArea.appMenu &&
+ ((actor._delegate || actor) instanceof PanelMenu.ButtonBox ||
+ actor == this.statusArea.quickSettings)
+ ) {
+ let child = actor.get_first_child()
+
+ if (isVertical && !actor.visible && !actor._dtpVisibleId) {
+ this._unmappedButtons.push(actor)
+ actor._dtpVisibleId = actor.connect('notify::visible', () => {
+ this._disconnectVisibleId(actor)
+ this._refreshVerticalAlloc()
+ })
+ actor._dtpDestroyId = actor.connect('destroy', () =>
+ this._disconnectVisibleId(actor),
+ )
+ }
+
+ if (child) {
+ let [, natWidth] = actor.get_preferred_width(-1)
+
+ child.x_align = Clutter.ActorAlign[isVertical ? 'CENTER' : 'START']
+ actor.set_width(isVertical ? this.geom.innerSize : -1)
+ isVertical = isVertical && natWidth > this.geom.innerSize
+ actor[(isVertical ? 'add' : 'remove') + '_style_class_name'](
+ 'vertical',
+ )
+ }
+ }
+
+ actor.get_children().forEach((c) => _set(c, isVertical))
+ }
+
+ _set(actor, false)
+
+ if (isVertical) _set(actor, isVertical)
+ }
+
+ _disconnectVisibleId(actor) {
+ actor.disconnect(actor._dtpVisibleId)
+ actor.disconnect(actor._dtpDestroyId)
+
+ delete actor._dtpVisibleId
+ delete actor._dtpDestroyId
+
+ this._unmappedButtons.splice(this._unmappedButtons.indexOf(actor), 1)
+ }
+
+ _formatVerticalClock() {
+ // https://github.com/GNOME/gnome-desktop/blob/master/libgnome-desktop/gnome-wall-clock.c#L310
+ if (this.statusArea.dateMenu) {
+ let datetime = this.statusArea.dateMenu._clock.clock
+ let datetimeParts = datetime.split(' ')
+ let time = datetimeParts[1]
+ let clockText = this.statusArea.dateMenu._clockDisplay.clutter_text
+ let setClockText = (text, useTimeSeparator) => {
+ let stacks = text instanceof Array
+ let separator = `\n ${useTimeSeparator ? '‧‧' : '—'} \n`
+
+ clockText.set_text((stacks ? text.join(separator) : text).trim())
+ clockText.set_use_markup(stacks)
+ clockText.get_allocation_box()
+
+ return !clockText.get_layout().is_ellipsized()
+ }
+
+ if (clockText.ellipsize == Pango.EllipsizeMode.NONE) {
+ //on gnome-shell 3.36.4, the clockdisplay isn't ellipsize anymore, so set it back
+ clockText.ellipsize = Pango.EllipsizeMode.END
+ }
+
+ clockText.natural_width = this.geom.innerSize
+
+ if (!time) {
+ datetimeParts = datetime.split(' ')
+ time = datetimeParts.pop()
+ datetimeParts = [datetimeParts.join(' '), time]
+ }
+
+ if (
+ !setClockText(datetime) &&
+ !setClockText(datetimeParts) &&
+ !setClockText(time)
+ ) {
+ let timeParts = time.split('∶')
+
+ if (!this._clockFormat) {
+ this._clockFormat = DESKTOPSETTINGS.get_string('clock-format')
+ }
+
+ if (this._clockFormat == '12h') {
+ timeParts.push.apply(timeParts, timeParts.pop().split(' '))
+ }
+
+ setClockText(timeParts, true)
+ }
+ }
+ }
+
+ _setShowDesktopButton(add) {
+ if (add) {
+ if (this._showDesktopButton) return
+
+ this._showDesktopButton = new St.Bin({
+ style_class: 'panel-button',
+ reactive: true,
+ can_focus: true,
+ // x_fill: true,
+ // y_fill: true,
+ track_hover: true,
+ })
+
+ this._showDesktopButton.icon = new St.Icon({
+ gicon: Gio.icon_new_for_string(
+ `${EXTENSION_PATH}/img/show-desktop-symbolic.svg`
+ ),
+ style_class: 'system-status-icon'
+ })
+
+ this._setShowDesktopButtonStyle()
+
+ this._showDesktopButton.connect('touch-event', (actor, event) => {
+ if (event.type() == Clutter.EventType.TOUCH_BEGIN) {
+ this._onShowDesktopButtonPress()
+ }
+ })
+ this._showDesktopButton.connect('button-press-event', () =>
+ this._onShowDesktopButtonPress(),
+ )
+ this._showDesktopButton.connect('enter-event', () => {
+ if (SETTINGS.get_boolean('show-showdesktop-hover')) {
+ this._timeoutsHandler.add([
+ T4,
+ SHOW_SHOWDESKTOP_DELAY,
+ () => {
+ this._hiddenDesktopWorkspace =
+ Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace()
+ this._toggleWorkspaceWindows(true, this._hiddenDesktopWorkspace)
+ },
+ ])
+ }
+ })
+
+ this._showDesktopButton.connect('leave-event', () => {
+ if (SETTINGS.get_boolean('show-showdesktop-hover')) {
+ if (this._timeoutsHandler.getId(T4)) {
+ this._timeoutsHandler.remove(T4)
+ } else if (this._hiddenDesktopWorkspace) {
+ this._toggleWorkspaceWindows(false, this._hiddenDesktopWorkspace)
+ }
+ }
+ })
+
+ this.panel.add_child(this._showDesktopButton)
+ } else {
+ if (!this._showDesktopButton) return
+
+ this.panel.remove_child(this._showDesktopButton)
+ this._showDesktopButton.destroy()
+ this._showDesktopButton = null
+ }
+ }
+
+ _setShowDesktopButtonStyle() {
+ let rgb = this._getBackgroundBrightness()
+ ? 'rgba(55, 55, 55, .2)'
+ : 'rgba(200, 200, 200, .2)'
+
+ for (let i = 0; i < this._showDesktopButton.get_children().length; i++) {
+ if (this._showDesktopButton.get_children()[i] == this._showDesktopButton.icon) {
+ this._showDesktopButton.remove_child(this._showDesktopButton.icon)
+ }
+ }
+
+ if (this._showDesktopButton) {
+ if (SETTINGS.get_boolean('show-showdesktop-icon')) {
+ this._showDesktopButton.add_child(this._showDesktopButton.icon)
+
+ let buttonSize = SETTINGS.get_int('showdesktop-button-width') + 'px;'
+ let isVertical = this.checkIfVertical()
+ let buttonPadding = isVertical ? buttonSize + ' 0;' : '0 ' + buttonSize + ';'
+
+ this._showDesktopButton.set_style('padding: ' + buttonPadding + ';')
+ } else {
+ let buttonSize = SETTINGS.get_int('showdesktop-button-width') + 'px;'
+ let isVertical = this.checkIfVertical()
+
+ let style = 'border: 0 solid ' + rgb + '; padding: 0;'
+ style += isVertical
+ ? 'border-top-width:1px;height:' + buttonSize
+ : 'border-left-width:1px;width:' + buttonSize
+
+ this._showDesktopButton.set_style(style)
+ this._showDesktopButton[(isVertical ? 'x' : 'y') + '_expand'] = true
+ }
+ }
+ }
+
+ // _getBackgroundBrightness: return true if panel has a bright background color
+ _getBackgroundBrightness() {
+ return Utils.checkIfColorIsBright(
+ this.dynamicTransparency.backgroundColorRgb,
+ )
+ }
+
+ _toggleWorkspaceWindows(hide, workspace) {
+ let time = SHOW_SHOWDESKTOP_TIME * 0.001
+
+ workspace.list_windows().forEach((w) => {
+ if (!w.minimized && !w.customJS_ding && w.window_type != Meta.WindowType.DESKTOP) {
+ let tweenOpts = {
+ opacity: hide ? 0 : 255,
+ time: time,
+ transition: 'easeOutQuad',
+ }
+
+ Utils.animateWindowOpacity(w.get_compositor_private(), tweenOpts)
+ }
+ })
+ }
+
+ _onShowDesktopButtonPress() {
+ let label = 'trackerFocusApp'
+
+ this._signalsHandler.removeWithLabel(label)
+ this._timeoutsHandler.remove(T5)
+
+ if (this._restoreWindowList && this._restoreWindowList.length) {
+ this._timeoutsHandler.remove(T4)
+
+ let current_workspace =
+ Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace()
+ let windows = current_workspace.list_windows()
+ this._restoreWindowList.forEach(function (w) {
+ if (windows.indexOf(w) > -1) Main.activateWindow(w)
+ })
+ this._restoreWindowList = null
+ } else {
+ let current_workspace =
+ Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace()
+ let windows = current_workspace.list_windows().filter(function (w) {
+ return w.showing_on_its_workspace() && !w.skip_taskbar
+ })
+ windows = global.display.sort_windows_by_stacking(windows)
+
+ windows.forEach(function (w) {
+ w.minimize()
+ })
+
+ this._restoreWindowList = windows
+
+ this._timeoutsHandler.add([
+ T5,
+ 20,
+ () =>
+ this._signalsHandler.addWithLabel(label, [
+ tracker,
+ 'notify::focus-app',
+ () => (this._restoreWindowList = null),
+ ]),
+ ])
+ }
+
+ Main.overview.hide()
+ }
+ },
+)
+
+export const SecondaryPanel = GObject.registerClass(
+ {},
+ class SecondaryPanel extends St.Widget {
+ _init(params) {
+ super._init(params)
+ }
+
+ vfunc_allocate(box) {
+ this.set_allocation(box)
+ }
+ },
+)
diff --git a/src/panelManager.js b/src/panelManager.js
new file mode 100644
index 0000000..5b2e9a2
--- /dev/null
+++ b/src/panelManager.js
@@ -0,0 +1,1083 @@
+/*
+ * 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 .
+ *
+ * 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.
+ */
+
+import * as Overview from './overview.js'
+import * as Panel from './panel.js'
+import * as PanelSettings from './panelSettings.js'
+import * as Proximity from './proximity.js'
+import * as Utils from './utils.js'
+import * as DesktopIconsIntegration from './desktopIconsIntegration.js'
+import { DTP_EXTENSION, SETTINGS, tracker } from './extension.js'
+
+import GLib from 'gi://GLib'
+import GObject from 'gi://GObject'
+import Clutter from 'gi://Clutter'
+import Meta from 'gi://Meta'
+import Shell from 'gi://Shell'
+import St from 'gi://St'
+
+import * as BoxPointer from 'resource:///org/gnome/shell/ui/boxpointer.js'
+import * as LookingGlass from 'resource:///org/gnome/shell/ui/lookingGlass.js'
+import * as Main from 'resource:///org/gnome/shell/ui/main.js'
+import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js'
+import { NotificationsMonitor } from './notificationsMonitor.js'
+import { Workspace } from 'resource:///org/gnome/shell/ui/workspace.js'
+import * as Layout from 'resource:///org/gnome/shell/ui/layout.js'
+import { InjectionManager } from 'resource:///org/gnome/shell/extensions/extension.js'
+import {
+ SecondaryMonitorDisplay,
+ WorkspacesView,
+} from 'resource:///org/gnome/shell/ui/workspacesView.js'
+
+export const PanelManager = class {
+ constructor() {
+ this.overview = new Overview.Overview(this)
+ this._injectionManager = new InjectionManager()
+ }
+
+ 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,
+ SETTINGS.get_boolean('stockgs-keep-top-panel'),
+ )
+ this.allPanels.push(this.primaryPanel)
+ this.overview.enable(this.primaryPanel)
+
+ this.setFocusedMonitor(this.dtpPrimaryMonitor)
+ }
+
+ if (SETTINGS.get_boolean('multi-monitors')) {
+ Main.layoutManager.monitors
+ .filter((m) => m != this.dtpPrimaryMonitor)
+ .forEach((m) => {
+ this.allPanels.push(this._createPanel(m, true))
+ })
+ }
+
+ global.zorinTaskbar.panels = this.allPanels
+ global.zorinTaskbar.emit('panels-created')
+
+ this._setDesktopIconsMargins()
+
+ this._updatePanelElementPositions()
+
+ if (reset) return
+
+ this.notificationsMonitor = new NotificationsMonitor()
+
+ 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()
+
+ Main.layoutManager.findIndexForActor = (actor) =>
+ '_dtpIndex' in actor
+ ? actor._dtpIndex
+ : Layout.LayoutManager.prototype.findIndexForActor.call(
+ Main.layoutManager,
+ actor,
+ )
+
+ 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,
+ )
+
+ let panelManager = this
+ this._injectionManager.overrideMethod(
+ BoxPointer.BoxPointer.prototype,
+ 'vfunc_get_preferred_height',
+ () =>
+ function (forWidth) {
+ let alloc = { min_size: 0, natural_size: 0 }
+
+ ;[alloc.min_size, alloc.natural_size] =
+ this.vfunc_get_preferred_height(forWidth)
+
+ return panelManager._getBoxPointerPreferredHeight(this, alloc)
+ },
+ )
+
+ this._injectionManager.overrideMethod(
+ Object.getPrototypeOf(
+ // WorkspaceDot in activities button
+ Main.panel.statusArea.activities.get_first_child().get_first_child(),
+ ),
+ 'vfunc_get_preferred_width',
+ (get_preferred_width) =>
+ function (forHeight) {
+ return Utils.getBoxLayoutVertical(this.get_parent())
+ ? [0, forHeight]
+ : get_preferred_width.call(this, forHeight)
+ },
+ )
+
+ 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
+
+ Main.messageTray._bannerBin.ease = (params) => {
+ if (params.y === 0) {
+ let panelOnPrimary = this.allPanels.find(
+ (p) => p.monitor == Main.layoutManager.primaryMonitor,
+ )
+
+ if (
+ panelOnPrimary &&
+ panelOnPrimary.intellihide?.enabled &&
+ panelOnPrimary.geom.position == St.Side.TOP &&
+ panelOnPrimary.panelBox.visible
+ )
+ params.y += panelOnPrimary.geom.outerSize
+ }
+
+ Object.getPrototypeOf(Main.messageTray._bannerBin).ease.call(
+ Main.messageTray._bannerBin,
+ params,
+ )
+ }
+
+ this._signalsHandler = new Utils.GlobalSignalsHandler()
+
+ //listen settings
+ this._signalsHandler.add(
+ [
+ SETTINGS,
+ 'changed::global-border-radius',
+ () => DTP_EXTENSION.resetGlobalStyles(),
+ ],
+ [
+ SETTINGS,
+ [
+ 'changed::multi-monitors',
+ 'changed::isolate-monitors',
+ 'changed::panel-positions',
+ 'changed::panel-lengths',
+ 'changed::panel-anchors',
+ 'changed::stockgs-keep-top-panel',
+ ],
+ (settings, settingChanged) => {
+ PanelSettings.clearCache(settingChanged)
+ this._reset()
+ },
+ ],
+ [
+ SETTINGS,
+ 'changed::panel-element-positions',
+ () => {
+ PanelSettings.clearCache('panel-element-positions')
+ this._updatePanelElementPositions()
+ },
+ ],
+ [
+ SETTINGS,
+ 'changed::intellihide-key-toggle-text',
+ () => this._setKeyBindings(true),
+ ],
+ [
+ SETTINGS,
+ 'changed::panel-sizes',
+ () => {
+ GLib.idle_add(GLib.PRIORITY_LOW, () => {
+ this._setDesktopIconsMargins()
+ return GLib.SOURCE_REMOVE
+ })
+ },
+ ],
+ [
+ Utils.DisplayWrapper.getMonitorManager(),
+ 'monitors-changed',
+ async () => {
+ if (Main.layoutManager.primaryMonitor) {
+ await PanelSettings.setMonitorsInfo(SETTINGS)
+ this._reset()
+ }
+ },
+ ],
+ )
+
+ Panel.panelBoxes.forEach((c) =>
+ this._signalsHandler.add([
+ Main.panel[c],
+ 'child-added',
+ (parent, child) => {
+ this.primaryPanel &&
+ child instanceof St.Bin &&
+ this._adjustPanelMenuButton(
+ this._getPanelMenuButton(child.get_first_child()),
+ this.primaryPanel.monitor,
+ this.primaryPanel.getPosition(),
+ )
+ },
+ ]),
+ )
+
+ this._setKeyBindings(true)
+
+ // keep GS overview.js from blowing away custom panel styles
+ if (!SETTINGS.get_boolean('stockgs-keep-top-panel'))
+ Object.defineProperty(Main.panel, 'style', {
+ configurable: true,
+ set() {},
+ })
+ }
+
+ disable(reset) {
+ this.primaryPanel && this.overview.disable()
+ this.proximityManager.destroy()
+
+ this.allPanels.forEach((p) => {
+ p.taskbar.iconAnimator.pause()
+
+ this._findPanelMenuButtons(p.panelBox).forEach((pmb) => {
+ if (pmb.menu._boxPointer._dtpGetPreferredHeightId) {
+ pmb.menu._boxPointer._container.disconnect(
+ pmb.menu._boxPointer._dtpGetPreferredHeightId,
+ )
+ }
+
+ pmb.menu._boxPointer.sourceActor = pmb.menu._boxPointer._dtpSourceActor
+ delete pmb.menu._boxPointer._dtpSourceActor
+ pmb.menu._boxPointer._userArrowSide = St.Side.TOP
+ })
+
+ this._removePanelBarriers(p)
+
+ p.disable()
+
+ let clipContainer = p.panelBox.get_parent()
+
+ Main.layoutManager._untrackActor(p.panelBox)
+ Main.layoutManager.removeChrome(clipContainer)
+
+ if (p.isStandalone) {
+ p.panelBox.destroy()
+ } else {
+ p.panelBox.remove_child(p)
+ p.remove_child(p.panel)
+ p.panelBox.add_child(p.panel)
+
+ p.panelBox.set_position(clipContainer.x, clipContainer.y)
+
+ clipContainer.remove_child(p.panelBox)
+ Main.layoutManager.addChrome(p.panelBox, {
+ affectsStruts: true,
+ trackFullscreen: true,
+ })
+ }
+ })
+
+ 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._injectionManager.clear()
+
+ this._setKeyBindings(false)
+
+ this.notificationsMonitor.destroy()
+
+ this._signalsHandler.destroy()
+
+ Main.layoutManager._updateHotCorners = this._oldUpdateHotCorners
+ Main.layoutManager._updateHotCorners()
+
+ delete Main.layoutManager.findIndexForActor
+
+ 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.messageTray._bannerBin.ease
+
+ 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.outerSize,
+ 0,
+ 0,
+ 0,
+ )
+ break
+ case St.Side.BOTTOM:
+ this._desktopIconsUsableArea?.setMargins(
+ p.monitor.index,
+ 0,
+ p.geom.outerSize,
+ 0,
+ 0,
+ )
+ break
+ case St.Side.LEFT:
+ this._desktopIconsUsableArea?.setMargins(
+ p.monitor.index,
+ 0,
+ 0,
+ p.geom.outerSize,
+ 0,
+ )
+ break
+ case St.Side.RIGHT:
+ this._desktopIconsUsableArea?.setMargins(
+ p.monitor.index,
+ 0,
+ 0,
+ 0,
+ p.geom.outerSize,
+ )
+ break
+ }
+ })
+ }
+
+ setFocusedMonitor(monitor) {
+ this.focusedMonitorPanel = this.allPanels.find((p) => p.monitor == monitor)
+
+ if (!this.checkIfFocusedMonitor(monitor)) {
+ Main.overview._overview.clear_constraints()
+ Main.overview._overview.add_constraint(
+ new Layout.MonitorConstraint({ index: monitor.index }),
+ )
+
+ Main.overview._overview._controls._workspacesDisplay._primaryIndex =
+ monitor.index
+
+ // https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2395
+ // The overview allocation used to calculate its workarea based on the monitor where the overview
+ // was displayed, but it got changed back to always use the primary monitor. So now, temporarily assign
+ // the primary monitor to dtp focused monitor while recalculating the overview workarea
+ Main.layoutManager.primaryMonitor = monitor
+ Main.overview._overview._controls.layout_manager._updateWorkAreaBox()
+ Main.layoutManager.primaryMonitor =
+ Main.layoutManager.monitors[Main.layoutManager.primaryIndex]
+ }
+ }
+
+ showFocusedAppInOverview(app, keepOverviewOpen) {
+ if (app == this.focusedApp) {
+ if (!keepOverviewOpen && Main.overview._shown) Main.overview.hide()
+
+ return
+ }
+
+ let isolateWorkspaces = SETTINGS.get_boolean('isolate-workspaces')
+ let isolateMonitors = SETTINGS.get_boolean('isolate-monitors')
+
+ this.focusedApp = app
+
+ if (!this._signalsHandler.hasLabel('overview-spread')) {
+ let hasWorkspaces = Main.sessionMode.hasWorkspaces
+ let maybeDisableWorkspacesClick = () => {
+ if (!isolateWorkspaces)
+ Utils.getOverviewWorkspaces().forEach(
+ (w) => (w._container.get_actions()[0].enabled = false),
+ )
+ }
+ let isIncludedWindow = (metaWindow) =>
+ !this.focusedApp ||
+ tracker.get_window_app(metaWindow) == this.focusedApp
+
+ Main.sessionMode.hasWorkspaces = isolateWorkspaces
+ maybeDisableWorkspacesClick()
+
+ Workspace.prototype._oldIsMyWindow = Workspace.prototype._isMyWindow
+ Workspace.prototype._isMyWindow = function (metaWindow) {
+ if (!metaWindow) return false
+
+ return (
+ isIncludedWindow(metaWindow) &&
+ (this.metaWorkspace === null ||
+ (!isolateWorkspaces && this.metaWorkspace.active) ||
+ (isolateWorkspaces &&
+ metaWindow.located_on_workspace(this.metaWorkspace))) &&
+ (!isolateMonitors || metaWindow.get_monitor() === this.monitorIndex)
+ )
+ }
+
+ this.focusedWorkspace = !isolateWorkspaces
+ ? Utils.getCurrentWorkspace()
+ : null
+
+ this._signalsHandler.addWithLabel(
+ 'overview-spread',
+ [Main.overview, 'showing', maybeDisableWorkspacesClick],
+ [
+ Main.overview,
+ 'hidden',
+ () => {
+ Utils.getCurrentWorkspace()
+ .list_windows()
+ .forEach((w) => {
+ if (
+ !w.minimized &&
+ !w.customJS_ding &&
+ global.display.focus_window != w &&
+ tracker.get_window_app(w) != this.focusedApp
+ ) {
+ let window = w.get_compositor_private()
+
+ ;(window.get_first_child() || window).opacity = 0
+
+ Utils.animateWindowOpacity(window, {
+ opacity: 255,
+ time: 0.25,
+ transition: 'easeOutQuad',
+ })
+ }
+ })
+
+ this.focusedApp = null
+ this.focusedWorkspace = null
+ this._signalsHandler.removeWithLabel('overview-spread')
+
+ Main.sessionMode.hasWorkspaces = hasWorkspaces
+
+ Workspace.prototype._isMyWindow = Workspace.prototype._oldIsMyWindow
+ delete Workspace.prototype._oldIsMyWindow
+ },
+ ],
+ )
+ }
+
+ if (Main.overview._shown) {
+ Utils.getOverviewWorkspaces().forEach((w) => {
+ let metaWindows = []
+ let metaWorkspace =
+ w.metaWorkspace ||
+ Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace()
+
+ w._container.layout_manager._windows.forEach((info, preview) =>
+ preview.destroy(),
+ )
+
+ if (this.focusedWorkspace && this.focusedWorkspace == metaWorkspace)
+ metaWindows = Utils.getAllMetaWindows()
+ else if (!this.focusedWorkspace)
+ metaWindows = metaWorkspace.list_windows()
+
+ metaWindows.forEach((mw) => w._doAddWindow(mw))
+ })
+ } else Main.overview.show()
+ }
+
+ _newSetPrimaryWorkspaceVisible(visible) {
+ if (this._primaryVisible === visible) return
+
+ this._primaryVisible = visible
+
+ const primaryIndex =
+ Main.overview._overview._controls._workspacesDisplay._primaryIndex
+ const primaryWorkspace = this._workspacesViews[primaryIndex]
+ if (primaryWorkspace) primaryWorkspace.visible = visible
+ }
+
+ _newUpdateWorkspacesViews() {
+ for (let i = 0; i < this._workspacesViews.length; i++)
+ this._workspacesViews[i].destroy()
+
+ this._workspacesViews = []
+ let monitors = Main.layoutManager.monitors
+ for (let i = 0; i < monitors.length; i++) {
+ let view
+ if (i === this._primaryIndex) {
+ view = new WorkspacesView(
+ i,
+ this._controls,
+ this._scrollAdjustment,
+ this._fitModeAdjustment,
+ this._overviewAdjustment,
+ )
+
+ view.visible = this._primaryVisible
+ this.bind_property(
+ 'opacity',
+ view,
+ 'opacity',
+ GObject.BindingFlags.SYNC_CREATE,
+ )
+ this.add_child(view)
+ } else {
+ // No idea why atm, but we need the import at the top of this file and to use the
+ // full imports ns here, otherwise SecondaryMonitorDisplay can't be used ¯\_(ツ)_/¯
+ view = new SecondaryMonitorDisplay(
+ i,
+ this._controls,
+ this._scrollAdjustment,
+ this._fitModeAdjustment,
+ this._overviewAdjustment,
+ )
+ Main.layoutManager.overviewGroup.add_child(view)
+ }
+
+ this._workspacesViews.push(view)
+ }
+ }
+
+ 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 Utils.createBoxLayout({ name: 'panelBox' })
+ } else {
+ panelBox = Main.layoutManager.panelBox
+ Main.layoutManager._untrackActor(panelBox)
+ panelBox.remove_child(Main.panel)
+ Main.layoutManager.removeChrome(panelBox)
+ }
+
+ Main.layoutManager.addChrome(clipContainer, { affectsInputRegion: false })
+ clipContainer.add_child(panelBox)
+ Main.layoutManager.trackChrome(panelBox, {
+ trackFullscreen: true,
+ affectsStruts: true,
+ affectsInputRegion: true,
+ })
+
+ panel = new Panel.Panel(this, monitor, panelBox, isStandalone)
+ panelBox.add_child(panel)
+ panel.enable()
+
+ panelBox._dtpIndex = monitor.index
+ panelBox.set_position(0, 0)
+
+ if (panel.checkIfVertical) panelBox.set_width(-1)
+
+ this._findPanelMenuButtons(panelBox).forEach((pmb) =>
+ this._adjustPanelMenuButton(pmb, monitor, panel.getPosition()),
+ )
+
+ panel.taskbar.iconAnimator.start()
+
+ return panel
+ }
+
+ _reset() {
+ this.disable(true)
+ this.allPanels = []
+ this.enable(true)
+ }
+
+ _updatePanelElementPositions() {
+ this.allPanels.forEach((p) => p.updateElementPositions())
+ }
+
+ _adjustPanelMenuButton(button, monitor, arrowSide) {
+ if (button) {
+ button.menu._boxPointer._dtpSourceActor =
+ button.menu._boxPointer.sourceActor
+ button.menu._boxPointer.sourceActor = button
+ button.menu._boxPointer._userArrowSide = arrowSide
+ button.menu._boxPointer._dtpInPanel = 1
+
+ if (!button.menu._boxPointer.vfunc_get_preferred_height) {
+ button.menu._boxPointer._dtpGetPreferredHeightId =
+ button.menu._boxPointer._container.connect(
+ 'get-preferred-height',
+ (actor, forWidth, alloc) => {
+ this._getBoxPointerPreferredHeight(
+ button.menu._boxPointer,
+ alloc,
+ monitor,
+ )
+ },
+ )
+ }
+ }
+ }
+
+ _getBoxPointerPreferredHeight(boxPointer, alloc, monitor) {
+ if (
+ boxPointer._dtpInPanel &&
+ boxPointer.sourceActor &&
+ SETTINGS.get_boolean('intellihide')
+ ) {
+ monitor =
+ monitor ||
+ Main.layoutManager.findMonitorForActor(boxPointer.sourceActor)
+ let panel = Utils.find(
+ global.zorinTaskbar.panels,
+ (p) => p.monitor == monitor,
+ )
+ let excess = alloc.natural_size + panel.outerSize + 10 - monitor.height // 10 is arbitrary
+
+ if (excess > 0) {
+ alloc.natural_size -= excess
+ }
+ }
+
+ return [alloc.min_size, alloc.natural_size]
+ }
+
+ _findPanelMenuButtons(container) {
+ let panelMenuButtons = []
+ let panelMenuButton
+
+ let find = (parent) =>
+ parent.get_children().forEach((c) => {
+ if ((panelMenuButton = this._getPanelMenuButton(c))) {
+ panelMenuButtons.push(panelMenuButton)
+ }
+
+ find(c)
+ })
+
+ find(container)
+
+ return panelMenuButtons
+ }
+
+ _removePanelBarriers(panel) {
+ if (panel.isStandalone && panel._rightPanelBarrier) {
+ panel._rightPanelBarrier.destroy()
+ }
+
+ if (panel._leftPanelBarrier) {
+ panel._leftPanelBarrier.destroy()
+ delete panel._leftPanelBarrier
+ }
+ }
+
+ _getPanelMenuButton(obj) {
+ return obj instanceof PanelMenu.Button && obj.menu?._boxPointer ? obj : 0
+ }
+
+ _setKeyBindings(enable) {
+ let keys = {
+ 'intellihide-key-toggle': () =>
+ this.allPanels.forEach((p) => p.intellihide.toggle()),
+ }
+
+ Object.keys(keys).forEach((k) => {
+ Utils.removeKeybinding(k)
+
+ if (enable) {
+ Utils.addKeybinding(k, SETTINGS, keys[k], Shell.ActionMode.NORMAL)
+ }
+ })
+ }
+}
+
+// This class drives long-running icon animations, to keep them running in sync
+// with each other.
+export const IconAnimator = class {
+ constructor(actor) {
+ this._count = 0
+ this._started = false
+ this._animations = {
+ dance: [],
+ }
+ this._timeline = new Clutter.Timeline({
+ duration: 3000,
+ repeat_count: -1,
+ })
+
+ /* Just use the construction property when no need to support 3.36 */
+ if (this._timeline.set_actor) this._timeline.set_actor(actor)
+
+ this._timeline.connect('new-frame', () => {
+ const progress = this._timeline.get_progress()
+ const danceRotation =
+ progress < 1 / 6 ? 15 * Math.sin(progress * 24 * Math.PI) : 0
+ const dancers = this._animations.dance
+ for (let i = 0, iMax = dancers.length; i < iMax; i++) {
+ dancers[i].target.rotation_angle_z = danceRotation
+ }
+ })
+ }
+
+ destroy() {
+ this._timeline.stop()
+ this._timeline = null
+ for (let name in this._animations) {
+ const pairs = this._animations[name]
+ for (let i = 0, iMax = pairs.length; i < iMax; i++) {
+ const pair = pairs[i]
+ pair.target.disconnect(pair.targetDestroyId)
+ }
+ }
+ this._animations = null
+ }
+
+ pause() {
+ if (this._started && this._count > 0) {
+ this._timeline.stop()
+ }
+ this._started = false
+ }
+
+ start() {
+ if (!this._started && this._count > 0) {
+ this._timeline.start()
+ }
+ this._started = true
+ }
+
+ addAnimation(target, name) {
+ // before adding a new animation, remove previous one to only have one running
+ let animationNames = Object.keys(this._animations)
+
+ for (let i = 0; i < animationNames.length; ++i) {
+ let n = animationNames[i]
+ let currentAnimationPair = this._animations[n].find(
+ (p) => p.target == target,
+ )
+
+ if (currentAnimationPair) {
+ if (n == name) return // already have this animation running, nothing else to do
+
+ this.removeAnimation(currentAnimationPair.target, n)
+ }
+ }
+
+ 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()
+ }
+
+ if (name == 'dance') target.rotation_angle_z = 0
+
+ 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.geom.innerSize : 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.geom.outerSize +
+ (SETTINGS.get_boolean('stockgs-keep-top-panel')
+ ? Main.layoutManager.panelBox.height
+ : 0) +
+ 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()
+}
diff --git a/src/panelPositions.js b/src/panelPositions.js
new file mode 100644
index 0000000..d896acf
--- /dev/null
+++ b/src/panelPositions.js
@@ -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 .
+ *
+ * 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
+}
diff --git a/src/panelSettings.js b/src/panelSettings.js
new file mode 100644
index 0000000..04fd5ca
--- /dev/null
+++ b/src/panelSettings.js
@@ -0,0 +1,308 @@
+/*
+ * 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 .
+ */
+
+import Gio from 'gi://Gio'
+
+import * as Pos from './panelPositions.js'
+
+const displayConfigWrapper = Gio.DBusProxy.makeProxyWrapper(
+ `
+
+
+
+
+
+
+
+
+
+ `,
+)
+
+// 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
+
+ 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 async 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 gsPrimaryIndex = 0
+ 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
+
+ if (primary) gsPrimaryIndex = i
+
+ monitorInfos.push({
+ id,
+ product,
+ primary,
+ })
+
+ monitorIdToIndex[id] = i
+ monitorIndexToId[i] = id
+ ids[id] = 1
+ })
+
+ _saveMonitors(settings, monitorInfos, gsPrimaryIndex)
+
+ 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, gsPrimaryIndex) {
+ /* 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])
+ dtpPrimaryMonitor = monitorInfos[dtpPrimaryMonitor].id
+
+ // default to gnome-shell primary monitor
+ if (!dtpPrimaryMonitor)
+ dtpPrimaryMonitor = monitorInfos[gsPrimaryIndex]?.id || 0
+
+ settings.set_string(keyPrimary, dtpPrimaryMonitor)
+ */
+
+ 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')
+}
diff --git a/src/panelStyle.js b/src/panelStyle.js
new file mode 100644
index 0000000..9c543af
--- /dev/null
+++ b/src/panelStyle.js
@@ -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 .
+ *
+ * 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)
+ }
+ }
+}
diff --git a/src/prefs.js b/src/prefs.js
new file mode 100644
index 0000000..b260b98
--- /dev/null
+++ b/src/prefs.js
@@ -0,0 +1,1672 @@
+/*
+ * 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 .
+ *
+ *
+ * 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 Adw from 'gi://Adw'
+import GdkPixbuf from 'gi://GdkPixbuf'
+import Gio from 'gi://Gio'
+import GioUnix from 'gi://GioUnix'
+import GLib from 'gi://GLib'
+import GObject from 'gi://GObject'
+import Gtk from 'gi://Gtk'
+import Gdk from 'gi://Gdk'
+
+import * as PanelSettings from './panelSettings.js'
+import * as Pos from './panelPositions.js'
+
+import {
+ ExtensionPreferences,
+ gettext as _,
+ ngettext,
+} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'
+
+const SCALE_UPDATE_TIMEOUT = 500
+const DEFAULT_PANEL_SIZES = [ 96, 64, 48, 32, 24 ]
+const DEFAULT_MARGIN_SIZES = [32, 24, 16, 12, 8, 4, 0]
+// Minimum length could be 0, but a higher value may help prevent confusion about where the panel went.
+const LENGTH_MARKS = [100, 90, 80, 70, 60, 50, 40, 30, 20]
+
+const SCHEMA_PATH = '/org.gnome.shell.extensions.zorin-taskbar/'
+
+/**
+ * This function was copied from the activities-config extension
+ * https://github.com/nls1729/acme-code/tree/master/activities-config
+ * by Norman L. Smith.
+ */
+function cssHexString(css) {
+ let rrggbb = '#'
+ let start
+ for (let loop = 0; loop < 3; loop++) {
+ let end = 0
+ let xx = ''
+ for (let loop = 0; loop < 2; loop++) {
+ while (true) {
+ let x = css.slice(end, end + 1)
+ if (x == '(' || x == ',' || x == ')') break
+ end++
+ }
+ if (loop == 0) {
+ end++
+ start = end
+ }
+ }
+ xx = parseInt(css.slice(start, end)).toString(16)
+ if (xx.length == 1) xx = '0' + xx
+ rrggbb += xx
+ css = css.slice(end)
+ }
+ return rrggbb
+}
+
+function setShortcut(settings, shortcutName) {
+ let shortcut_text = settings.get_string(shortcutName + '-text')
+ let [success, key, mods] = Gtk.accelerator_parse(shortcut_text)
+
+ if (success && Gtk.accelerator_valid(key, mods)) {
+ let shortcut = Gtk.accelerator_name(key, mods)
+ settings.set_strv(shortcutName, [shortcut])
+ } else {
+ settings.set_strv(shortcutName, [])
+ }
+}
+
+function checkHotkeyPrefix(settings) {
+ settings.delay()
+
+ let hotkeyPrefix = settings.get_string('hotkey-prefix-text')
+ if (hotkeyPrefix == 'Super') hotkeyPrefix = ''
+ else if (hotkeyPrefix == 'SuperAlt') hotkeyPrefix = ''
+ let [, , mods] = Gtk.accelerator_parse(hotkeyPrefix)
+ let [, , shift_mods] = Gtk.accelerator_parse('' + hotkeyPrefix)
+ let [, , ctrl_mods] = Gtk.accelerator_parse('' + hotkeyPrefix)
+
+ let numHotkeys = 10
+ for (let i = 1; i <= numHotkeys; i++) {
+ let number = i
+ if (number == 10) number = 0
+ let key = Gdk.keyval_from_name(number.toString())
+ let key_kp = Gdk.keyval_from_name('KP_' + number.toString())
+ if (Gtk.accelerator_valid(key, mods)) {
+ let shortcut = Gtk.accelerator_name(key, mods)
+ let shortcut_kp = Gtk.accelerator_name(key_kp, mods)
+
+ // Setup shortcut strings
+ settings.set_strv('app-hotkey-' + i, [shortcut])
+ settings.set_strv('app-hotkey-kp-' + i, [shortcut_kp])
+
+ // With
+ shortcut = Gtk.accelerator_name(key, shift_mods)
+ shortcut_kp = Gtk.accelerator_name(key_kp, shift_mods)
+ settings.set_strv('app-shift-hotkey-' + i, [shortcut])
+ settings.set_strv('app-shift-hotkey-kp-' + i, [shortcut_kp])
+
+ // With
+ shortcut = Gtk.accelerator_name(key, ctrl_mods)
+ shortcut_kp = Gtk.accelerator_name(key_kp, ctrl_mods)
+ settings.set_strv('app-ctrl-hotkey-' + i, [shortcut])
+ settings.set_strv('app-ctrl-hotkey-kp-' + i, [shortcut_kp])
+ } else {
+ // Reset default settings for the relevant keys if the
+ // accelerators are invalid
+ let keys = [
+ 'app-hotkey-' + i,
+ 'app-shift-hotkey-' + i,
+ 'app-ctrl-hotkey-' + i, // Regular numbers
+ 'app-hotkey-kp-' + i,
+ 'app-shift-hotkey-kp-' + i,
+ 'app-ctrl-hotkey-kp-' + i,
+ ] // Key-pad numbers
+ keys.forEach(function (val) {
+ settings.set_value(val, settings.get_default_value(val))
+ }, this)
+ }
+ }
+
+ settings.apply()
+}
+
+function mergeObjects(main, bck) {
+ for (const prop in bck) {
+ if (!Object.hasOwn(main, prop) && Object.hasOwn(bck, prop)) {
+ main[prop] = bck[prop]
+ }
+ }
+
+ return main
+}
+
+const Preferences = class {
+ constructor(window, settings, gnomeInterfaceSettings, path) {
+ // this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.zorin-taskbar');
+ this._rtl = Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL
+ this._builder = new Gtk.Builder()
+ this._builder.set_scope(new BuilderScope(this))
+ this._settings = settings
+ this._gnomeInterfaceSettings = gnomeInterfaceSettings
+ this._path = path
+
+ this._metadata = ExtensionPreferences.lookupByURL(import.meta.url).metadata
+ this._builder.set_translation_domain(this._metadata['gettext-domain'])
+
+ window.set_search_enabled(true)
+
+ // dialogs
+ this._builder.add_from_file(this._path + '/ui/BoxShowDesktopOptions.ui')
+ this._builder.add_from_file(this._path + '/ui/BoxDynamicOpacityOptions.ui')
+ this._builder.add_from_file(this._path + '/ui/BoxIntellihideOptions.ui')
+ this._builder.add_from_file(
+ this._path + '/ui/BoxShowDateMenuOptions.ui',
+ )
+ this._builder.add_from_file(this._path + '/ui/BoxWindowPreviewOptions.ui')
+ this._builder.add_from_file(this._path + '/ui/BoxGroupAppsOptions.ui')
+ this._builder.add_from_file(this._path + '/ui/BoxMiddleClickOptions.ui')
+ this._builder.add_from_file(this._path + '/ui/BoxOverlayShortcut.ui')
+
+ // pages
+ this._builder.add_from_file(this._path + '/ui/SettingsStyle.ui')
+ let pageStyle = this._builder.get_object('style')
+ window.add(pageStyle)
+
+ this._builder.add_from_file(this._path + '/ui/SettingsPosition.ui')
+ let pagePosition = this._builder.get_object('position')
+ window.add(pagePosition)
+
+ this._builder.add_from_file(this._path + '/ui/SettingsBehavior.ui')
+ let pageBehavior = this._builder.get_object('behavior')
+ window.add(pageBehavior)
+
+ this._builder.add_from_file(this._path + '/ui/SettingsAction.ui')
+ let pageAction = this._builder.get_object('action')
+ window.add(pageAction)
+
+ let listbox = this._builder.get_object('taskbar_display_listbox')
+ let provider = new Gtk.CssProvider()
+ provider.load_from_data('list { background-color: transparent; }', -1)
+ let context = listbox.get_style_context()
+ context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
+
+ // set the window as notebook, it is being used as parent for dialogs
+ this.notebook = window
+
+ PanelSettings.setMonitorsInfo(settings).then(() => {
+ this._bindSettings()
+
+ PanelSettings.displayConfigProxy.connectSignal(
+ 'MonitorsChanged',
+ async () => {
+ await PanelSettings.setMonitorsInfo(settings)
+ this._setMonitorsInfo()
+ },
+ )
+
+ let maybeGoToPage = () => {
+ let targetPageName = settings.get_string('target-prefs-page')
+
+ if (targetPageName) {
+ window.set_visible_page_name(targetPageName)
+ settings.set_string('target-prefs-page', '')
+ }
+ }
+
+ settings.connect('changed::target-prefs-page', maybeGoToPage)
+
+ maybeGoToPage()
+ })
+ }
+
+ /**
+ * Connect signals
+ */
+ _connector(builder, object, signal, handler) {
+ object.connect(signal, this._SignalHandler[handler].bind(this))
+ }
+
+ _updateVerticalRelatedOptions() {
+ let position = this._getPanelPosition(this._currentMonitorIndex)
+ let isVertical = position == Pos.LEFT || position == Pos.RIGHT
+ let showDesktopWidthLabel = this._builder.get_object(
+ 'show_showdesktop_width_label',
+ )
+
+ showDesktopWidthLabel.set_title(_('Show Desktop button padding (px)'))
+
+ this._displayPanelPositionsForMonitor(this._currentMonitorIndex)
+ this._setPanelLenghtWidgetSensitivity(
+ PanelSettings.getPanelLength(this._settings, this._currentMonitorIndex),
+ )
+ }
+
+ _getPanelPosition(monitorIndex) {
+ return PanelSettings.getPanelPosition(this._settings, monitorIndex)
+ }
+
+ _setPanelPosition(position) {
+ const monitorSync = this._settings.get_boolean(
+ 'panel-element-positions-monitors-sync',
+ )
+ const monitorsToSetFor = monitorSync
+ ? Object.keys(this.monitors)
+ : [this._currentMonitorIndex]
+ monitorsToSetFor.forEach((monitorIndex) => {
+ PanelSettings.setPanelPosition(this._settings, monitorIndex, position)
+ })
+ this._setAnchorLabels(this._currentMonitorIndex)
+ }
+
+ _setPositionRadios(position) {
+ this._ignorePositionRadios = true
+
+ switch (position) {
+ case Pos.BOTTOM:
+ this._builder.get_object('position_bottom_button').set_active(true)
+ break
+ case Pos.TOP:
+ this._builder.get_object('position_top_button').set_active(true)
+ break
+ case Pos.LEFT:
+ this._builder.get_object('position_left_button').set_active(true)
+ break
+ case Pos.RIGHT:
+ this._builder.get_object('position_right_button').set_active(true)
+ break
+ }
+
+ this._ignorePositionRadios = false
+ }
+
+ /**
+ * Set panel anchor combo labels according to whether the monitor's panel is vertical
+ * or horizontal, or if all monitors' panels are being configured and they are a mix
+ * of vertical and horizontal.
+ */
+ _setAnchorLabels(currentMonitorIndex) {
+ const monitorSync = this._settings.get_boolean(
+ 'panel-element-positions-monitors-sync',
+ )
+ const monitorsToSetFor = monitorSync
+ ? Object.keys(this.monitors)
+ : [currentMonitorIndex]
+ const allVertical = monitorsToSetFor.every((i) => {
+ const position = PanelSettings.getPanelPosition(this._settings, i)
+ return position === Pos.LEFT || position === Pos.RIGHT
+ })
+ const allHorizontal = monitorsToSetFor.every((i) => {
+ const position = PanelSettings.getPanelPosition(this._settings, i)
+ return position === Pos.TOP || position === Pos.BOTTOM
+ })
+
+ const anchor_combo = this._builder.get_object('panel_anchor_combo')
+ anchor_combo.remove_all()
+
+ if (allHorizontal) {
+ anchor_combo.append(Pos.START, _('Left'))
+ anchor_combo.append(Pos.MIDDLE, _('Center'))
+ anchor_combo.append(Pos.END, _('Right'))
+ } else if (allVertical) {
+ anchor_combo.append(Pos.START, _('Top'))
+ anchor_combo.append(Pos.MIDDLE, _('Middle'))
+ anchor_combo.append(Pos.END, _('Bottom'))
+ } else {
+ // Setting for a mix of horizontal and vertical panels on different monitors.
+ anchor_combo.append(Pos.START, _('Start'))
+ anchor_combo.append(Pos.MIDDLE, _('Middle'))
+ anchor_combo.append(Pos.END, _('End'))
+ }
+
+ // Set combo box after re-populating its options. But only if it's for a single-panel
+ // configuration, or a multi-panel configuration where they all have the same anchor
+ // setting. So don't set the combo box if there is a multi-panel configuration with
+ // different anchor settings.
+ const someAnchor = PanelSettings.getPanelAnchor(
+ this._settings,
+ currentMonitorIndex,
+ )
+ if (
+ monitorsToSetFor.every(
+ (i) => PanelSettings.getPanelAnchor(this._settings, i) === someAnchor,
+ )
+ ) {
+ const panel_anchor = PanelSettings.getPanelAnchor(
+ this._settings,
+ currentMonitorIndex,
+ )
+ this._builder.get_object('panel_anchor_combo').set_active_id(panel_anchor)
+ }
+ }
+
+ /**
+ * When a monitor is selected, update the widgets for panel position, size, anchoring,
+ * and contents so they accurately show the settings for the panel on that monitor.
+ */
+ _updateWidgetSettingsForMonitor(monitorIndex) {
+ // Update display of panel screen position setting
+ const panelPosition = this._getPanelPosition(monitorIndex)
+ this._setPositionRadios(panelPosition)
+
+ // Update display of thickness, length, and anchor settings
+ const panel_size_scale = this._builder.get_object('panel_size_scale')
+ const size = PanelSettings.getPanelSize(this._settings, monitorIndex)
+ panel_size_scale.set_value(size)
+
+ const panel_length_scale = this._builder.get_object('panel_length_scale')
+ const dynamicLengthButton = this._builder.get_object(
+ 'panel_length_dynamic_button',
+ )
+ const length = PanelSettings.getPanelLength(this._settings, monitorIndex)
+ const isDynamicLength = length == -1
+
+ dynamicLengthButton.set_active(isDynamicLength)
+ panel_length_scale.set_value(isDynamicLength ? 100 : length)
+
+ this._setAnchorLabels(monitorIndex)
+
+ // Update display of panel content settings
+ this._displayPanelPositionsForMonitor(monitorIndex)
+
+ this._setPanelLenghtWidgetSensitivity(length)
+ }
+
+ /**
+ * Anchor is only relevant if panel length is less than 100%. Enable or disable
+ * anchor widget sensitivity accordingly.
+ */
+ _setPanelLenghtWidgetSensitivity(panelLength) {
+ const taskbarListBox = this._builder.get_object('taskbar_display_listbox')
+ let i = 0
+ let row
+ const isDynamicLength = panelLength == -1
+ const isPartialLength = panelLength < 100
+
+ this._builder
+ .get_object('panel_length_scale')
+ .set_sensitive(!isDynamicLength)
+ this._builder
+ .get_object('panel_anchor_label')
+ .set_sensitive(isPartialLength)
+ this._builder
+ .get_object('panel_anchor_combo')
+ .set_sensitive(isPartialLength)
+
+ while ((row = taskbarListBox.get_row_at_index(i++)) != null) {
+ let grid = row.get_child()
+ let positionCombo = grid.get_child_at(4, 0)
+
+ positionCombo.set_sensitive(!isDynamicLength)
+ }
+ }
+
+ _displayPanelPositionsForMonitor(monitorIndex) {
+ let taskbarListBox = this._builder.get_object('taskbar_display_listbox')
+
+ while (taskbarListBox.get_first_child()) {
+ taskbarListBox.remove(taskbarListBox.get_first_child())
+ }
+
+ let labels = {}
+ let panelPosition = this._getPanelPosition(monitorIndex)
+ let isVertical = panelPosition == Pos.LEFT || panelPosition == Pos.RIGHT
+ let panelElementPositions = PanelSettings.getPanelElementPositions(
+ this._settings,
+ monitorIndex,
+ )
+ let updateElementsSettings = () => {
+ let newPanelElementPositions = []
+ let monitorSync = this._settings.get_boolean(
+ 'panel-element-positions-monitors-sync',
+ )
+ let monitors = monitorSync ? Object.keys(this.monitors) : [monitorIndex]
+
+ let child = taskbarListBox.get_first_child()
+ while (child != null) {
+ newPanelElementPositions.push({
+ element: child.id,
+ visible: child.visibleToggleBtn.get_active(),
+ position: child.positionCombo.get_active_id(),
+ })
+ child = child.get_next_sibling()
+ }
+
+ monitors.forEach((m) =>
+ PanelSettings.setPanelElementPositions(
+ this._settings,
+ m,
+ newPanelElementPositions,
+ ),
+ )
+ }
+
+ labels[Pos.SHOW_APPS_BTN] = _('Show Applications button')
+ labels[Pos.ACTIVITIES_BTN] = _('Activities button')
+ labels[Pos.TASKBAR] = _('Taskbar')
+ labels[Pos.DATE_MENU] = _('Date menu')
+ labels[Pos.SYSTEM_MENU] = _('System menu')
+ labels[Pos.LEFT_BOX] = _('Left box')
+ labels[Pos.CENTER_BOX] = _('Center box')
+ labels[Pos.RIGHT_BOX] = _('Right box')
+ labels[Pos.DESKTOP_BTN] = _('Desktop button')
+
+ panelElementPositions.forEach((el) => {
+ let row = new Gtk.ListBoxRow()
+ let grid = new Gtk.Grid({
+ margin_start: 12,
+ margin_end: 12,
+ column_spacing: 8,
+ })
+ let upDownGrid = new Gtk.Grid({ column_spacing: 2 })
+ let upBtn = new Gtk.Button({ tooltip_text: _('Move up') })
+ let upImg = new Gtk.Image({ icon_name: 'go-up-symbolic', pixel_size: 12 })
+ let downBtn = new Gtk.Button({ tooltip_text: _('Move down') })
+ let downImg = new Gtk.Image({
+ icon_name: 'go-down-symbolic',
+ pixel_size: 12,
+ })
+ let visibleToggleBtn = new Gtk.ToggleButton({
+ label: _('Visible'),
+ active: el.visible,
+ })
+ let positionCombo = new Gtk.ComboBoxText({
+ tooltip_text: _('Select element position'),
+ })
+ let upDownClickHandler = (limit) => {
+ let index = row.get_index()
+
+ if (index != limit) {
+ taskbarListBox.remove(row)
+ taskbarListBox.insert(row, index + (!limit ? -1 : 1))
+ updateElementsSettings()
+ }
+ }
+
+ positionCombo.append(
+ Pos.STACKED_TL,
+ isVertical ? _('Stacked to top') : _('Stacked to left'),
+ )
+ positionCombo.append(
+ Pos.STACKED_BR,
+ isVertical ? _('Stacked to bottom') : _('Stacked to right'),
+ )
+ positionCombo.append(Pos.CENTERED, _('Centered'))
+ positionCombo.append(Pos.CENTERED_MONITOR, _('Monitor Center'))
+ positionCombo.set_active_id(el.position)
+
+ upBtn.connect('clicked', () => upDownClickHandler(0))
+ downBtn.connect('clicked', () =>
+ upDownClickHandler(panelElementPositions.length - 1),
+ )
+ visibleToggleBtn.connect('toggled', () => updateElementsSettings())
+ positionCombo.connect('changed', () => updateElementsSettings())
+
+ upBtn.set_child(upImg)
+ downBtn.set_child(downImg)
+
+ upDownGrid.attach(upBtn, 0, 0, 1, 1)
+ upDownGrid.attach(downBtn, 1, 0, 1, 1)
+
+ grid.attach(upDownGrid, 0, 0, 1, 1)
+ grid.attach(
+ new Gtk.Label({ label: labels[el.element], xalign: 0, hexpand: true }),
+ 1,
+ 0,
+ 1,
+ 1,
+ )
+
+ if (Pos.optionDialogFunctions[el.element]) {
+ let cogImg = new Gtk.Image({ icon_name: 'emblem-system-symbolic' })
+ let optionsBtn = new Gtk.Button({ tooltip_text: _('More options') })
+
+ optionsBtn.get_style_context().add_class('circular')
+ optionsBtn.set_child(cogImg)
+ grid.attach(optionsBtn, 2, 0, 1, 1)
+
+ optionsBtn.connect('clicked', () =>
+ this[Pos.optionDialogFunctions[el.element]](),
+ )
+ }
+
+ grid.attach(visibleToggleBtn, 3, 0, 1, 1)
+ grid.attach(positionCombo, 4, 0, 1, 1)
+
+ row.id = el.element
+ row.visibleToggleBtn = visibleToggleBtn
+ row.positionCombo = positionCombo
+
+ row.set_child(grid)
+ taskbarListBox.insert(row, -1)
+ })
+ }
+
+ _createPreferencesDialog(title, content, reset_function = null) {
+ let dialog
+
+ dialog = new Gtk.Dialog({
+ title: title,
+ transient_for: this.notebook.get_root(),
+ use_header_bar: true,
+ modal: true,
+ })
+
+ // GTK+ leaves positive values for application-defined response ids.
+ // Use +1 for the reset action
+ if (reset_function != null) dialog.add_button(_('Reset to defaults'), 1)
+
+ dialog.get_content_area().append(content)
+
+ dialog.connect('response', (dialog, id) => {
+ if (id == 1) {
+ // restore default settings
+ if (reset_function) reset_function()
+ } else {
+ // remove the settings content so it doesn't get destroyed;
+ dialog.get_content_area().remove(content)
+ dialog.destroy()
+ }
+ return
+ })
+
+ return dialog
+ }
+
+ _showDateMenuOptions() {
+ let box = this._builder.get_object('box_date_menu_options')
+
+ let dialog = this._createPreferencesDialog(
+ _('Date Menu options'),
+ box,
+ () => {
+ // restore default settings
+ this._gnomeInterfaceSettings.set_value('clock-show-date', this._gnomeInterfaceSettings.get_default_value('clock-show-date'))
+ this._gnomeInterfaceSettings.set_value('clock-show-weekday', this._gnomeInterfaceSettings.get_default_value('clock-show-weekday'))
+ this._gnomeInterfaceSettings.set_value('clock-show-seconds', this._gnomeInterfaceSettings.get_default_value('clock-show-seconds'))
+ }
+ )
+
+ dialog.show()
+ dialog.set_default_size(1, 1)
+ }
+
+ _showDesktopButtonOptions() {
+ let box = this._builder.get_object('box_show_showdesktop_options')
+
+ let dialog = this._createPreferencesDialog(
+ _('Show Desktop options'),
+ box,
+ () => {
+ // restore default settings
+ this._settings.set_value(
+ 'show-showdesktop-icon',
+ this._settings.get_default_value('show-showdesktop-icon'),
+ )
+ this._settings.set_value(
+ 'showdesktop-button-width',
+ this._settings.get_default_value('showdesktop-button-width'),
+ )
+ this._builder
+ .get_object('show_showdesktop_width_spinbutton')
+ .set_value(this._settings.get_int('showdesktop-button-width'))
+
+ this._settings.set_value(
+ 'show-showdesktop-hover',
+ this._settings.get_default_value('show-showdesktop-hover'),
+ )
+ },
+ )
+
+ this._builder
+ .get_object('show_showdesktop_width_spinbutton')
+ .set_value(this._settings.get_int('showdesktop-button-width'))
+ this._builder
+ .get_object('show_showdesktop_width_spinbutton')
+ .connect('value-changed', (widget) => {
+ this._settings.set_int('showdesktop-button-width', widget.get_value())
+ })
+
+ dialog.show()
+ dialog.set_default_size(1, 1)
+ }
+
+ _setMonitorsInfo() {
+ this.monitors = PanelSettings.availableMonitors
+
+ let panelOptionsMonitorCombo = this._builder.get_object(
+ 'taskbar_position_monitor_combo',
+ )
+ let dtpPrimaryMonitorIndex = 0
+
+ this._currentMonitorIndex = dtpPrimaryMonitorIndex
+
+ this._updateVerticalRelatedOptions()
+
+ panelOptionsMonitorCombo.remove_all()
+
+ for (let i = 0; i < this.monitors.length; ++i) {
+ let monitor = this.monitors[i]
+ let label = monitor.primary
+ ? _('Primary monitor')
+ : _('Monitor ') + (i + 1)
+
+ label += monitor.product ? ` (${monitor.product})` : ''
+
+ panelOptionsMonitorCombo.append_text(label)
+ }
+
+ panelOptionsMonitorCombo.set_active(dtpPrimaryMonitorIndex)
+ }
+
+ _bindSettings() {
+ //multi-monitor
+ this._setMonitorsInfo()
+
+ this._settings.connect('changed::panel-positions', () =>
+ this._updateVerticalRelatedOptions(),
+ )
+
+ this._settings.bind(
+ 'panel-element-positions-monitors-sync',
+ this._builder.get_object('taskbar_position_sync_button'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'panel-element-positions-monitors-sync',
+ this._builder.get_object('taskbar_position_monitor_combo'),
+ 'sensitive',
+ Gio.SettingsBindFlags.INVERT_BOOLEAN,
+ )
+
+ this._settings.connect(
+ 'changed::panel-element-positions-monitors-sync',
+ () => {
+ // The anchor combo box may has different labels for single- or all-monitor configuration.
+ this._setAnchorLabels(this._currentMonitorIndex)
+ },
+ )
+
+ this._builder
+ .get_object('taskbar_position_monitor_combo')
+ .connect('changed', (widget) => {
+ this._currentMonitorIndex = widget.get_active()
+ this._updateWidgetSettingsForMonitor(this._currentMonitorIndex)
+ })
+
+ this._settings.bind(
+ 'multi-monitors',
+ this._builder.get_object('multimon_multi_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ if (this.monitors.length === 1) {
+ this._builder.get_object('multimon_multi_switch').set_sensitive(false)
+ }
+
+ let panelLengthScale = {
+ objectName: 'panel_length_scale',
+ valueName: '',
+ range: LENGTH_MARKS,
+ unit: '%',
+ getValue: () =>
+ PanelSettings.getPanelLength(this._settings, this._currentMonitorIndex),
+ setValue: (value) => setPanelLength(value),
+ manualConnect: true,
+ }
+
+ let setPanelLength = (value) => {
+ const monitorSync = this._settings.get_boolean(
+ 'panel-element-positions-monitors-sync',
+ )
+ const monitorsToSetFor = monitorSync
+ ? Object.keys(this.monitors)
+ : [this._currentMonitorIndex]
+ monitorsToSetFor.forEach((monitorIndex) => {
+ PanelSettings.setPanelLength(this._settings, monitorIndex, value)
+ })
+
+ maybeSetPanelLengthScaleValueChange(value)
+ this._setPanelLenghtWidgetSensitivity(value)
+ }
+
+ let maybeSetPanelLengthScaleValueChange = (value) => {
+ const panel_length_scale = this._builder.get_object('panel_length_scale')
+
+ if (panelLengthScale.valueChangedId) {
+ panel_length_scale.disconnect(panelLengthScale.valueChangedId)
+ panelLengthScale.valueChangedId = 0
+ }
+
+ if (value != -1) connectValueChanged(panel_length_scale, panelLengthScale)
+ else panel_length_scale.set_value(100)
+ }
+
+ const dynamicLengthButton = this._builder.get_object(
+ 'panel_length_dynamic_button',
+ )
+ dynamicLengthButton.connect('notify::active', () => {
+ setPanelLength(dynamicLengthButton.get_active() ? -1 : 100)
+ })
+
+ this._builder
+ .get_object('panel_anchor_combo')
+ .connect('changed', (widget) => {
+ const value = widget.get_active_id()
+ // Value can be null while anchor labels are being swapped out
+ if (value !== null) {
+ const monitorSync = this._settings.get_boolean(
+ 'panel-element-positions-monitors-sync',
+ )
+ const monitorsToSetFor = monitorSync
+ ? Object.keys(this.monitors)
+ : [this._currentMonitorIndex]
+ monitorsToSetFor.forEach((monitorIndex) => {
+ PanelSettings.setPanelAnchor(this._settings, monitorIndex, value)
+ })
+ }
+ })
+
+ this._updateWidgetSettingsForMonitor(this._currentMonitorIndex)
+
+ //dynamic opacity
+ this._settings.bind(
+ 'trans-use-custom-opacity',
+ this._builder.get_object('trans_opacity_override_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'trans-use-custom-opacity',
+ this._builder.get_object('trans_opacity_box'),
+ 'sensitive',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'trans-use-custom-opacity',
+ this._builder.get_object('trans_opacity_box2'),
+ 'sensitive',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._builder
+ .get_object('trans_opacity_override_switch')
+ .connect('notify::active', (widget) => {
+ if (!widget.get_active())
+ this._builder.get_object('trans_dyn_switch').set_active(false)
+ })
+
+ this._builder
+ .get_object('trans_opacity_spinbutton')
+ .set_value(this._settings.get_double('trans-panel-opacity') * 100)
+ this._builder
+ .get_object('trans_opacity_spinbutton')
+ .connect('value-changed', (widget) => {
+ this._settings.set_double(
+ 'trans-panel-opacity',
+ widget.get_value() * 0.01,
+ )
+ })
+
+ this._settings.bind(
+ 'trans-use-dynamic-opacity',
+ this._builder.get_object('trans_dyn_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'trans-use-dynamic-opacity',
+ this._builder.get_object('trans_dyn_options_button'),
+ 'sensitive',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'trans-dynamic-behavior',
+ this._builder.get_object('trans_options_window_type_combo'),
+ 'active-id',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._builder
+ .get_object('trans_options_min_opacity_spinbutton')
+ .set_value(this._settings.get_double('trans-dynamic-anim-target') * 100)
+ this._builder
+ .get_object('trans_options_min_opacity_spinbutton')
+ .connect('value-changed', (widget) => {
+ this._settings.set_double(
+ 'trans-dynamic-anim-target',
+ widget.get_value() * 0.01,
+ )
+ })
+
+ this._builder
+ .get_object('trans_dyn_options_button')
+ .connect('clicked', () => {
+ let box = this._builder.get_object('box_dynamic_opacity_options')
+
+ let dialog = this._createPreferencesDialog(
+ _('Dynamic opacity options'),
+ box,
+ () => {
+ // restore default settings
+ this._settings.set_value(
+ 'trans-dynamic-behavior',
+ this._settings.get_default_value('trans-dynamic-behavior'),
+ )
+
+ this._settings.set_value(
+ 'trans-dynamic-anim-target',
+ this._settings.get_default_value('trans-dynamic-anim-target'),
+ )
+ this._builder
+ .get_object('trans_options_min_opacity_spinbutton')
+ .set_value(
+ this._settings.get_double('trans-dynamic-anim-target') * 100,
+ )
+ },
+ )
+
+ dialog.show()
+ dialog.set_default_size(1, 1)
+ })
+
+ this._settings.bind(
+ 'intellihide',
+ this._builder.get_object('intellihide_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'intellihide',
+ this._builder.get_object('intellihide_options_button'),
+ 'sensitive',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'intellihide-hide-from-windows',
+ this._builder.get_object('intellihide_window_hide_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'intellihide-hide-from-windows',
+ this._builder.get_object('intellihide_behaviour_options'),
+ 'sensitive',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'intellihide-behaviour',
+ this._builder.get_object('intellihide_behaviour_combo'),
+ 'active-id',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'intellihide-use-pressure',
+ this._builder.get_object('intellihide_use_pressure_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'intellihide-show-in-fullscreen',
+ this._builder.get_object('intellihide_show_in_fullscreen_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'intellihide-only-secondary',
+ this._builder.get_object('intellihide_only_secondary_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'multi-monitors',
+ this._builder.get_object('grid_intellihide_only_secondary'),
+ 'sensitive',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._builder
+ .get_object('multimon_multi_switch')
+ .connect('notify::active', (widget) => {
+ if (!widget.get_active())
+ this._builder
+ .get_object('intellihide_only_secondary_switch')
+ .set_active(false)
+ })
+
+ this._settings.bind(
+ 'intellihide-key-toggle-text',
+ this._builder.get_object('intellihide_toggle_entry'),
+ 'text',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+ this._settings.connect('changed::intellihide-key-toggle-text', () =>
+ setShortcut(this._settings, 'intellihide-key-toggle'),
+ )
+
+ let intellihidePersistStateSwitch = this._builder.get_object(
+ 'intellihide_persist_state_switch',
+ )
+
+ intellihidePersistStateSwitch.set_active(
+ this._settings.get_int('intellihide-persisted-state') > -1,
+ )
+
+ intellihidePersistStateSwitch.connect('notify::active', (widget) => {
+ this._settings.set_int(
+ 'intellihide-persisted-state',
+ widget.get_active() ? 0 : -1,
+ )
+ })
+
+ this._settings.bind(
+ 'intellihide-show-on-notification',
+ this._builder.get_object('intellihide_show_on_notification_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._builder
+ .get_object('intellihide_options_button')
+ .connect('clicked', () => {
+ let box = this._builder.get_object('box_intellihide_options')
+
+ let dialog = this._createPreferencesDialog(
+ _('Intellihide options'),
+ box,
+ () => {
+ // restore default settings
+ this._settings.set_value(
+ 'intellihide-hide-from-windows',
+ this._settings.get_default_value('intellihide-hide-from-windows'),
+ )
+ this._settings.set_value(
+ 'intellihide-behaviour',
+ this._settings.get_default_value('intellihide-behaviour'),
+ )
+ this._settings.set_value(
+ 'intellihide-use-pressure',
+ this._settings.get_default_value('intellihide-use-pressure'),
+ )
+ this._settings.set_value(
+ 'intellihide-show-in-fullscreen',
+ this._settings.get_default_value(
+ 'intellihide-show-in-fullscreen',
+ ),
+ )
+ this._settings.set_value(
+ 'intellihide-show-on-notification',
+ this._settings.get_default_value(
+ 'intellihide-show-on-notification',
+ ),
+ )
+ this._settings.set_value(
+ 'intellihide-persisted-state',
+ this._settings.get_default_value('intellihide-persisted-state'),
+ )
+ this._settings.set_value(
+ 'intellihide-only-secondary',
+ this._settings.get_default_value('intellihide-only-secondary'),
+ )
+
+ this._settings.set_value(
+ 'intellihide-key-toggle-text',
+ this._settings.get_default_value('intellihide-key-toggle-text'),
+ )
+
+ intellihidePersistStateSwitch.set_active(false)
+ },
+ )
+
+ dialog.show()
+ dialog.set_default_size(1, 1)
+ })
+
+ // Behavior panel
+
+ this._gnomeInterfaceSettings.bind(
+ 'clock-show-date',
+ this._builder.get_object('date_menu_date_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._gnomeInterfaceSettings.bind(
+ 'clock-show-weekday',
+ this._builder.get_object('date_menu_weekday_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._gnomeInterfaceSettings.bind(
+ 'clock-show-seconds',
+ this._builder.get_object('date_menu_seconds_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'show-showdesktop-icon',
+ this._builder.get_object('show_showdesktop_icon_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'show-showdesktop-hover',
+ this._builder.get_object('show_showdesktop_hide_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'show-window-previews',
+ this._builder.get_object('show_window_previews_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'show-window-previews',
+ this._builder.get_object('show_window_previews_button'),
+ 'sensitive',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'show-tooltip',
+ this._builder.get_object('show_tooltip_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'show-favorites',
+ this._builder.get_object('show_favorite_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'show-favorites-all-monitors',
+ this._builder.get_object('multimon_multi_show_favorites_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'show-favorites',
+ this._builder.get_object('multimon_multi_show_favorites_switch'),
+ 'sensitive',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'show-running-apps',
+ this._builder.get_object('show_runnning_apps_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._builder
+ .get_object('show_window_previews_button')
+ .connect('clicked', () => {
+ let scrolledWindow = this._builder.get_object(
+ 'box_window_preview_options',
+ )
+
+ let dialog = this._createPreferencesDialog(
+ _('Window preview options'),
+ scrolledWindow,
+ () => {
+ // restore default settings
+ this._settings.set_value(
+ 'peek-mode',
+ this._settings.get_default_value('peek-mode'),
+ )
+
+ this._settings.set_value(
+ 'window-preview-size',
+ this._settings.get_default_value('window-preview-size'),
+ )
+ this._builder
+ .get_object('preview_size_spinbutton')
+ .set_value(this._settings.get_int('window-preview-size'))
+
+ this._settings.set_value(
+ 'preview-middle-click-close',
+ this._settings.get_default_value('preview-middle-click-close'),
+ )
+ },
+ )
+
+ this._settings.bind(
+ 'preview-middle-click-close',
+ this._builder.get_object('preview_middle_click_close_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'peek-mode',
+ this._builder.get_object('peek_mode_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._builder
+ .get_object('preview_size_spinbutton')
+ .set_value(this._settings.get_int('window-preview-size'))
+ this._builder
+ .get_object('preview_size_spinbutton')
+ .connect('value-changed', (widget) => {
+ this._settings.set_int('window-preview-size', widget.get_value())
+ })
+
+ dialog.show()
+ })
+
+ this._settings.bind(
+ 'group-apps',
+ this._builder.get_object('group_apps_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN,
+ )
+
+ this._settings.bind(
+ 'group-apps',
+ this._builder.get_object('show_group_apps_options_button'),
+ 'sensitive',
+ Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN,
+ )
+
+ this._settings.bind(
+ 'progress-show-count',
+ this._builder.get_object('show_notification_badge_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'group-apps-use-fixed-width',
+ this._builder.get_object('group_apps_use_fixed_width_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'group-apps-use-launchers',
+ this._builder.get_object('group_apps_use_launchers_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._builder
+ .get_object('display_multitasking_settings')
+ .connect('activated', () => {
+ try {
+ const output = GLib.spawn_command_line_async('gnome-control-center multitasking')
+ } catch (e) {
+ logError(e)
+ }
+ }
+ )
+
+ this._builder
+ .get_object('show_group_apps_options_button')
+ .connect('clicked', () => {
+ let box = this._builder.get_object('box_group_apps_options')
+
+ let dialog = this._createPreferencesDialog(
+ _('Ungrouped application options'),
+ box,
+ () => {
+ // restore default settings
+ this._settings.set_value(
+ 'group-apps-label-max-width',
+ this._settings.get_default_value('group-apps-label-max-width'),
+ )
+ this._builder
+ .get_object('group_apps_label_max_width_spinbutton')
+ .set_value(this._settings.get_int('group-apps-label-max-width'))
+
+ this._settings.set_value(
+ 'group-apps-use-fixed-width',
+ this._settings.get_default_value('group-apps-use-fixed-width'),
+ )
+ this._settings.set_value(
+ 'group-apps-use-launchers',
+ this._settings.get_default_value('group-apps-use-launchers'),
+ )
+ },
+ )
+
+ this._builder
+ .get_object('group_apps_label_max_width_spinbutton')
+ .set_value(this._settings.get_int('group-apps-label-max-width'))
+ this._builder
+ .get_object('group_apps_label_max_width_spinbutton')
+ .connect('value-changed', (widget) => {
+ this._settings.set_int(
+ 'group-apps-label-max-width',
+ widget.get_value(),
+ )
+ })
+
+ dialog.show()
+ dialog.set_default_size(600, 1)
+ })
+
+ this._builder
+ .get_object('click_action_combo')
+ .set_active_id(this._settings.get_string('click-action'))
+ this._builder
+ .get_object('click_action_combo')
+ .connect('changed', (widget) => {
+ this._settings.set_string('click-action', widget.get_active_id())
+ })
+
+ this._builder
+ .get_object('shift_click_action_combo')
+ .connect('changed', (widget) => {
+ this._settings.set_string('shift-click-action', widget.get_active_id())
+ })
+
+ this._builder
+ .get_object('middle_click_action_combo')
+ .connect('changed', (widget) => {
+ this._settings.set_string('middle-click-action', widget.get_active_id())
+ })
+ this._builder
+ .get_object('shift_middle_click_action_combo')
+ .connect('changed', (widget) => {
+ this._settings.set_string(
+ 'shift-middle-click-action',
+ widget.get_active_id(),
+ )
+ })
+
+ // Create dialog for middle-click options
+ this._builder
+ .get_object('middle_click_options_button')
+ .connect('clicked', () => {
+ let box = this._builder.get_object('box_middle_click_options')
+
+ let dialog = this._createPreferencesDialog(
+ _('Customize middle-click behavior'),
+ box,
+ () => {
+ // restore default settings for the relevant keys
+ let keys = [
+ 'shift-click-action',
+ 'middle-click-action',
+ 'shift-middle-click-action',
+ ]
+ keys.forEach(function (val) {
+ this._settings.set_value(
+ val,
+ this._settings.get_default_value(val),
+ )
+ }, this)
+ this._builder
+ .get_object('shift_click_action_combo')
+ .set_active_id(this._settings.get_string('shift-click-action'))
+ this._builder
+ .get_object('middle_click_action_combo')
+ .set_active_id(this._settings.get_string('middle-click-action'))
+ this._builder
+ .get_object('shift_middle_click_action_combo')
+ .set_active_id(
+ this._settings.get_string('shift-middle-click-action'),
+ )
+ },
+ )
+
+ this._builder
+ .get_object('shift_click_action_combo')
+ .set_active_id(this._settings.get_string('shift-click-action'))
+
+ this._builder
+ .get_object('middle_click_action_combo')
+ .set_active_id(this._settings.get_string('middle-click-action'))
+
+ this._builder
+ .get_object('shift_middle_click_action_combo')
+ .set_active_id(this._settings.get_string('shift-middle-click-action'))
+
+ this._settings.bind(
+ 'shift-click-action',
+ this._builder.get_object('shift_click_action_combo'),
+ 'active-id',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+ this._settings.bind(
+ 'middle-click-action',
+ this._builder.get_object('middle_click_action_combo'),
+ 'active-id',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+ this._settings.bind(
+ 'shift-middle-click-action',
+ this._builder.get_object('shift_middle_click_action_combo'),
+ 'active-id',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ dialog.show()
+ dialog.set_default_size(700, 1)
+ })
+
+ this._builder
+ .get_object('scroll_icon_combo')
+ .set_active_id(this._settings.get_string('scroll-icon-action'))
+ this._builder
+ .get_object('scroll_icon_combo')
+ .connect('changed', (widget) => {
+ this._settings.set_string('scroll-icon-action', widget.get_active_id())
+ })
+
+ this._settings.bind(
+ 'hot-keys',
+ this._builder.get_object('hot_keys_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+ this._settings.bind(
+ 'hot-keys',
+ this._builder.get_object('overlay_button'),
+ 'sensitive',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._builder.get_object('overlay_combo').connect('changed', (widget) => {
+ this._settings.set_string('hotkeys-overlay-combo', widget.get_active_id())
+ })
+
+ this._settings.bind(
+ 'shortcut-previews',
+ this._builder.get_object('shortcut_preview_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._builder
+ .get_object('shortcut_num_keys_combo')
+ .set_active_id(this._settings.get_string('shortcut-num-keys'))
+ this._builder
+ .get_object('shortcut_num_keys_combo')
+ .connect('changed', (widget) => {
+ this._settings.set_string('shortcut-num-keys', widget.get_active_id())
+ })
+
+ this._settings.connect('changed::hotkey-prefix-text', () => {
+ checkHotkeyPrefix(this._settings)
+ })
+
+ this._builder
+ .get_object('hotkey_prefix_combo')
+ .set_active_id(this._settings.get_string('hotkey-prefix-text'))
+
+ this._settings.bind(
+ 'hotkey-prefix-text',
+ this._builder.get_object('hotkey_prefix_combo'),
+ 'active-id',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._builder
+ .get_object('overlay_combo')
+ .set_active_id(this._settings.get_string('hotkeys-overlay-combo'))
+
+ this._settings.bind(
+ 'hotkeys-overlay-combo',
+ this._builder.get_object('overlay_combo'),
+ 'active-id',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'shortcut-text',
+ this._builder.get_object('shortcut_entry'),
+ 'text',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+ this._settings.connect('changed::shortcut-text', () => {
+ setShortcut(this._settings, 'shortcut')
+ })
+
+ // Create dialog for number overlay options
+ this._builder.get_object('overlay_button').connect('clicked', () => {
+ let box = this._builder.get_object('box_overlay_shortcut')
+
+ let dialog = this._createPreferencesDialog(
+ _('Advanced hotkeys options'),
+ box,
+ () => {
+ // restore default settings for the relevant keys
+ let keys = [
+ 'hotkey-prefix-text',
+ 'shortcut-text',
+ 'hotkeys-overlay-combo',
+ 'shortcut-previews',
+ ]
+ keys.forEach(function (val) {
+ this._settings.set_value(val, this._settings.get_default_value(val))
+ }, this)
+ },
+ )
+
+ dialog.show()
+ dialog.set_default_size(600, 1)
+ })
+
+ // Fine-tune panel
+
+ let scaleInfos = [
+ {
+ objectName: 'panel_size_scale',
+ valueName: 'tray-size',
+ range: DEFAULT_PANEL_SIZES,
+ getValue: () =>
+ PanelSettings.getPanelSize(this._settings, this._currentMonitorIndex),
+ setValue: (value) => {
+ const monitorSync = this._settings.get_boolean(
+ 'panel-element-positions-monitors-sync',
+ )
+ const monitorsToSetFor = monitorSync
+ ? Object.keys(this.monitors)
+ : [this._currentMonitorIndex]
+ monitorsToSetFor.forEach((monitorIndex) => {
+ PanelSettings.setPanelSize(this._settings, monitorIndex, value)
+ })
+ },
+ },
+ panelLengthScale,
+ {
+ objectName: 'global_border_radius_scale',
+ valueName: 'global-border-radius',
+ range: [5, 4, 3, 2, 1, 0],
+ rangeFactor: 5,
+ },
+ {
+ objectName: 'panel_margin_scale',
+ valueName: 'panel-margin',
+ range: DEFAULT_MARGIN_SIZES,
+ },
+ ]
+
+ let connectValueChanged = (scaleObj, scaleInfo) => {
+ let timeoutId = 0
+
+ scaleObj = scaleObj || this._builder.get_object(scaleInfo.objectName)
+
+ scaleInfo.valueChangedId = scaleObj.connect('value-changed', () => {
+ // Avoid settings the size consinuosly
+ if (timeoutId > 0) GLib.Source.remove(timeoutId)
+
+ timeoutId = GLib.timeout_add(
+ GLib.PRIORITY_DEFAULT,
+ SCALE_UPDATE_TIMEOUT,
+ () => {
+ let value = scaleObj.get_value()
+
+ scaleInfo.setValue
+ ? scaleInfo.setValue(value)
+ : this._settings.set_int(scaleInfo.valueName, value)
+ timeoutId = 0
+
+ return GLib.SOURCE_REMOVE
+ },
+ )
+ })
+ }
+
+ for (const idx in scaleInfos) {
+ let scaleInfo = scaleInfos[idx]
+ let scaleObj = this._builder.get_object(scaleInfo.objectName)
+ let range = scaleInfo.range
+ let factor = scaleInfo.rangeFactor
+ let value = scaleInfo.getValue
+ ? scaleInfo.getValue()
+ : this._settings.get_int(scaleInfo.valueName)
+
+ scaleObj.set_range(range[range.length - 1], range[0])
+ scaleObj.set_value(value)
+ // Add marks from range arrays, omitting the first and last values.
+ range.slice(1, -1).forEach(function (val) {
+ scaleObj.add_mark(
+ val,
+ Gtk.PositionType.TOP,
+ (val * (factor || 1)).toString(),
+ )
+ })
+
+ if (!scaleInfo.manualConnect) connectValueChanged(scaleObj, scaleInfo)
+
+ scaleObj.set_format_value_func((scale, value) => {
+ return `${value * (factor || 1)} ${scaleInfo.unit || 'px'}`
+ })
+
+ // Corrent for rtl languages
+ if (this._rtl) {
+ // Flip value position: this is not done automatically
+ scaleObj.set_value_pos(Gtk.PositionType.LEFT)
+ // I suppose due to a bug, having a more than one mark and one above a value of 100
+ // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable
+ // and then manually inverting it
+ scaleObj.set_flippable(false)
+ scaleObj.set_inverted(true)
+ }
+ }
+
+ maybeSetPanelLengthScaleValueChange(
+ PanelSettings.getPanelLength(this._settings, this._currentMonitorIndex),
+ )
+
+ this._settings.bind(
+ 'stockgs-keep-top-panel',
+ this._builder.get_object('stockgs_top_panel_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+
+ this._settings.bind(
+ 'stockgs-panelbtn-click-only',
+ this._builder.get_object('stockgs_panelbtn_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT,
+ )
+ }
+}
+
+const BuilderScope = GObject.registerClass(
+ {
+ Implements: [Gtk.BuilderScope],
+ },
+ class BuilderScope extends GObject.Object {
+ _init(preferences) {
+ this._preferences = preferences
+ super._init()
+ }
+
+ vfunc_create_closure(builder, handlerName, flags, connectObject) {
+ if (flags & Gtk.BuilderClosureFlags.SWAPPED)
+ throw new Error('Unsupported template signal flag "swapped"')
+
+ if (typeof this[handlerName] === 'undefined')
+ throw new Error(`${handlerName} is undefined`)
+
+ return this[handlerName].bind(connectObject || this)
+ }
+
+ on_btn_click(connectObject) {
+ connectObject.set_label('Clicked')
+ }
+
+ position_bottom_button_clicked_cb(button) {
+ if (!this._preferences._ignorePositionRadios && button.get_active())
+ this._preferences._setPanelPosition(Pos.BOTTOM)
+ }
+
+ position_top_button_clicked_cb(button) {
+ if (!this._preferences._ignorePositionRadios && button.get_active())
+ this._preferences._setPanelPosition(Pos.TOP)
+ }
+
+ position_left_button_clicked_cb(button) {
+ if (!this._preferences._ignorePositionRadios && button.get_active())
+ this._preferences._setPanelPosition(Pos.LEFT)
+ }
+
+ position_right_button_clicked_cb(button) {
+ if (!this._preferences._ignorePositionRadios && button.get_active())
+ this._preferences._setPanelPosition(Pos.RIGHT)
+ }
+ },
+)
+
+export default class ZorinTaskbarPreferences extends ExtensionPreferences {
+ fillPreferencesWindow(window) {
+ let closeRequestId = null
+
+ window._settings = this.getSettings(
+ 'org.gnome.shell.extensions.zorin-taskbar',
+ )
+ window._gnomeInterfaceSettings = new Gio.Settings({
+ schema_id: 'org.gnome.desktop.interface',
+ })
+
+ // use default width or window
+ window.set_default_size(0, 625)
+
+ new Preferences(window, window._settings, window._gnomeInterfaceSettings, this.path)
+ }
+}
diff --git a/src/proximity.js b/src/proximity.js
new file mode 100644
index 0000000..ee2ca5c
--- /dev/null
+++ b/src/proximity.js
@@ -0,0 +1,285 @@
+/*
+ * 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 .
+ *
+ * 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,
+}
+
+export class ProximityWatch {
+ constructor(actor, monitorIndex, mode, xThreshold, yThreshold, handler) {
+ this.actor = actor
+ this.monitorIndex = monitorIndex
+ this.overlap = false
+ this.mode = mode
+ this.threshold = [xThreshold, yThreshold]
+ this.handler = handler
+
+ this._allocationChangedId = actor.connect('notify::allocation', () =>
+ this._updateWatchRect(),
+ )
+
+ this._updateWatchRect()
+ }
+
+ destroy() {
+ this.actor.disconnect(this._allocationChangedId)
+ }
+
+ _updateWatchRect() {
+ let [actorX, actorY] = this.actor.get_position()
+
+ this.rect = new Mtk.Rectangle({
+ x: actorX - this.threshold[0],
+ y: actorY - this.threshold[1],
+ width: this.actor.width + this.threshold[0] * 2,
+ height: this.actor.height + this.threshold[1] * 2,
+ })
+ }
+}
+
+export const ProximityManager = class {
+ constructor() {
+ this._counter = 1
+ this._watches = {}
+ this._focusedWindowInfo = null
+
+ this._signalsHandler = new Utils.GlobalSignalsHandler()
+ this._timeoutsHandler = new Utils.TimeoutsHandler()
+
+ this._bindSignals()
+ this._setFocusedWindow()
+ }
+
+ createWatch(actor, monitorIndex, mode, xThreshold, yThreshold, handler) {
+ let watch = new ProximityWatch(
+ actor,
+ monitorIndex,
+ mode,
+ xThreshold,
+ yThreshold,
+ handler,
+ )
+
+ this._watches[this._counter] = watch
+ this.update()
+
+ return this._counter++
+ }
+
+ removeWatch(id) {
+ if (this._watches[id]) {
+ this._watches[id].destroy()
+ delete this._watches[id]
+ }
+ }
+
+ update() {
+ this._queueUpdate(true)
+ }
+
+ destroy() {
+ this._signalsHandler.destroy()
+ this._timeoutsHandler.destroy()
+ this._disconnectFocusedWindow()
+ Object.keys(this._watches).forEach((id) => this.removeWatch(id))
+ }
+
+ _bindSignals() {
+ this._signalsHandler.add(
+ [global.window_manager, 'switch-workspace', () => this._queueUpdate()],
+ [Main.overview, 'hidden', () => this._queueUpdate()],
+ [
+ global.display,
+ 'notify::focus-window',
+ () => {
+ this._setFocusedWindow()
+ this._queueUpdate()
+ },
+ ],
+ [global.display, 'restacked', () => this._queueUpdate()],
+ )
+ }
+
+ _setFocusedWindow() {
+ this._disconnectFocusedWindow()
+
+ let focusedWindow = global.display.focus_window
+
+ if (focusedWindow) {
+ let focusedWindowInfo = this._getFocusedWindowInfo(focusedWindow)
+
+ if (
+ focusedWindowInfo &&
+ this._checkIfHandledWindowType(focusedWindowInfo.metaWindow)
+ ) {
+ focusedWindowInfo.allocationId = focusedWindowInfo.window.connect(
+ 'notify::allocation',
+ () => this._queueUpdate(),
+ )
+ focusedWindowInfo.destroyId = focusedWindowInfo.window.connect(
+ 'destroy',
+ () => this._disconnectFocusedWindow(true),
+ )
+
+ this._focusedWindowInfo = focusedWindowInfo
+ }
+ }
+ }
+
+ _getFocusedWindowInfo(focusedWindow) {
+ let window = focusedWindow.get_compositor_private()
+ let focusedWindowInfo
+
+ if (window) {
+ focusedWindowInfo = { window: window }
+ focusedWindowInfo.metaWindow = focusedWindow
+
+ if (focusedWindow.is_attached_dialog()) {
+ let mainMetaWindow = focusedWindow.get_transient_for()
+
+ if (
+ focusedWindowInfo.metaWindow.get_frame_rect().height <
+ mainMetaWindow.get_frame_rect().height
+ ) {
+ focusedWindowInfo.window = mainMetaWindow.get_compositor_private()
+ focusedWindowInfo.metaWindow = mainMetaWindow
+ }
+ }
+ }
+
+ return focusedWindowInfo
+ }
+
+ _disconnectFocusedWindow(destroy) {
+ if (this._focusedWindowInfo && !destroy) {
+ this._focusedWindowInfo.window.disconnect(
+ this._focusedWindowInfo.allocationId,
+ )
+ this._focusedWindowInfo.window.disconnect(
+ this._focusedWindowInfo.destroyId,
+ )
+ }
+
+ this._focusedWindowInfo = null
+ }
+
+ _getHandledWindows() {
+ return Utils.getCurrentWorkspace()
+ .list_windows()
+ .filter((mw) => this._checkIfHandledWindow(mw))
+ }
+
+ _checkIfHandledWindow(metaWindow) {
+ return (
+ metaWindow &&
+ !metaWindow.minimized &&
+ !metaWindow.customJS_ding &&
+ 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),
+ ))
+ )
+ }
+}
diff --git a/stylesheet.css b/src/stylesheet.css
similarity index 66%
rename from stylesheet.css
rename to src/stylesheet.css
index 6dd4d17..1ea5d34 100644
--- a/stylesheet.css
+++ b/src/stylesheet.css
@@ -44,7 +44,6 @@
#zorintaskbarTaskbar .dash-item-container .overview-tile:hover,
#zorintaskbarTaskbar .dash-item-container .overview-tile .dtp-container .overview-icon,
-#zorintaskbarScrollview .overview-tile:hover .dtp-container.animate-appicon-hover,
.zorintaskbarMainPanel .dash-item-container .show-apps:hover .overview-icon {
background: none;
}
@@ -112,32 +111,13 @@
spacing: 0px;
}
-#panelBox.floating {
- background: transparent;
-}
-#panelBox.floating.top {
- padding: 8px 8px 0 8px;
-}
-#panelBox.floating.right {
- padding: 8px 8px 8px 0;
-}
-#panelBox.floating.bottom {
- padding: 0 8px 8px 8px;
-}
-#panelBox.floating.left {
- padding: 8px 0 8px 8px;
-}
-
-#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);
+ padding: 0.2em 0.5em;
+ border-radius: 1em;
font-weight: bold;
text-align: center;
+ margin: 0 0 0 2px;
}
#zorintaskbarScrollview .number-overlay {
@@ -159,3 +139,64 @@
#preview-menu {
border-radius: 10px;
}
+
+/* border radius, grrr no css variables in ST */
+#uiGroup.br5 .zorintaskbarPanel.dock,
+#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 .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 .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 .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 .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;
+}
diff --git a/src/taskbar.js b/src/taskbar.js
new file mode 100644
index 0000000..3b43bf9
--- /dev/null
+++ b/src/taskbar.js
@@ -0,0 +1,1479 @@
+/*
+ * 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 .
+ *
+ *
+ * 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 Gio from 'gi://Gio'
+import GLib from 'gi://GLib'
+import GObject from 'gi://GObject'
+import Graphene from 'gi://Graphene'
+import Shell from 'gi://Shell'
+import St from 'gi://St'
+
+import * as AppFavorites from 'resource:///org/gnome/shell/ui/appFavorites.js'
+import * as Dash from 'resource:///org/gnome/shell/ui/dash.js'
+import * as DND from 'resource:///org/gnome/shell/ui/dnd.js'
+import * as Main from 'resource:///org/gnome/shell/ui/main.js'
+import { EventEmitter } from 'resource:///org/gnome/shell/misc/signals.js'
+
+import * as AppIcons from './appIcons.js'
+import * as PanelManager from './panelManager.js'
+import * as PanelSettings from './panelSettings.js'
+import * as Pos from './panelPositions.js'
+import * as Utils from './utils.js'
+import * as WindowPreview from './windowPreview.js'
+import { SETTINGS, tracker } from './extension.js'
+
+const SearchController = Main.overview.searchController
+
+export var hotkeyAppNumbers = {}
+
+export const DASH_ANIMATION_TIME = 0.2 // Dash.DASH_ANIMATION_TIME is now private
+const DASH_ITEM_HOVER_TIMEOUT = 0.3 // Dash.DASH_ITEM_HOVER_TIMEOUT is now private
+export const MIN_ICON_SIZE = 4
+export const APPICON_MARGIN = 6
+export const APPICON_PADDING = 8
+
+const T1 = 'ensureAppIconVisibilityTimeout'
+const T2 = 'showLabelTimeout'
+const T3 = 'resetHoverTimeout'
+
+/**
+ * Extend DashItemContainer
+ *
+ * - set label position based on taskbar orientation
+ *
+ * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973.
+ * thus use this ugly pattern.
+ */
+
+export function extendDashItemContainer(dashItemContainer) {
+ dashItemContainer.showLabel = AppIcons.ItemShowLabel
+}
+
+/* This class is a fork of the upstream DashActor class (ui.dash.js)
+ *
+ * Summary of changes:
+ * - modified chldBox calculations for when 'show-apps-at-top' option is checked
+ * - handle horizontal dash
+ */
+export const TaskbarActor = GObject.registerClass(
+ {},
+ class TaskbarActor extends St.Widget {
+ _init(delegate) {
+ this._delegate = delegate
+ this._currentBackgroundColor = 0
+ super._init({
+ name: 'zorintaskbarTaskbar',
+ layout_manager: new Clutter.BoxLayout({
+ orientation:
+ Clutter.Orientation[
+ delegate.dtpPanel.getOrientation().toUpperCase()
+ ],
+ }),
+ clip_to_allocation: true,
+ })
+ }
+
+ vfunc_allocate(box) {
+ this.set_allocation(box)
+
+ let panel = this._delegate.dtpPanel
+ let availFixedSize = box[panel.fixedCoord.c2] - box[panel.fixedCoord.c1]
+ let availVarSize = box[panel.varCoord.c2] - box[panel.varCoord.c1]
+ let [dummy, scrollview, leftFade, rightFade] = this.get_children()
+ let [, natSize] = this[panel.sizeFunc](availFixedSize)
+ let childBox = new Clutter.ActorBox()
+ let orientation = panel.getOrientation()
+
+ dummy.allocate(childBox)
+
+ childBox[panel.varCoord.c1] = box[panel.varCoord.c1]
+ childBox[panel.varCoord.c2] = Math.min(availVarSize, natSize)
+ childBox[panel.fixedCoord.c1] = box[panel.fixedCoord.c1]
+ childBox[panel.fixedCoord.c2] = box[panel.fixedCoord.c2]
+
+ scrollview.allocate(childBox)
+
+ let [, , upper, , , pageSize] =
+ scrollview[orientation[0] + 'adjustment'].get_values()
+ upper = Math.floor(upper)
+ scrollview._dtpFadeSize = upper > pageSize ? this._delegate.iconSize : 0
+
+ if (
+ this._currentBackgroundColor !==
+ panel.dynamicTransparency.currentBackgroundColor
+ ) {
+ this._currentBackgroundColor =
+ panel.dynamicTransparency.currentBackgroundColor
+ let gradientStyle =
+ 'background-gradient-start: ' +
+ this._currentBackgroundColor +
+ 'background-gradient-direction: ' +
+ orientation
+
+ leftFade.set_style(gradientStyle)
+ rightFade.set_style(gradientStyle)
+ }
+
+ childBox[panel.varCoord.c2] =
+ childBox[panel.varCoord.c1] + scrollview._dtpFadeSize
+ leftFade.allocate(childBox)
+
+ childBox[panel.varCoord.c1] =
+ box[panel.varCoord.c2] - scrollview._dtpFadeSize
+ childBox[panel.varCoord.c2] = box[panel.varCoord.c2]
+ rightFade.allocate(childBox)
+ }
+
+ // We want to request the natural size of all our children
+ // as our natural width, so we chain up to StWidget (which
+ // then calls BoxLayout)
+ vfunc_get_preferred_width(forHeight) {
+ let [, natWidth] = St.Widget.prototype.vfunc_get_preferred_width.call(
+ this,
+ forHeight,
+ )
+
+ return [0, natWidth]
+ }
+
+ vfunc_get_preferred_height(forWidth) {
+ let [, natHeight] = St.Widget.prototype.vfunc_get_preferred_height.call(
+ this,
+ forWidth,
+ )
+
+ return [0, natHeight]
+ }
+ },
+)
+
+/* This class is a fork of the upstream dash class (ui.dash.js)
+ *
+ * Summary of changes:
+ * - disconnect global signals adding a destroy method;
+ * - play animations even when not in overview mode
+ * - set a maximum icon size
+ * - show running and/or favorite applications
+ * - emit a custom signal when an app icon is added
+ * - Add scrollview
+ * Ensure actor is visible on keyfocus inside the scrollview
+ * - add 128px icon size, might be useful for hidpi display
+ * - Sync minimization application target position.
+ */
+
+export const Taskbar = class extends EventEmitter {
+ constructor(panel) {
+ super()
+
+ this.dtpPanel = panel
+
+ // start at smallest size due to running indicator drawing area expanding but not shrinking
+ this.iconSize = 16
+
+ this._shownInitially = false
+
+ this._signalsHandler = new Utils.GlobalSignalsHandler()
+ this._timeoutsHandler = new Utils.TimeoutsHandler()
+
+ this._labelShowing = false
+ this.fullScrollView = 0
+
+ let isVertical = panel.checkIfVertical()
+
+ this._box = Utils.createBoxLayout({
+ vertical: isVertical,
+ clip_to_allocation: false,
+ x_align: Clutter.ActorAlign.START,
+ y_align: Clutter.ActorAlign.START,
+ })
+
+ this._container = new TaskbarActor(this)
+ this._scrollView = new St.ScrollView({
+ name: 'zorintaskbarScrollview',
+ hscrollbar_policy: St.PolicyType.NEVER,
+ vscrollbar_policy: St.PolicyType.NEVER,
+ enable_mouse_scrolling: true,
+ })
+
+ this._scrollView.connect('scroll-event', this._onScrollEvent.bind(this))
+ this._scrollView.add_child(this._box)
+
+ this._showAppsIconWrapper = panel.showAppsIconWrapper
+ this._showAppsIconWrapper.connect(
+ 'menu-state-changed',
+ (showAppsIconWrapper, opened) => {
+ this._itemMenuStateChanged(showAppsIconWrapper, opened)
+ },
+ )
+ // an instance of the showAppsIcon class is encapsulated in the wrapper
+ this._showAppsIcon = this._showAppsIconWrapper.realShowAppsIcon
+ this.showAppsButton = this._showAppsIcon.toggleButton
+
+ if (isVertical) {
+ this.showAppsButton.set_width(panel.geom.w)
+ }
+
+ this.showAppsButton.connect(
+ 'notify::checked',
+ this._onShowAppsButtonToggled.bind(this),
+ )
+
+ this.showAppsButton.checked = SearchController._showAppsButton
+ ? SearchController._showAppsButton.checked
+ : false
+
+ this._showAppsIcon.childScale = 1
+ this._showAppsIcon.childOpacity = 255
+ this._showAppsIcon.icon.setIconSize(this.iconSize)
+ this._hookUpLabel(this._showAppsIcon, this._showAppsIconWrapper)
+
+ this._container.add_child(new St.Widget({ width: 0, reactive: false }))
+ this._container.add_child(this._scrollView)
+
+ let orientation = panel.getOrientation()
+ let fadeStyle = 'background-gradient-direction:' + orientation
+ this._fadeLeft = new St.Widget({
+ style_class: 'scrollview-fade',
+ reactive: false,
+ })
+ this._fadeRight = new St.Widget({
+ style_class: 'scrollview-fade',
+ reactive: false,
+ pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
+ rotation_angle_z: 180,
+ })
+
+ this._fadeLeft.set_style(fadeStyle)
+ this._fadeRight.set_style(fadeStyle)
+
+ this._container.add_child(this._fadeLeft)
+ this._container.add_child(this._fadeRight)
+
+ this.previewMenu = new WindowPreview.PreviewMenu(panel)
+ this.previewMenu.enable()
+
+ let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL
+ this.actor = new St.Bin({
+ child: this._container,
+ y_align: Clutter.ActorAlign.START,
+ x_align: rtl ? Clutter.ActorAlign.END : Clutter.ActorAlign.START,
+ })
+
+ const adjustment = this._scrollView[orientation[0] + 'adjustment']
+
+ this._workId = Main.initializeDeferredWork(
+ this._box,
+ this._redisplay.bind(this),
+ )
+
+ this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' })
+
+ this._appSystem = Shell.AppSystem.get_default()
+
+ this.iconAnimator = new PanelManager.IconAnimator(this.dtpPanel.panel)
+
+ this._signalsHandler.add(
+ [this.dtpPanel.panel, 'notify::height', () => this._queueRedisplay()],
+ [this.dtpPanel.panel, 'notify::width', () => this._queueRedisplay()],
+ [
+ this._appSystem,
+ 'installed-changed',
+ () => {
+ AppFavorites.getAppFavorites().reload()
+ this._queueRedisplay()
+ },
+ ],
+ [this._appSystem, 'app-state-changed', this._queueRedisplay.bind(this)],
+ [
+ AppFavorites.getAppFavorites(),
+ 'changed',
+ this._queueRedisplay.bind(this),
+ ],
+ [
+ global.window_manager,
+ 'switch-workspace',
+ () => this._connectWorkspaceSignals(),
+ ],
+ [
+ Utils.DisplayWrapper.getScreen(),
+ ['window-entered-monitor', 'window-left-monitor'],
+ () => {
+ if (SETTINGS.get_boolean('isolate-monitors')) {
+ this._queueRedisplay()
+ }
+ },
+ ],
+ [Main.overview, 'item-drag-begin', this._onDragBegin.bind(this)],
+ [Main.overview, 'item-drag-end', this._onDragEnd.bind(this)],
+ [Main.overview, 'item-drag-cancelled', this._onDragCancelled.bind(this)],
+ [
+ // Ensure the ShowAppsButton status is kept in sync
+ SearchController._showAppsButton,
+ 'notify::checked',
+ this._syncShowAppsButtonToggled.bind(this),
+ ],
+ [
+ SETTINGS,
+ [
+ 'changed::show-favorites',
+ 'changed::show-running-apps',
+ 'changed::show-favorites-all-monitors',
+ ],
+ () => {
+ setAttributes()
+ this._redisplay()
+ },
+ ],
+ [
+ SETTINGS,
+ 'changed::group-apps',
+ () => {
+ setAttributes()
+ this._connectWorkspaceSignals()
+ },
+ ],
+ [
+ SETTINGS,
+ [
+ 'changed::group-apps-use-launchers',
+ 'changed::taskbar-locked',
+ ],
+ () => {
+ setAttributes()
+ this.resetAppIcons()
+ },
+ ],
+ [
+ adjustment,
+ ['notify::upper', 'notify::pageSize'],
+ () => this._onScrollSizeChange(adjustment),
+ ],
+ )
+
+ let setAttributes = () => {
+ this.isGroupApps = SETTINGS.get_boolean('group-apps')
+ this.usingLaunchers =
+ !this.isGroupApps && SETTINGS.get_boolean('group-apps-use-launchers')
+ this.showFavorites =
+ SETTINGS.get_boolean('show-favorites') &&
+ (this.dtpPanel.isPrimary ||
+ SETTINGS.get_boolean('show-favorites-all-monitors'))
+ this.showRunningApps = SETTINGS.get_boolean('show-running-apps')
+ this.allowSplitApps =
+ this.usingLaunchers || (!this.isGroupApps && !this.showFavorites)
+ }
+
+ setAttributes()
+
+ this._onScrollSizeChange(adjustment)
+ this._connectWorkspaceSignals()
+ }
+
+ destroy() {
+ if (this._waitIdleId) {
+ GLib.source_remove(this._waitIdleId)
+ this._waitIdleId = 0
+ }
+
+ this._timeoutsHandler.destroy()
+ this.iconAnimator.destroy()
+
+ this._signalsHandler.destroy()
+ this._signalsHandler = 0
+
+ this._container.destroy()
+
+ this.previewMenu.disable()
+ this.previewMenu.destroy()
+
+ this._disconnectWorkspaceSignals()
+ }
+
+ _maybeUpdateScrollviewFade(adjustment) {
+ if (this._scrollView._dtpFadeSize) {
+ adjustment =
+ adjustment ||
+ this._scrollView[this.dtpPanel.getOrientation()[0] + 'adjustment']
+ let [value, , upper, , , pageSize] = adjustment.get_values()
+
+ this._fadeLeft.visible = value > 0
+ this._fadeRight.visible = value + pageSize < upper
+ }
+ }
+
+ _onScrollEvent(actor, event) {
+ let orientation = this.dtpPanel.getOrientation()
+
+ // reset timeout to avid conflicts with the mousehover event
+ this._timeoutsHandler.add([T1, 0, () => (this._swiping = false)])
+
+ // Skip to avoid double events mouse
+ if (event.is_pointer_emulated()) return Clutter.EVENT_STOP
+
+ let adjustment, delta
+
+ adjustment = this._scrollView[orientation[0] + 'adjustment']
+
+ let increment = adjustment.step_increment
+
+ switch (event.get_scroll_direction()) {
+ case Clutter.ScrollDirection.UP:
+ case Clutter.ScrollDirection.LEFT:
+ delta = -increment
+ break
+ case Clutter.ScrollDirection.DOWN:
+ case Clutter.ScrollDirection.RIGHT:
+ delta = +increment
+ break
+ case Clutter.ScrollDirection.SMOOTH: {
+ let [dx, dy] = event.get_scroll_delta()
+ delta = dy * increment
+ delta += dx * increment
+ break
+ }
+ }
+
+ adjustment.set_value(adjustment.get_value() + delta)
+
+ this._maybeUpdateScrollviewFade(adjustment)
+
+ return Clutter.EVENT_STOP
+ }
+
+ _onScrollSizeChange(adjustment) {
+ // Update minimization animation target position on scrollview change.
+ this._updateAppIcons()
+ this._maybeUpdateScrollviewFade()
+
+ // When applications are ungrouped and there is some empty space on the horizontal taskbar,
+ // force a fixed label width to prevent the icons from "wiggling" when an animation runs
+ // (adding or removing an icon). When the taskbar is full, revert to a dynamic label width
+ // to allow them to resize and make room for new icons.
+ if (!this.dtpPanel.checkIfVertical() && !this.isGroupApps) {
+ let initial = this.fullScrollView
+
+ if (
+ !this.fullScrollView &&
+ Math.floor(adjustment.upper) > adjustment.page_size
+ ) {
+ this.fullScrollView = adjustment.page_size
+ } else if (adjustment.page_size < this.fullScrollView) {
+ this.fullScrollView = 0
+ }
+
+ if (initial != this.fullScrollView && !this._waitIdleId) {
+ this._waitIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
+ this._getAppIcons().forEach((a) => a.updateTitleStyle())
+ this._waitIdleId = 0
+
+ return GLib.SOURCE_REMOVE
+ })
+ }
+ }
+ }
+
+ _onDragBegin() {
+ this._dragCancelled = false
+ this._dragMonitor = {
+ dragMotion: this._onDragMotion.bind(this),
+ }
+ DND.addDragMonitor(this._dragMonitor)
+
+ if (this._box.get_n_children() == 0) {
+ this._emptyDropTarget = new Dash.EmptyDropTargetItem()
+ this._box.insert_child_at_index(this._emptyDropTarget, 0)
+ this._emptyDropTarget.show(true)
+ }
+
+ this._toggleFavoriteHighlight(true)
+ }
+
+ _onDragCancelled() {
+ this._dragCancelled = true
+
+ if (this._dragInfo) {
+ this._box.set_child_at_index(
+ this._dragInfo[1]._dashItemContainer,
+ this._dragInfo[0],
+ )
+ }
+
+ this._endDrag()
+ }
+
+ _onDragEnd() {
+ if (this._dragCancelled) return
+
+ this._endDrag()
+ }
+
+ _endDrag() {
+ if (
+ this._dragInfo &&
+ this._dragInfo[1]._dashItemContainer instanceof DragPlaceholderItem
+ ) {
+ this._box.remove_child(this._dragInfo[1]._dashItemContainer)
+ this._dragInfo[1]._dashItemContainer.destroy()
+ delete this._dragInfo[1]._dashItemContainer
+ }
+
+ this._dragInfo = null
+ this._clearEmptyDropTarget()
+ this._showAppsIcon.setDragApp(null)
+ DND.removeDragMonitor(this._dragMonitor)
+
+ this._dragMonitor = null
+ this.emit('end-drag')
+
+ this._toggleFavoriteHighlight()
+ }
+
+ _onDragMotion(dragEvent) {
+ let app = Dash.Dash.getAppFromSource(dragEvent.source)
+ if (app == null) return DND.DragMotionResult.CONTINUE
+
+ let showAppsHovered = this._showAppsIcon.contains(dragEvent.targetActor)
+
+ if (showAppsHovered) this._showAppsIcon.setDragApp(app)
+ else this._showAppsIcon.setDragApp(null)
+
+ return DND.DragMotionResult.CONTINUE
+ }
+
+ _toggleFavoriteHighlight(show) {
+ let appFavorites = AppFavorites.getAppFavorites()
+ let cssFuncName = (show ? 'add' : 'remove') + '_style_class_name'
+
+ if (this.showFavorites)
+ this._getAppIcons()
+ .filter(
+ (appIcon) =>
+ (this.usingLaunchers && appIcon.isLauncher) ||
+ (!this.usingLaunchers &&
+ appFavorites.isFavorite(appIcon.app.get_id())),
+ )
+ .forEach((fav) => fav._container[cssFuncName]('favorite'))
+ }
+
+ handleIsolatedWorkspaceSwitch() {
+ this._shownInitially = this.isGroupApps
+ this._queueRedisplay()
+ }
+
+ _connectWorkspaceSignals() {
+ this._disconnectWorkspaceSignals()
+
+ this._lastWorkspace =
+ Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace()
+
+ this._workspaceWindowAddedId = this._lastWorkspace.connect(
+ 'window-added',
+ () => this._queueRedisplay(),
+ )
+ this._workspaceWindowRemovedId = this._lastWorkspace.connect(
+ 'window-removed',
+ () => this._queueRedisplay(),
+ )
+ }
+
+ _disconnectWorkspaceSignals() {
+ if (this._lastWorkspace) {
+ this._lastWorkspace.disconnect(this._workspaceWindowAddedId)
+ this._lastWorkspace.disconnect(this._workspaceWindowRemovedId)
+
+ this._lastWorkspace = null
+ }
+ }
+
+ _queueRedisplay() {
+ Main.queueDeferredWork(this._workId)
+ }
+
+ _hookUpLabel(item, syncHandler) {
+ item.child.connect('notify::hover', () => {
+ this._syncLabel(item, syncHandler)
+ })
+
+ syncHandler.connect('sync-tooltip', () => {
+ this._syncLabel(item, syncHandler)
+ })
+ }
+
+ _createAppItem(app, window, isLauncher) {
+ let appIcon = new AppIcons.TaskbarAppIcon(
+ {
+ app,
+ window,
+ isLauncher,
+ },
+ this.dtpPanel,
+ {
+ setSizeManually: true,
+ showLabel: false,
+ isDraggable: !SETTINGS.get_boolean('taskbar-locked'),
+ },
+ this.previewMenu,
+ this.iconAnimator,
+ )
+
+ if (appIcon._draggable) {
+ appIcon._draggable.connect('drag-begin', () => {
+ appIcon.opacity = 0
+ appIcon.isDragged = 1
+ })
+ appIcon._draggable.connect('drag-end', () => {
+ appIcon.opacity = 255
+ delete appIcon.isDragged
+ this._updateAppIcons()
+ })
+ }
+
+ appIcon.connect('menu-state-changed', (appIcon, opened) => {
+ this._itemMenuStateChanged(item, opened)
+ })
+
+ let item = new TaskbarItemContainer()
+
+ item._dtpPanel = this.dtpPanel
+ extendDashItemContainer(item)
+
+ item.setChild(appIcon)
+ appIcon._dashItemContainer = item
+
+ appIcon.connect('notify::hover', () => {
+ if (appIcon.hover) {
+ this._timeoutsHandler.add([
+ T1,
+ 100,
+ () =>
+ Utils.ensureActorVisibleInScrollView(
+ this._scrollView,
+ appIcon,
+ this._scrollView._dtpFadeSize,
+ ),
+ ])
+ } else {
+ this._timeoutsHandler.remove(T1)
+ }
+ })
+
+ appIcon.connect('clicked', (actor) => {
+ Utils.ensureActorVisibleInScrollView(
+ this._scrollView,
+ actor,
+ this._scrollView._dtpFadeSize,
+ )
+ })
+
+ appIcon.connect('key-focus-in', (actor) => {
+ let [x_shift, y_shift] = Utils.ensureActorVisibleInScrollView(
+ this._scrollView,
+ actor,
+ this._scrollView._dtpFadeSize,
+ )
+
+ // This signal is triggered also by mouse click. The popup menu is opened at the original
+ // coordinates. Thus correct for the shift which is going to be applied to the scrollview.
+ if (appIcon._menu) {
+ appIcon._menu._boxPointer.xOffset = -x_shift
+ appIcon._menu._boxPointer.yOffset = -y_shift
+ }
+ })
+
+ // Override default AppIcon label_actor, now the
+ // accessible_name is set at DashItemContainer.setLabelText
+ appIcon.label_actor = null
+ item.setLabelText(app.get_name())
+
+ appIcon.icon.setIconSize(this.iconSize)
+ this._hookUpLabel(item, appIcon)
+
+ return item
+ }
+
+ // Return an array with the "proper" appIcons currently in the taskbar
+ _getAppIcons() {
+ // Only consider children which are "proper" icons and which are not
+ // animating out (which means they will be destroyed at the end of
+ // the animation)
+ return this._getTaskbarIcons().map(function (actor) {
+ return actor.child._delegate
+ })
+ }
+
+ _getTaskbarIcons(includeAnimated) {
+ return this._box.get_children().filter(function (actor) {
+ return (
+ actor.child &&
+ actor.child._delegate &&
+ actor.child._delegate.icon &&
+ (includeAnimated || !actor.animatingOut)
+ )
+ })
+ }
+
+ _updateAppIcons() {
+ let appIcons = this._getAppIcons()
+
+ appIcons
+ .filter((icon) => icon.constructor === AppIcons.TaskbarAppIcon)
+ .forEach((icon) => {
+ icon.updateIcon()
+ })
+ }
+
+ _itemMenuStateChanged(item, opened) {
+ // When the menu closes, it calls sync_hover, which means
+ // that the notify::hover handler does everything we need to.
+ if (opened) {
+ this._timeoutsHandler.remove(T2)
+
+ item.hideLabel()
+ } else {
+ // I want to listen from outside when a menu is closed. I used to
+ // add a custom signal to the appIcon, since gnome 3.8 the signal
+ // calling this callback was added upstream.
+ this.emit('menu-closed')
+ }
+ }
+
+ _syncLabel(item, syncHandler) {
+ let shouldShow = syncHandler
+ ? syncHandler.shouldShowTooltip()
+ : item.child.get_hover()
+
+ if (shouldShow) {
+ if (!this._timeoutsHandler.getId(T2)) {
+ let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT
+
+ this._timeoutsHandler.add([
+ T2,
+ timeout,
+ () => {
+ this._labelShowing = true
+ item.showLabel()
+ },
+ ])
+
+ this._timeoutsHandler.remove(T3)
+ }
+ } else {
+ this._timeoutsHandler.remove(T2)
+
+ item.hideLabel()
+ if (this._labelShowing) {
+ this._timeoutsHandler.add([
+ T3,
+ DASH_ITEM_HOVER_TIMEOUT,
+ () => (this._labelShowing = false),
+ ])
+ }
+ }
+ }
+
+ _adjustIconSize() {
+ let panelSize = this.dtpPanel.geom.iconSize / Utils.getScaleFactor()
+ let availSize = panelSize - APPICON_PADDING * 2
+ let minIconSize = MIN_ICON_SIZE + (panelSize % 2)
+
+ if (availSize == this.iconSize) return
+
+ if (availSize < minIconSize) {
+ availSize = minIconSize
+ }
+
+ // For the icon size, we only consider children which are "proper"
+ // icons and which are not animating out (which means they will be
+ // destroyed at the end of the animation)
+ let iconChildren = this._getTaskbarIcons().concat([this._showAppsIcon])
+ let scale = this.iconSize / availSize
+
+ this.iconSize = availSize
+
+ for (let i = 0; i < iconChildren.length; i++) {
+ let icon = iconChildren[i].child._delegate.icon
+
+ // Set the new size immediately, to keep the icons' sizes
+ // in sync with this.iconSize
+ icon.setIconSize(this.iconSize)
+
+ // Don't animate the icon size change when the overview
+ // is transitioning, or when initially filling
+ // the taskbar
+ if (Main.overview.animationInProgress || !this._shownInitially) continue
+
+ let [targetWidth, targetHeight] = icon.icon.get_size()
+
+ // Scale the icon's texture to the previous size and
+ // tween to the new size
+ icon.icon.set_size(icon.icon.width * scale, icon.icon.height * scale)
+
+ Utils.animate(icon.icon, {
+ width: targetWidth,
+ height: targetHeight,
+ time: DASH_ANIMATION_TIME,
+ transition: 'easeOutQuad',
+ })
+ }
+ }
+
+ sortAppsCompareFunction(appA, appB) {
+ return (
+ getAppStableSequence(appA, this.dtpPanel.monitor) -
+ getAppStableSequence(appB, this.dtpPanel.monitor)
+ )
+ }
+
+ getAppInfos() {
+ //get the user's favorite apps
+ let favoriteApps = this.showFavorites
+ ? AppFavorites.getAppFavorites().getFavorites()
+ : []
+
+ //find the apps that should be in the taskbar: the favorites first, then add the running apps
+ // When using isolation, we filter out apps that have no windows in
+ // the current workspace (this check is done in AppIcons.getInterestingWindows)
+ let runningApps = this.showRunningApps
+ ? this._getRunningApps().sort(this.sortAppsCompareFunction.bind(this))
+ : []
+ let appInfos
+
+ if (this.allowSplitApps) {
+ appInfos = this._createAppInfos(favoriteApps, [], true).concat(
+ this._createAppInfos(runningApps).filter(
+ (appInfo) => appInfo.windows.length,
+ ),
+ )
+ } else {
+ appInfos = this._createAppInfos(
+ favoriteApps.concat(
+ runningApps.filter((app) => favoriteApps.indexOf(app) < 0),
+ ),
+ ).filter(
+ (appInfo) =>
+ appInfo.windows.length || favoriteApps.indexOf(appInfo.app) >= 0,
+ )
+ }
+
+ return appInfos
+ }
+
+ _redisplay() {
+ if (!this._signalsHandler) {
+ return
+ }
+
+ //get the currently displayed appIcons
+ let currentAppIcons = this._getTaskbarIcons()
+ let expectedAppInfos = this.getAppInfos()
+
+ //remove the appIcons which are not in the expected apps list
+ for (let i = currentAppIcons.length - 1; i > -1; --i) {
+ let appIcon = currentAppIcons[i].child._delegate
+ let appIndex = Utils.findIndex(
+ expectedAppInfos,
+ (appInfo) =>
+ appInfo.app == appIcon.app &&
+ (!this.allowSplitApps ||
+ this.isGroupApps ||
+ appInfo.windows[0] == appIcon.window) &&
+ appInfo.isLauncher == appIcon.isLauncher,
+ )
+
+ if (
+ appIndex < 0 ||
+ (appIcon.window &&
+ (this.isGroupApps ||
+ expectedAppInfos[appIndex].windows.indexOf(appIcon.window) < 0)) ||
+ (!appIcon.window &&
+ !appIcon.isLauncher &&
+ !this.isGroupApps &&
+ expectedAppInfos[appIndex].windows.length)
+ ) {
+ currentAppIcons[i][
+ this._shownInitially ? 'animateOutAndDestroy' : 'destroy'
+ ]()
+ currentAppIcons.splice(i, 1)
+ }
+ }
+
+ //if needed, reorder the existing appIcons and create the missing ones
+ let currentPosition = 0
+ for (let i = 0, l = expectedAppInfos.length; i < l; ++i) {
+ let neededAppIcons =
+ this.isGroupApps || !expectedAppInfos[i].windows.length
+ ? [
+ {
+ app: expectedAppInfos[i].app,
+ window: null,
+ isLauncher: expectedAppInfos[i].isLauncher,
+ },
+ ]
+ : expectedAppInfos[i].windows.map((window) => ({
+ app: expectedAppInfos[i].app,
+ window: window,
+ isLauncher: false,
+ }))
+
+ for (let j = 0, ll = neededAppIcons.length; j < ll; ++j) {
+ //check if the icon already exists
+ let matchingAppIconIndex = Utils.findIndex(
+ currentAppIcons,
+ (appIcon) =>
+ appIcon.child._delegate.app == neededAppIcons[j].app &&
+ appIcon.child._delegate.window == neededAppIcons[j].window,
+ )
+
+ if (
+ matchingAppIconIndex > 0 &&
+ matchingAppIconIndex != currentPosition
+ ) {
+ //moved icon, reposition it
+ this._box.remove_child(currentAppIcons[matchingAppIconIndex])
+ this._box.insert_child_at_index(
+ currentAppIcons[matchingAppIconIndex],
+ currentPosition,
+ )
+ } else if (matchingAppIconIndex < 0) {
+ //the icon doesn't exist yet, create a new one
+ let newAppIcon = this._createAppItem(
+ neededAppIcons[j].app,
+ neededAppIcons[j].window,
+ neededAppIcons[j].isLauncher,
+ )
+
+ this._box.insert_child_at_index(newAppIcon, currentPosition)
+ currentAppIcons.splice(currentPosition, 0, newAppIcon)
+
+ // Skip animations on first run when adding the initial set
+ // of items, to avoid all items zooming in at once
+ newAppIcon.show(this._shownInitially)
+ }
+
+ ++currentPosition
+ }
+ }
+
+ this._adjustIconSize()
+
+ // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744
+ // Without it, StBoxLayout may use a stale size cache
+ this._box.queue_relayout()
+
+ // This is required for icon reordering when the scrollview is used.
+ this._updateAppIcons()
+
+ // This will update the size, and the corresponding number for each icon
+ this._updateHotkeysNumberOverlay()
+
+ this._shownInitially = true
+ }
+
+ _getRunningApps() {
+ let windows = Utils.getAllMetaWindows()
+ let apps = []
+
+ for (let i = 0, l = windows.length; i < l; ++i) {
+ let app = tracker.get_window_app(windows[i])
+
+ if (app && apps.indexOf(app) < 0) {
+ apps.push(app)
+ }
+ }
+
+ return apps
+ }
+
+ _createAppInfos(apps, defaultWindows, defaultIsLauncher) {
+ if (this.allowSplitApps && !defaultIsLauncher) {
+ let separateApps = []
+
+ if (apps.length) {
+ let windows = AppIcons.getInterestingWindows(
+ null,
+ this.dtpPanel.monitor,
+ ).sort(sortWindowsCompareFunction)
+
+ windows.forEach((w) => {
+ let windowApp = tracker.get_window_app(w)
+
+ if (apps.indexOf(windowApp) >= 0)
+ separateApps.push({
+ app: windowApp,
+ isLauncher: false,
+ windows: [w],
+ })
+ })
+ }
+
+ return separateApps
+ }
+
+ return apps.map((app) => ({
+ app: app,
+ isLauncher: defaultIsLauncher || false,
+ windows:
+ defaultWindows ||
+ AppIcons.getInterestingWindows(app, this.dtpPanel.monitor).sort(
+ sortWindowsCompareFunction,
+ ),
+ }))
+ }
+
+ // Reset the displayed apps icon to mantain the correct order
+ resetAppIcons(geometryChange) {
+ let children = this._getTaskbarIcons(true)
+
+ for (let i = 0; i < children.length; i++) {
+ let item = children[i]
+ item.destroy()
+ }
+
+ // to avoid ugly animations, just suppress them like when taskbar is first loaded.
+ this._shownInitially = false
+ this._redisplay()
+
+ if (geometryChange && this.dtpPanel.checkIfVertical()) {
+ this.previewMenu._updateClip()
+ }
+ }
+
+ _updateHotkeysNumberOverlay() {
+ let counter = 0
+
+ if (this.dtpPanel.isPrimary) hotkeyAppNumbers = {}
+
+ this._getAppIcons().forEach((icon) => {
+ if (
+ this.dtpPanel.isPrimary &&
+ (!hotkeyAppNumbers[icon.app] || this.allowSplitApps)
+ ) {
+ hotkeyAppNumbers[icon.app] = ++counter
+ }
+
+ let label = hotkeyAppNumbers[icon.app]
+
+ if (label <= 10) {
+ icon.setHotkeysNumberOverlayLabel(label == 10 ? 0 : label)
+ } else {
+ // No overlay after 10
+ icon.setHotkeysNumberOverlayLabel(-1)
+ }
+ })
+
+ if (
+ SETTINGS.get_boolean('hot-keys') &&
+ SETTINGS.get_string('hotkeys-overlay-combo') === 'ALWAYS'
+ )
+ this.toggleHotkeysNumberOverlay(true)
+ }
+
+ toggleHotkeysNumberOverlay(activate) {
+ let appIcons = this._getAppIcons()
+ appIcons.forEach(function (icon) {
+ icon.toggleHotkeysNumberOverlay(
+ activate ? SETTINGS.get_string('hotkeys-overlay-combo') : false,
+ )
+ })
+ }
+
+ _clearEmptyDropTarget() {
+ if (this._emptyDropTarget) {
+ this._emptyDropTarget.animateOutAndDestroy()
+ this._emptyDropTarget = null
+ }
+ }
+
+ handleDragOver(source, actor, x, y) {
+ if (source == Main.xdndHandler) return DND.DragMotionResult.CONTINUE
+
+ // Don't allow favoriting of transient apps
+ if (source.app == null || source.app.is_window_backed())
+ return DND.DragMotionResult.NO_DROP
+
+ if (!this._settings.is_writable('favorite-apps'))
+ return DND.DragMotionResult.NO_DROP
+
+ let isVertical = this.dtpPanel.checkIfVertical()
+
+ if (!this._box.contains(source) && !source._dashItemContainer) {
+ //not an appIcon of the taskbar, probably from the applications view
+ source._dashItemContainer = new DragPlaceholderItem(
+ source,
+ this.iconSize,
+ isVertical,
+ )
+ this._box.insert_child_above(source._dashItemContainer, null)
+ }
+
+ let sizeProp = isVertical ? 'height' : 'width'
+ let posProp = isVertical ? 'y' : 'x'
+ let pos = isVertical ? y : x
+
+ let currentAppIcons = this._getAppIcons()
+ let sourceIndex = currentAppIcons.indexOf(source)
+ let hoveredIndex = Utils.findIndex(
+ currentAppIcons,
+ (appIcon) =>
+ pos >= appIcon._dashItemContainer[posProp] &&
+ pos <=
+ appIcon._dashItemContainer[posProp] +
+ appIcon._dashItemContainer[sizeProp],
+ )
+
+ if (!this._dragInfo) {
+ this._dragInfo = [sourceIndex, source]
+ }
+
+ if (hoveredIndex >= 0) {
+ let isLeft =
+ pos <
+ currentAppIcons[hoveredIndex]._dashItemContainer[posProp] +
+ currentAppIcons[hoveredIndex]._dashItemContainer[sizeProp] * 0.5
+ let prevIcon = currentAppIcons[hoveredIndex - 1]
+ let nextIcon = currentAppIcons[hoveredIndex + 1]
+
+ // Don't allow positioning before or after self and between icons of same app if ungrouped and showing favorites
+ if (
+ !(
+ hoveredIndex === sourceIndex ||
+ (isLeft && hoveredIndex - 1 == sourceIndex) ||
+ (!this.allowSplitApps &&
+ isLeft &&
+ hoveredIndex - 1 >= 0 &&
+ source.app != prevIcon.app &&
+ prevIcon.app == currentAppIcons[hoveredIndex].app) ||
+ (!isLeft && hoveredIndex + 1 == sourceIndex) ||
+ (!this.allowSplitApps &&
+ !isLeft &&
+ hoveredIndex + 1 < currentAppIcons.length &&
+ source.app != nextIcon.app &&
+ nextIcon.app == currentAppIcons[hoveredIndex].app)
+ )
+ ) {
+ this._box.set_child_at_index(source._dashItemContainer, hoveredIndex)
+
+ // Ensure the next and previous icon are visible when moving the icon
+ // (I assume there's room for both of them)
+ if (hoveredIndex > 1)
+ Utils.ensureActorVisibleInScrollView(
+ this._scrollView,
+ this._box.get_children()[hoveredIndex - 1],
+ this._scrollView._dtpFadeSize,
+ )
+ if (hoveredIndex < this._box.get_children().length - 1)
+ Utils.ensureActorVisibleInScrollView(
+ this._scrollView,
+ this._box.get_children()[hoveredIndex + 1],
+ this._scrollView._dtpFadeSize,
+ )
+ }
+ }
+
+ return this._dragInfo[0] !== sourceIndex
+ ? DND.DragMotionResult.MOVE_DROP
+ : DND.DragMotionResult.CONTINUE
+ }
+
+ // Draggable target interface
+ acceptDrop(source) {
+ // Don't allow favoriting of transient apps
+ if (
+ !this._dragInfo ||
+ !source.app ||
+ source.app.is_window_backed() ||
+ !this._settings.is_writable('favorite-apps')
+ ) {
+ return false
+ }
+
+ let appIcons = this._getAppIcons()
+ let sourceIndex = appIcons.indexOf(source)
+ let usingLaunchers = !this.isGroupApps && this.usingLaunchers
+
+ // dragging the icon to its original position
+ if (this._dragInfo[0] === sourceIndex) {
+ return true
+ }
+
+ let appFavorites = AppFavorites.getAppFavorites()
+ let sourceAppId = source.app.get_id()
+ let appIsFavorite =
+ this.showFavorites && appFavorites.isFavorite(sourceAppId)
+ let replacingIndex =
+ sourceIndex + (sourceIndex > this._dragInfo[0] ? -1 : 1)
+ let favoriteIndex =
+ replacingIndex >= 0
+ ? appFavorites.getFavorites().indexOf(appIcons[replacingIndex].app)
+ : 0
+ let sameApps = this.allowSplitApps
+ ? []
+ : appIcons.filter((a) => a != source && a.app == source.app)
+ let favoritesCount = 0
+ let position = 0
+ let interestingWindows = {}
+ let getAppWindows = (app) => {
+ if (!interestingWindows[app]) {
+ interestingWindows[app] = AppIcons.getInterestingWindows(
+ app,
+ this.dtpPanel.monitor,
+ )
+ }
+
+ let appWindows = interestingWindows[app] //prevents "reference to undefined property Symbol.toPrimitive" warning
+ return appWindows
+ }
+
+ if (
+ sameApps.length &&
+ (!appIcons[sourceIndex - 1] ||
+ appIcons[sourceIndex - 1].app !== source.app) &&
+ (!appIcons[sourceIndex + 1] ||
+ appIcons[sourceIndex + 1].app !== source.app)
+ ) {
+ appIcons.splice(appIcons.indexOf(sameApps[0]), sameApps.length)
+ Array.prototype.splice.apply(
+ appIcons,
+ [sourceIndex + 1, 0].concat(sameApps),
+ )
+ }
+
+ for (let i = 0, l = appIcons.length; i < l; ++i) {
+ let windows = []
+
+ if (!usingLaunchers || (!source.isLauncher && !appIcons[i].isLauncher)) {
+ windows = appIcons[i].window
+ ? [appIcons[i].window]
+ : getAppWindows(appIcons[i].app)
+ }
+
+ windows.forEach((w) => (w._dtpPosition = position++))
+
+ if (
+ this.showFavorites &&
+ ((usingLaunchers && appIcons[i].isLauncher) ||
+ (!usingLaunchers &&
+ appFavorites.isFavorite(appIcons[i].app.get_id())))
+ ) {
+ ++favoritesCount
+ }
+ }
+
+ if (sourceIndex < favoritesCount) {
+ if (appIsFavorite) {
+ appFavorites.moveFavoriteToPos(sourceAppId, favoriteIndex)
+ } else {
+ appFavorites.addFavoriteAtPos(sourceAppId, favoriteIndex)
+ }
+ } else if (
+ appIsFavorite &&
+ this.showFavorites &&
+ (!usingLaunchers || source.isLauncher)
+ ) {
+ appFavorites.removeFavorite(sourceAppId)
+ }
+
+ appFavorites.emit('changed')
+
+ return true
+ }
+
+ _onShowAppsButtonToggled() {
+ // Sync the status of the default appButtons. Only if the two statuses are
+ // different, that means the user interacted with the extension provided
+ // application button, cutomize the behaviour. Otherwise the shell has changed the
+ // status (due to the _syncShowAppsButtonToggled function below) and it
+ // has already performed the desired action.
+ let selector = SearchController
+
+ if (
+ selector._showAppsButton &&
+ selector._showAppsButton.checked !== this.showAppsButton.checked
+ ) {
+ // find visible view
+
+ if (this.showAppsButton.checked) {
+ //override escape key to return to the desktop when entering the overview using the showapps button
+ SearchController._onStageKeyPress = function (actor, event) {
+ if (
+ Main.modalCount == 1 &&
+ event.get_key_symbol() === Clutter.KEY_Escape
+ ) {
+ this._searchActive ? this.reset() : Main.overview.hide()
+
+ return Clutter.EVENT_STOP
+ }
+
+ return Object.getPrototypeOf(this)._onStageKeyPress.call(
+ this,
+ actor,
+ event,
+ )
+ }
+
+ let overviewHiddenId = Main.overview.connect('hidden', () => {
+ Main.overview.disconnect(overviewHiddenId)
+ delete SearchController._onStageKeyPress
+ })
+
+ // force exiting overview if needed
+ if (!Main.overview._shown) {
+ this.forcedOverview = true
+ }
+
+ //temporarily use as primary the monitor on which the showapps btn was clicked, this is
+ //restored by the panel when exiting the overview
+ this.dtpPanel.panelManager.setFocusedMonitor(this.dtpPanel.monitor)
+
+ // Finally show the overview
+ selector._showAppsButton.checked = true
+ Main.overview.show(2 /*APP_GRID*/)
+ } else {
+ if (this.forcedOverview) {
+ // force exiting overview if needed
+ Main.overview.hide()
+ } else {
+ selector._showAppsButton.checked = false
+ }
+
+ this.forcedOverview = false
+ }
+ }
+ }
+
+ _syncShowAppsButtonToggled() {
+ let status = SearchController._showAppsButton.checked
+ if (this.showAppsButton.checked !== status)
+ this.showAppsButton.checked = status
+ }
+
+ showShowAppsButton() {
+ this.showAppsButton.visible = true
+ this.showAppsButton.set_width(-1)
+ this.showAppsButton.set_height(-1)
+ }
+
+ popupFocusedAppSecondaryMenu() {
+ let appIcons = this._getAppIcons()
+
+ for (let i in appIcons) {
+ if (appIcons[i].app == tracker.focus_app) {
+ let appIcon = appIcons[i]
+ if (appIcon._menu && appIcon._menu.isOpen) appIcon._menu.close()
+ else appIcon.popupMenu()
+
+ appIcon.sync_hover()
+ break
+ }
+ }
+ }
+}
+
+export const TaskbarItemContainer = GObject.registerClass(
+ {},
+ class TaskbarItemContainer extends Dash.DashItemContainer {
+ _init() {
+ super._init()
+ this.x_expand = this.y_expand = false
+ }
+
+ vfunc_allocate(box) {
+ if (this.child == null) return
+
+ this.set_allocation(box)
+
+ let availWidth = box.x2 - box.x1
+ let availHeight = box.y2 - box.y1
+ let [, , natChildWidth, natChildHeight] = this.child.get_preferred_size()
+ let [childScaleX, childScaleY] = this.child.get_scale()
+
+ let childWidth = Math.min(natChildWidth * childScaleX, availWidth)
+ let childHeight = Math.min(natChildHeight * childScaleY, availHeight)
+ let childBox = new Clutter.ActorBox()
+
+ childBox.x1 = (availWidth - childWidth) / 2
+ childBox.y1 = (availHeight - childHeight) / 2
+ childBox.x2 = childBox.x1 + childWidth
+ childBox.y2 = childBox.y1 + childHeight
+
+ this.child.allocate(childBox)
+ }
+
+ // In case appIcon is removed from the taskbar while it is hovered,
+ // restore opacity before dashItemContainer.animateOutAndDestroy does the destroy animation.
+ animateOutAndDestroy() {
+ if (this._raisedClone) {
+ this._raisedClone.source.opacity = 255
+ this._raisedClone.destroy()
+ }
+
+ super.animateOutAndDestroy()
+ }
+ },
+)
+
+const DragPlaceholderItem = GObject.registerClass(
+ {},
+ class DragPlaceholderItem extends St.Widget {
+ _init(appIcon, iconSize, isVertical) {
+ super._init({
+ style: AppIcons.getIconContainerStyle(isVertical),
+ layout_manager: new Clutter.BinLayout(),
+ })
+
+ this.child = { _delegate: appIcon }
+
+ this._clone = new Clutter.Clone({
+ source: appIcon.icon._iconBin,
+ width: iconSize,
+ height: iconSize,
+ })
+
+ this.add_child(this._clone)
+ }
+
+ destroy() {
+ this._clone.destroy()
+ super.destroy()
+ }
+ },
+)
+
+export function getAppStableSequence(app, monitor) {
+ let windows = AppIcons.getInterestingWindows(app, monitor)
+
+ return windows.reduce((prevWindow, window) => {
+ return Math.min(prevWindow, getWindowStableSequence(window))
+ }, Infinity)
+}
+
+export function sortWindowsCompareFunction(windowA, windowB) {
+ return getWindowStableSequence(windowA) - getWindowStableSequence(windowB)
+}
+
+export function getWindowStableSequence(window) {
+ return '_dtpPosition' in window
+ ? window._dtpPosition
+ : window.get_stable_sequence()
+}
diff --git a/src/transparency.js b/src/transparency.js
new file mode 100644
index 0000000..a7a6361
--- /dev/null
+++ b/src/transparency.js
@@ -0,0 +1,199 @@
+/*
+ * 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 .
+ *
+ * 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._setBackground()
+ }
+
+ _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-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.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[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._setBackground()
+ this._setActorStyle()
+ }
+
+ _updateAlphaAndSet() {
+ this._updateAlpha()
+ this._setBackground()
+ }
+
+ _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
+ }
+ }
+
+ _setBackground() {
+ this.currentBackgroundColor = Utils.getrgbaColor(
+ this.backgroundColorRgb,
+ this.alpha,
+ )
+
+ let transition = 'transition-duration: 300ms;'
+
+ this._dtpPanel.set_style(
+ 'background-color: ' + this.currentBackgroundColor + transition,
+ )
+ }
+
+ _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) {
+ console.log(error)
+ }
+
+ return bg
+ }
+}
diff --git a/src/utils.js b/src/utils.js
new file mode 100644
index 0000000..d9494a9
--- /dev/null
+++ b/src/utils.js
@@ -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 .
+ *
+ *
+ * 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()
+}
diff --git a/src/windowPreview.js b/src/windowPreview.js
new file mode 100644
index 0000000..170c267
--- /dev/null
+++ b/src/windowPreview.js
@@ -0,0 +1,1362 @@
+/*
+ * 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 .
+ *
+ * Credits:
+ * This file is based on code from the Dash to Panel extensionq
+ */
+
+import GObject from 'gi://GObject'
+import Clutter from 'gi://Clutter'
+import GLib from 'gi://GLib'
+import Graphene from 'gi://Graphene'
+import * as Main from 'resource:///org/gnome/shell/ui/main.js'
+import Meta from 'gi://Meta'
+import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'
+import St from 'gi://St'
+
+import * as Taskbar from './taskbar.js'
+import * as Utils from './utils.js'
+import { SETTINGS } from './extension.js'
+import { gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js'
+
+//timeout intervals
+const ENSURE_VISIBLE_MS = 200
+
+//timeout names
+const T1 = 'openMenuTimeout'
+const T2 = 'closeMenuTimeout'
+const T3 = 'peekTimeout'
+const T4 = 'ensureVisibleTimeout'
+
+const MAX_TRANSLATION = 40
+const HEADER_HEIGHT = 38
+const MAX_CLOSE_BUTTON_SIZE = 30
+const MIN_DIMENSION = 100
+const FOCUSED_COLOR_OFFSET = 24
+const FADE_SIZE = 36
+const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'
+const MARGIN_SIZE = 8
+
+const SHOW_WINDOW_PREVIEWS_TIMEOUT = 400
+const LEAVE_TIMEOUT = 250
+const WINDOW_PREVIEW_ANIMATION_TIME = 200
+const WINDOW_PREVIEW_ASPECT_RATIO_X = 16
+const WINDOW_PREVIEW_FIXED_X = false
+const WINDOW_PREVIEW_ASPECT_RATIO_Y = 9
+const WINDOW_PREVIEW_FIXED_Y = true
+const WINDOW_PREVIEW_PADDING = 8
+const ENTER_PEEK_MODE_TIMEOUT = 500
+const PEEK_MODE_OPACITY = 40
+
+let headerHeight = 0
+let alphaBg = 0
+let isLeftButtons = false
+let isTopHeader = true
+let scaleFactor = 1
+let animationTime = 0
+let aspectRatio = {}
+
+export const PreviewMenu = GObject.registerClass(
+ {
+ Signals: { 'open-state-changed': {} },
+ },
+ class PreviewMenu extends St.Widget {
+ _init(panel) {
+ super._init({ layout_manager: new Clutter.BinLayout() })
+
+ let geom = panel.geom
+ this.panel = panel
+ this.currentAppIcon = null
+ this._focusedPreview = null
+ this._peekedWindow = null
+ this.allowCloseWindow = true
+ this.peekInitialWorkspaceIndex = -1
+ this.opened = false
+ this.isVertical =
+ geom.position == St.Side.LEFT || geom.position == St.Side.RIGHT
+ this._translationProp = 'translation_' + (this.isVertical ? 'x' : 'y')
+ this._translationDirection =
+ geom.position == St.Side.TOP || geom.position == St.Side.LEFT ? -1 : 1
+ this._translationOffset =
+ Math.min(panel.geom.innerSize, MAX_TRANSLATION) *
+ this._translationDirection
+
+ this.menu = new St.Widget({
+ name: 'preview-menu',
+ style_class: 'dash-label',
+ layout_manager: new Clutter.BinLayout(),
+ reactive: true,
+ track_hover: true,
+ x_expand: true,
+ y_expand: true,
+ x_align:
+ Clutter.ActorAlign[geom.position != St.Side.RIGHT ? 'START' : 'END'],
+ y_align:
+ Clutter.ActorAlign[geom.position != St.Side.BOTTOM ? 'START' : 'END'],
+ })
+ this._box = Utils.createBoxLayout({ vertical: this.isVertical })
+ this._scrollView = new St.ScrollView({
+ name: 'zorintaskbarPreviewScrollview',
+ hscrollbar_policy: St.PolicyType.NEVER,
+ vscrollbar_policy: St.PolicyType.NEVER,
+ enable_mouse_scrolling: true,
+ y_expand: !this.isVertical,
+ })
+
+ this._scrollView.add_child(this._box)
+ this.menu.add_child(this._scrollView)
+ this.add_child(this.menu)
+ }
+
+ enable() {
+ this._timeoutsHandler = new Utils.TimeoutsHandler()
+ this._signalsHandler = new Utils.GlobalSignalsHandler()
+
+ Main.layoutManager.addChrome(this, { affectsInputRegion: false })
+ Main.layoutManager.trackChrome(this.menu, { affectsInputRegion: true })
+
+ this._resetHiddenState()
+ this._refreshGlobals()
+ this._updateClip()
+ this.menu.set_position(1, 1)
+
+ this._signalsHandler.add(
+ [this.menu, 'notify::hover', () => this._onHoverChanged()],
+ [this._scrollView, 'scroll-event', this._onScrollEvent.bind(this)],
+ [this.panel.panelBox, 'style-changed', () => this._updateClip()],
+ [
+ Utils.DisplayWrapper.getScreen(),
+ 'in-fullscreen-changed',
+ () => {
+ if (
+ global.display.focus_window &&
+ global.display.focus_window.is_fullscreen()
+ ) {
+ this.close(true)
+ }
+ },
+ ],
+ [
+ SETTINGS,
+ [
+ 'changed::panel-sizes',
+ 'changed::panel-margin',
+ 'changed::window-preview-size'
+ ],
+ () => {
+ this._refreshGlobals()
+ this._updateClip()
+ },
+ ],
+ )
+ }
+
+ disable() {
+ this._timeoutsHandler.destroy()
+ this._signalsHandler.destroy()
+
+ this.close(true)
+
+ Main.layoutManager.untrackChrome(this.menu)
+ Main.layoutManager.removeChrome(this)
+ }
+
+ requestOpen(appIcon) {
+ let timeout = SHOW_WINDOW_PREVIEWS_TIMEOUT
+
+ if (this.opened) {
+ timeout = Math.min(100, timeout)
+ }
+
+ this._endOpenCloseTimeouts()
+ this._timeoutsHandler.add([T1, timeout, () => this.open(appIcon)])
+ }
+
+ requestClose() {
+ this._endOpenCloseTimeouts()
+ this._addCloseTimeout()
+ }
+
+ open(appIcon, preventCloseWindow) {
+ if (this.currentAppIcon != appIcon) {
+ this.currentAppIcon = appIcon
+ this.allowCloseWindow = !preventCloseWindow
+
+ if (!this.opened) {
+ this._refreshGlobals()
+
+ this.set_height(this.clipHeight)
+ this.show()
+
+ setStyle(
+ this.menu,
+ 'padding: 0; margin: 0; border: none; background-image: none;',
+ )
+ }
+
+ this._mergeWindows(appIcon)
+ this._updatePosition()
+ this._animateOpenOrClose(true)
+
+ this._setReactive(true)
+ this._setOpenedState(true)
+ }
+ }
+
+ close(immediate) {
+ this._endOpenCloseTimeouts()
+ this._removeFocus()
+ this._endPeek()
+
+ if (immediate) {
+ Utils.stopAnimations(this.menu)
+ this._resetHiddenState()
+ } else {
+ this._animateOpenOrClose(false, () => this._resetHiddenState())
+ }
+
+ this._setReactive(false)
+ this.currentAppIcon = null
+ }
+
+ update(appIcon, windows) {
+ if (this.currentAppIcon == appIcon) {
+ if (windows && !windows.length) {
+ this.close()
+ } else {
+ this._addAndRemoveWindows(windows)
+ this._updatePosition()
+ }
+ }
+ }
+
+ updatePosition() {
+ this._updatePosition()
+ }
+
+ focusNext() {
+ let previews = this._box.get_children()
+ let currentIndex = this._focusedPreview
+ ? previews.indexOf(this._focusedPreview)
+ : -1
+ let nextIndex = currentIndex + 1
+
+ nextIndex = previews[nextIndex] ? nextIndex : 0
+
+ if (previews[nextIndex]) {
+ this._removeFocus()
+ previews[nextIndex].setFocus(true)
+ this._focusedPreview = previews[nextIndex]
+ }
+
+ return nextIndex
+ }
+
+ activateFocused() {
+ if (this.opened && this._focusedPreview) {
+ this._focusedPreview.activate()
+ }
+ }
+
+ requestPeek(window) {
+ this._timeoutsHandler.remove(T3)
+
+ if (SETTINGS.get_boolean('peek-mode')) {
+ if (this.peekInitialWorkspaceIndex < 0) {
+ this._timeoutsHandler.add([
+ T3,
+ ENTER_PEEK_MODE_TIMEOUT,
+ () => this._peek(window),
+ ])
+ } else {
+ this._peek(window)
+ }
+ }
+ }
+
+ endPeekHere() {
+ this._endPeek(true)
+ }
+
+ ensureVisible(preview) {
+ let [, upper, pageSize] = this._getScrollAdjustmentValues()
+
+ if (upper > pageSize) {
+ this._timeoutsHandler.add([
+ T4,
+ ENSURE_VISIBLE_MS,
+ () =>
+ Utils.ensureActorVisibleInScrollView(
+ this._scrollView,
+ preview,
+ MIN_DIMENSION,
+ () => this._updateScrollFade(),
+ ),
+ ])
+ }
+ }
+
+ getCurrentAppIcon() {
+ return this.currentAppIcon
+ }
+
+ _setReactive(reactive) {
+ this._box.get_children().forEach((c) => (c.reactive = reactive))
+ this.menu.reactive = reactive
+ }
+
+ _setOpenedState(opened) {
+ this.opened = opened
+ this.emit('open-state-changed')
+ }
+
+ _resetHiddenState() {
+ this.hide()
+ this.set_height(0)
+ this._setOpenedState(false)
+ this.menu.opacity = 0
+ this.menu[this._translationProp] = this._translationOffset
+ this._box.get_children().forEach((c) => c.destroy())
+ }
+
+ _removeFocus() {
+ if (this._focusedPreview) {
+ this._focusedPreview.setFocus(false)
+ this._focusedPreview = null
+ }
+ }
+
+ _mergeWindows(appIcon, windows) {
+ windows =
+ windows ||
+ (appIcon.window
+ ? [appIcon.window]
+ : appIcon.getAppIconInterestingWindows())
+ windows.sort(Taskbar.sortWindowsCompareFunction)
+
+ let currentPreviews = this._box.get_children()
+ let l = Math.max(windows.length, currentPreviews.length)
+
+ for (let i = 0; i < l; ++i) {
+ if (currentPreviews[i] && windows[i]) {
+ currentPreviews[i].assignWindow(windows[i], this.opened)
+ } else if (!currentPreviews[i]) {
+ this._addNewPreview(windows[i])
+ } else if (!windows[i]) {
+ currentPreviews[i][!this.opened ? 'destroy' : 'animateOut']()
+ }
+ }
+ }
+
+ _addAndRemoveWindows(windows) {
+ let currentPreviews = this._box.get_children()
+
+ windows.sort(Taskbar.sortWindowsCompareFunction)
+
+ for (let i = 0, l = windows.length; i < l; ++i) {
+ let currentIndex = Utils.findIndex(
+ currentPreviews,
+ (c) => c.window == windows[i],
+ )
+
+ if (currentIndex < 0) {
+ this._addNewPreview(windows[i])
+ } else {
+ currentPreviews[currentIndex].assignWindow(windows[i])
+ currentPreviews.splice(currentIndex, 1)
+
+ if (this._peekedWindow && this._peekedWindow == windows[i]) {
+ this.requestPeek(windows[i])
+ }
+ }
+ }
+
+ currentPreviews.forEach((c) => c.animateOut())
+ }
+
+ _addNewPreview(window) {
+ let preview = new Preview(this)
+
+ this._box.add_child(preview)
+ preview.adjustOnStage()
+ preview.assignWindow(window, this.opened)
+ }
+
+ _addCloseTimeout() {
+ this._timeoutsHandler.add([
+ T2,
+ LEAVE_TIMEOUT,
+ () => this.close(),
+ ])
+ }
+
+ _onHoverChanged() {
+ this._endOpenCloseTimeouts()
+
+ if (this.currentAppIcon) {
+ this.menu.sync_hover() // See dash-to-panel issue #2169
+
+ if (!this.menu.hover) {
+ this._addCloseTimeout()
+ this._endPeek()
+ }
+ }
+ }
+
+ _onScrollEvent(actor, event) {
+ if (!event.is_pointer_emulated()) {
+ let vOrh = this.isVertical ? 'v' : 'h'
+ let adjustment =
+ this._scrollView['get_' + vOrh + 'scroll_bar']().get_adjustment()
+ let increment = adjustment.step_increment
+ let delta = increment
+
+ switch (event.get_scroll_direction()) {
+ case Clutter.ScrollDirection.UP:
+ delta = -increment
+ break
+ case Clutter.ScrollDirection.SMOOTH: {
+ let [dx, dy] = event.get_scroll_delta()
+ delta = dy * increment
+ delta += dx * increment
+ break
+ }
+ }
+
+ adjustment.set_value(adjustment.get_value() + delta)
+ this._updateScrollFade()
+ }
+
+ return Clutter.EVENT_STOP
+ }
+
+ _endOpenCloseTimeouts() {
+ this._timeoutsHandler.remove(T1)
+ this._timeoutsHandler.remove(T2)
+ this._timeoutsHandler.remove(T4)
+ }
+
+ _refreshGlobals() {
+ isLeftButtons =
+ Meta.prefs_get_button_layout().left_buttons.indexOf(
+ Meta.ButtonFunction.CLOSE,
+ ) >= 0
+ scaleFactor = Utils.getScaleFactor()
+ headerHeight = HEADER_HEIGHT * scaleFactor
+ animationTime = WINDOW_PREVIEW_ANIMATION_TIME * 0.001
+ aspectRatio.x = {
+ size: WINDOW_PREVIEW_ASPECT_RATIO_X,
+ fixed: WINDOW_PREVIEW_FIXED_X,
+ }
+ aspectRatio.y = {
+ size: WINDOW_PREVIEW_ASPECT_RATIO_Y,
+ fixed: WINDOW_PREVIEW_FIXED_Y,
+ }
+
+ alphaBg = this._getThemeBackground().alpha
+ }
+
+ _updateClip() {
+ let x, y, w
+ let geom = this.panel.getGeometry()
+ let panelSize = geom.outerSize - geom.fixedPadding
+ let panelBoxTheme = this.panel.panelBox.get_theme_node()
+ let previewSize =
+ (SETTINGS.get_int('window-preview-size') +
+ WINDOW_PREVIEW_PADDING * 2) *
+ scaleFactor
+
+ if (this.isVertical) {
+ w = previewSize
+ this.clipHeight = this.panel.monitor.height
+ y = this.panel.monitor.y
+ } else {
+ w = this.panel.monitor.width
+ this.clipHeight = previewSize + headerHeight
+ x = this.panel.monitor.x
+ }
+
+ if (geom.position == St.Side.LEFT) {
+ x =
+ this.panel.monitor.x +
+ panelSize -
+ panelBoxTheme.get_padding(St.Side.RIGHT) +
+ MARGIN_SIZE
+ } else if (geom.position == St.Side.RIGHT) {
+ x =
+ this.panel.monitor.x +
+ this.panel.monitor.width -
+ (panelSize + previewSize) +
+ panelBoxTheme.get_padding(St.Side.LEFT) -
+ MARGIN_SIZE
+ } else if (geom.position == St.Side.TOP) {
+ y = geom.y + panelSize - panelBoxTheme.get_padding(St.Side.BOTTOM) + MARGIN_SIZE
+ } else {
+ //St.Side.BOTTOM
+ y =
+ this.panel.monitor.y +
+ this.panel.monitor.height -
+ (panelSize -
+ panelBoxTheme.get_padding(St.Side.TOP) +
+ previewSize +
+ headerHeight) -
+ MARGIN_SIZE
+ }
+
+ Utils.setClip(this, x, y, w, this.clipHeight)
+ }
+
+ _updatePosition() {
+ let sourceNode = this.currentAppIcon.get_theme_node()
+ let sourceContentBox = sourceNode.get_content_box(
+ this.currentAppIcon.get_allocation_box(),
+ )
+ let sourceAllocation = Utils.getTransformedAllocation(this.currentAppIcon)
+ let [previewsWidth, previewsHeight] = this._getPreviewsSize()
+ let appIconMargin = Taskbar.APPICON_MARGIN / scaleFactor
+ let x = 0,
+ y = 0
+
+ previewsWidth = Math.min(previewsWidth, this.panel.monitor.width)
+ previewsHeight = Math.min(previewsHeight, this.panel.monitor.height)
+ this._updateScrollFade(
+ previewsWidth < this.panel.monitor.width &&
+ previewsHeight < this.panel.monitor.height,
+ )
+
+ if (this.isVertical) {
+ y =
+ sourceAllocation.y1 +
+ appIconMargin -
+ this.panel.monitor.y +
+ (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * 0.5
+ y = Math.max(y, 0)
+ y = Math.min(y, this.panel.monitor.height - previewsHeight)
+ } else {
+ x =
+ sourceAllocation.x1 +
+ appIconMargin -
+ this.panel.monitor.x +
+ (sourceContentBox.x2 - sourceContentBox.x1 - previewsWidth) * 0.5
+ x = Math.max(x, 0)
+ x = Math.min(x, this.panel.monitor.width - previewsWidth)
+ }
+
+ if (!this.opened) {
+ this.menu.set_position(x, y)
+ this.menu.set_size(previewsWidth, previewsHeight)
+ } else {
+ Utils.animate(
+ this.menu,
+ getTweenOpts({
+ x: x,
+ y: y,
+ width: previewsWidth,
+ height: previewsHeight,
+ }),
+ )
+ }
+ }
+
+ _updateScrollFade(remove) {
+ let [value, upper, pageSize] = this._getScrollAdjustmentValues()
+ let needsFade = Math.round(upper) > Math.round(pageSize)
+ let fadeWidgets = this.menu
+ .get_children()
+ .filter((c) => c != this._scrollView)
+
+ if (!remove && needsFade) {
+ if (!fadeWidgets.length) {
+ fadeWidgets.push(this._getFadeWidget())
+ fadeWidgets.push(this._getFadeWidget(true))
+
+ this.menu.add_child(fadeWidgets[0])
+ this.menu.add_child(fadeWidgets[1])
+ }
+
+ fadeWidgets[0].visible = value > 0
+ fadeWidgets[1].visible = value + pageSize < upper
+ } else if (remove || (!needsFade && fadeWidgets.length)) {
+ fadeWidgets.forEach((fw) => fw.destroy())
+ }
+ }
+
+ _getScrollAdjustmentValues() {
+ let [value, , upper, , , pageSize] =
+ this._scrollView[
+ (this.isVertical ? 'v' : 'h') + 'adjustment'
+ ].get_values()
+
+ return [value, upper, pageSize]
+ }
+
+ _getFadeWidget(end) {
+ let x = 0,
+ y = 0
+ let startBg = Utils.getrgbaColor(
+ this._getThemeBackground(),
+ Math.min(alphaBg + 0.1, 1),
+ )
+ let endBg = Utils.getrgbaColor(
+ this._getThemeBackground(),
+ 0,
+ )
+ let fadeStyle =
+ 'background-gradient-start:' +
+ startBg +
+ 'background-gradient-end:' +
+ endBg +
+ 'background-gradient-direction:' +
+ this.panel.getOrientation()
+
+ if (this.isVertical) {
+ y = end ? this.panel.monitor.height - FADE_SIZE : 0
+ } else {
+ x = end ? this.panel.monitor.width - FADE_SIZE : 0
+ }
+
+ let fadeWidget = new St.Widget({
+ reactive: false,
+ pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
+ rotation_angle_z: end ? 180 : 0,
+ style: fadeStyle,
+ x: x,
+ y: y,
+ width: this.isVertical ? this.width : FADE_SIZE,
+ height: this.isVertical ? FADE_SIZE : this.height,
+ })
+
+ return fadeWidget
+ }
+
+ _getPreviewsSize() {
+ let previewsWidth = 0
+ let previewsHeight = 0
+
+ this._box.get_children().forEach((c) => {
+ if (!c.animatingOut) {
+ let [width, height] = c.getSize()
+
+ if (this.isVertical) {
+ previewsWidth = Math.max(width, previewsWidth)
+ previewsHeight += height
+ } else {
+ previewsWidth += width
+ previewsHeight = Math.max(height, previewsHeight)
+ }
+ }
+ })
+
+ return [previewsWidth, previewsHeight]
+ }
+
+ _getThemeBackground(reload) {
+ if (reload || !this._themeBackground) {
+ let fakeTooltip = new St.Bin({ style_class: 'dash-label' })
+ Main.uiGroup.add_child(fakeTooltip)
+ let fakeTheme = fakeTooltip.get_theme_node()
+ this._themeBackground = fakeTheme.get_background_color()
+ Main.uiGroup.remove_child(fakeTooltip)
+ }
+
+ return this._themeBackground
+ }
+
+ _animateOpenOrClose(show, onComplete) {
+ let isTranslationAnimation = this.menu[this._translationProp] != 0
+ let tweenOpts = {
+ opacity: show ? 255 : 0,
+ transition: show ? 'easeInOutQuad' : 'easeInCubic',
+ onComplete: () => {
+ if (isTranslationAnimation) {
+ Main.layoutManager._queueUpdateRegions()
+ }
+
+ ;(onComplete || (() => {}))()
+ },
+ }
+
+ tweenOpts[this._translationProp] = show
+ ? this._translationDirection
+ : this._translationOffset
+
+ Utils.animate(this.menu, getTweenOpts(tweenOpts))
+ }
+
+ _peek(window) {
+ let currentWorkspace = Utils.getCurrentWorkspace()
+ let isAppSpread = !Main.sessionMode.hasWorkspaces
+ let windowWorkspace = isAppSpread
+ ? currentWorkspace
+ : window.get_workspace()
+ let focusWindow = () =>
+ this._focusMetaWindow(PEEK_MODE_OPACITY, window)
+
+ this._restorePeekedWindowStack()
+
+ if (this._peekedWindow && windowWorkspace != currentWorkspace) {
+ currentWorkspace
+ .list_windows()
+ .forEach((mw) => this.animateWindowOpacity(mw, null, 255))
+ }
+
+ this._peekedWindow = window
+
+ if (currentWorkspace != windowWorkspace) {
+ this._switchToWorkspaceImmediate(windowWorkspace.index())
+ this._timeoutsHandler.add([T3, 100, focusWindow])
+ } else {
+ focusWindow()
+ }
+
+ if (this.peekInitialWorkspaceIndex < 0) {
+ this.peekInitialWorkspaceIndex = currentWorkspace.index()
+ }
+ }
+
+ _endPeek(stayHere) {
+ this._timeoutsHandler.remove(T3)
+
+ if (this._peekedWindow) {
+ let immediate =
+ !stayHere &&
+ this.peekInitialWorkspaceIndex != Utils.getCurrentWorkspace().index()
+
+ this._restorePeekedWindowStack()
+ this._focusMetaWindow(255, this._peekedWindow, immediate, true)
+ this._peekedWindow = null
+
+ if (!stayHere) {
+ this._switchToWorkspaceImmediate(this.peekInitialWorkspaceIndex)
+ }
+
+ this.peekInitialWorkspaceIndex = -1
+ }
+ }
+
+ _switchToWorkspaceImmediate(workspaceIndex) {
+ let workspace = Utils.getWorkspaceByIndex(workspaceIndex)
+ let shouldAnimate = Main.wm._shouldAnimate
+
+ if (
+ !workspace ||
+ (!workspace.list_windows().length &&
+ workspaceIndex < Utils.getWorkspaceCount() - 1)
+ ) {
+ workspace = Utils.getCurrentWorkspace()
+ }
+
+ Main.wm._shouldAnimate = () => false
+ workspace.activate(global.display.get_current_time_roundtrip())
+ Main.wm._shouldAnimate = shouldAnimate
+ }
+
+ _focusMetaWindow(dimOpacity, window, immediate, ignoreFocus) {
+ let isAppSpread = !Main.sessionMode.hasWorkspaces
+ let windowWorkspace = isAppSpread
+ ? Utils.getCurrentWorkspace()
+ : window.get_workspace()
+ let windows = isAppSpread
+ ? Utils.getAllMetaWindows()
+ : windowWorkspace.list_windows()
+
+ windows.forEach((mw) => {
+ let wa = mw.get_compositor_private()
+ let isFocused = !ignoreFocus && mw == window
+
+ if (wa) {
+ if (isFocused) {
+ mw[PEEK_INDEX_PROP] = wa.get_parent().get_children().indexOf(wa)
+ wa.get_parent().set_child_above_sibling(wa, null)
+ }
+
+ if (isFocused && mw.minimized) {
+ wa.show()
+ }
+
+ this.animateWindowOpacity(
+ mw,
+ wa,
+ isFocused ? 255 : dimOpacity,
+ immediate,
+ )
+ }
+ })
+ }
+
+ animateWindowOpacity(metaWindow, windowActor, opacity, immediate) {
+ windowActor = windowActor || metaWindow.get_compositor_private()
+
+ if (windowActor && !metaWindow.minimized) {
+ let tweenOpts = getTweenOpts({ opacity })
+
+ if (immediate && !metaWindow.is_on_all_workspaces()) {
+ tweenOpts.time = 0
+ }
+
+ Utils.animateWindowOpacity(windowActor, tweenOpts)
+ }
+ }
+
+ _restorePeekedWindowStack() {
+ let windowActor = this._peekedWindow
+ ? this._peekedWindow.get_compositor_private()
+ : null
+
+ if (windowActor) {
+ if (Object.hasOwn(this._peekedWindow, PEEK_INDEX_PROP)) {
+ windowActor
+ .get_parent()
+ .set_child_at_index(
+ windowActor,
+ this._peekedWindow[PEEK_INDEX_PROP],
+ )
+ delete this._peekedWindow[PEEK_INDEX_PROP]
+ }
+
+ if (this._peekedWindow.minimized) {
+ windowActor.hide()
+ }
+ }
+ }
+ },
+)
+
+export const Preview = GObject.registerClass(
+ {},
+ class Preview extends St.Widget {
+ _init(previewMenu) {
+ super._init({
+ style_class: 'preview-container',
+ reactive: true,
+ track_hover: true,
+ layout_manager: new Clutter.BinLayout(),
+ })
+
+ this.window = null
+ this._waitWindowId = 0
+ this._needsCloseButton = true
+ this.cloneWidth = this.cloneHeight = 0
+ this._previewMenu = previewMenu
+ this._padding = WINDOW_PREVIEW_PADDING * scaleFactor
+ this._previewDimensions = this._getPreviewDimensions()
+ this.animatingOut = false
+
+ let box = new St.Widget({
+ layout_manager: new Clutter.BoxLayout({
+ orientation: Clutter.Orientation.VERTICAL,
+ }),
+ y_expand: true,
+ })
+ let [previewBinWidth, previewBinHeight] = this._getBinSize()
+ let closeButton = new St.Button({
+ style_class: 'window-close',
+ accessible_name: 'Close window',
+ })
+
+ closeButton.add_child(new St.Icon({ icon_name: 'window-close-symbolic' }))
+
+ this._closeButtonBin = new St.Widget({
+ style_class: 'preview-close-btn-container',
+ layout_manager: new Clutter.BinLayout(),
+ opacity: 0,
+ x_expand: true,
+ y_expand: true,
+ x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'],
+ y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'],
+ })
+
+ this._closeButtonBin.add_child(closeButton)
+
+ this._previewBin = new St.Widget({
+ layout_manager: new Clutter.BinLayout(),
+ x_expand: true,
+ y_expand: true,
+ style: 'padding: ' + this._padding / scaleFactor + 'px;',
+ })
+
+ this._previewBin.set_size(previewBinWidth, previewBinHeight)
+
+ box.add_child(this._previewBin)
+
+ if (headerHeight) {
+ let headerBox = new St.Widget({
+ style_class: 'preview-header-box',
+ layout_manager: new Clutter.BoxLayout(),
+ x_expand: true,
+ y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'],
+ })
+ headerBox.set_size(headerHeight, headerHeight)
+
+ this._windowTitle = new St.Label({
+ y_align: Clutter.ActorAlign.CENTER,
+ x_expand: true,
+ })
+
+ headerBox.insert_child_at_index(
+ this._windowTitle,
+ isLeftButtons ? 1 : 2,
+ )
+
+ box.insert_child_at_index(headerBox, isTopHeader ? 0 : 1)
+ }
+
+ this.add_child(box)
+ this.add_child(this._closeButtonBin)
+
+ closeButton.connect('clicked', () => this._onCloseBtnClick())
+ this.connect('notify::hover', () => this._onHoverChanged())
+ this.connect('button-release-event', (actor, e) =>
+ this._onButtonReleaseEvent(e),
+ )
+ this.connect('destroy', () => this._onDestroy())
+ }
+
+ adjustOnStage() {
+ let closeButton = this._closeButtonBin.get_first_child()
+ let closeButtonHeight = closeButton.height
+ let maxCloseButtonSize = MAX_CLOSE_BUTTON_SIZE * scaleFactor
+ let closeButtonBorderRadius = ''
+
+ if (closeButtonHeight > maxCloseButtonSize) {
+ closeButtonHeight = maxCloseButtonSize
+ closeButton.set_size(closeButtonHeight, closeButtonHeight)
+ }
+
+ if (!headerHeight) {
+ closeButtonBorderRadius = 'border-radius: '
+
+ if (isTopHeader) {
+ closeButtonBorderRadius += isLeftButtons ? '0 0 8px 0;' : '0 0 0 8px;'
+ } else {
+ closeButtonBorderRadius += isLeftButtons ? '0 8px 0 0;' : '8px 0 0 0;'
+ }
+ }
+
+ setStyle(
+ this._closeButtonBin,
+ 'padding: ' +
+ (headerHeight
+ ? Math.round(
+ ((headerHeight - closeButtonHeight) * 0.5) / scaleFactor,
+ )
+ : 4) +
+ 'px;' +
+ closeButtonBorderRadius,
+ )
+ }
+
+ assignWindow(window, animateSize) {
+ if (this.window != window) {
+ let _assignWindowClone = () => {
+ if (window.get_compositor_private()) {
+ let cloneBin = this._getWindowCloneBin(window)
+
+ this._resizeClone(cloneBin, window)
+ this._addClone(cloneBin, animateSize)
+ this._previewMenu.updatePosition()
+ } else if (!this._waitWindowId) {
+ this._waitWindowId = GLib.idle_add(
+ GLib.PRIORITY_DEFAULT_IDLE,
+ () => {
+ this._waitWindowId = 0
+
+ if (this._previewMenu.opened) {
+ _assignWindowClone()
+ }
+
+ return GLib.SOURCE_REMOVE
+ },
+ )
+ }
+ }
+
+ _assignWindowClone()
+ }
+
+ this._cancelAnimateOut()
+ this._removeWindowSignals()
+ this.window = window
+ this._needsCloseButton =
+ this._previewMenu.allowCloseWindow &&
+ window.can_close() &&
+ !Utils.checkIfWindowHasTransient(window)
+ this._updateHeader()
+ }
+
+ animateOut() {
+ if (!this.animatingOut) {
+ let tweenOpts = getTweenOpts({
+ opacity: 0,
+ width: 0,
+ height: 0,
+ onComplete: () => this.destroy(),
+ })
+
+ this.animatingOut = true
+
+ Utils.stopAnimations(this)
+ Utils.animate(this, tweenOpts)
+ }
+ }
+
+ getSize() {
+ let [binWidth, binHeight] = this._getBinSize()
+
+ binWidth = Math.max(binWidth, this.cloneWidth + this._padding * 2)
+ binHeight =
+ Math.max(binHeight, this.cloneHeight + this._padding * 2) + headerHeight
+
+ return [binWidth, binHeight]
+ }
+
+ setFocus(focused) {
+ this._hideOrShowCloseButton(!focused)
+ setStyle(
+ this,
+ this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0),
+ )
+
+ if (focused) {
+ this._previewMenu.ensureVisible(this)
+ this._previewMenu.requestPeek(this.window)
+ }
+ }
+
+ activate() {
+ this._previewMenu.endPeekHere()
+ this._previewMenu.close()
+ Main.activateWindow(this.window)
+ }
+
+ _onDestroy() {
+ if (this._waitWindowId) {
+ GLib.source_remove(this._waitWindowId)
+ this._waitWindowId = 0
+ }
+
+ this._removeWindowSignals()
+ }
+
+ _onHoverChanged() {
+ this.setFocus(this.hover)
+ }
+
+ _onCloseBtnClick() {
+ this._hideOrShowCloseButton(true)
+ this.reactive = false
+
+ if (!SETTINGS.get_boolean('group-apps')) {
+ this._previewMenu.close()
+ } else {
+ this._previewMenu.endPeekHere()
+ }
+
+ this.window.delete(global.get_current_time())
+ }
+
+ _onButtonReleaseEvent(e) {
+ switch (e.get_button()) {
+ case 1: // Left click
+ this.activate()
+ break
+ case 2: // Middle click
+ if (SETTINGS.get_boolean('preview-middle-click-close')) {
+ this._onCloseBtnClick()
+ }
+ break
+ case 3: // Right click
+ this._showContextMenu(e)
+ break
+ }
+
+ return Clutter.EVENT_STOP
+ }
+
+ _cancelAnimateOut() {
+ if (this.animatingOut) {
+ this.animatingOut = false
+
+ Utils.stopAnimations(this)
+ Utils.animate(
+ this,
+ getTweenOpts({
+ opacity: 255,
+ width: this.cloneWidth,
+ height: this.cloneHeight,
+ }),
+ )
+ }
+ }
+
+ _showContextMenu(e) {
+ let coords = e.get_coords()
+ let currentWorkspace =
+ this._previewMenu.peekInitialWorkspaceIndex < 0
+ ? Utils.getCurrentWorkspace()
+ : Utils.getWorkspaceByIndex(
+ this._previewMenu.peekInitialWorkspaceIndex,
+ )
+
+ Main.wm._showWindowMenu(null, this.window, Meta.WindowMenuType.WM, {
+ x: coords[0],
+ y: coords[1],
+ width: 0,
+ height: 0,
+ })
+
+ let menu = Main.wm._windowMenuManager._manager._menus[0]
+
+ menu.connect('open-state-changed', () =>
+ this._previewMenu.menu.sync_hover(),
+ )
+ this._previewMenu.menu.sync_hover()
+
+ if (this.window.get_workspace() != currentWorkspace) {
+ let menuItem = new PopupMenu.PopupMenuItem(
+ _('Move to current Workspace') +
+ ' [' +
+ (currentWorkspace.index() + 1) +
+ ']',
+ )
+ let menuItems = menu.box.get_children()
+ let insertIndex = Utils.findIndex(
+ menuItems,
+ (c) => c._delegate instanceof PopupMenu.PopupSeparatorMenuItem,
+ )
+
+ insertIndex = insertIndex >= 0 ? insertIndex : menuItems.length - 1
+ menu.addMenuItem(menuItem, insertIndex)
+ menuItem.connect('activate', () =>
+ this.window.change_workspace(currentWorkspace),
+ )
+ }
+ }
+
+ _removeWindowSignals() {
+ if (this._titleWindowChangeId) {
+ this.window.disconnect(this._titleWindowChangeId)
+ this._titleWindowChangeId = 0
+ }
+ }
+
+ _updateHeader() {
+ if (headerHeight) {
+ this._titleWindowChangeId = this.window.connect('notify::title', () =>
+ this._updateWindowTitle(),
+ )
+ setStyle(
+ this._windowTitle,
+ 'max-width: 0px; padding-left: 8px; padding-right: 8px; text-align: center;',
+ )
+ this._updateWindowTitle()
+ }
+ }
+
+ _updateWindowTitle() {
+ this._windowTitle.text = this.window.title
+ }
+
+ _hideOrShowCloseButton(hide) {
+ if (this._needsCloseButton) {
+ Utils.animate(
+ this._closeButtonBin,
+ getTweenOpts({ opacity: hide ? 0 : 255 }),
+ )
+ }
+ }
+
+ _getBackgroundColor(offset, alpha) {
+ return (
+ 'background-color: ' +
+ this._getRgbaColor(offset, alpha) +
+ 'transition-duration:' +
+ this._previewMenu.panel.dynamicTransparency.animationDuration
+ )
+ }
+
+ _getRgbaColor(offset, alpha) {
+ alpha = Math.abs(alpha)
+
+ if (isNaN(alpha)) {
+ alpha = alphaBg
+ }
+
+ return Utils.getrgbaColor(
+ this._previewMenu._getThemeBackground(),
+ alpha,
+ offset,
+ )
+ }
+
+ _addClone(newCloneBin, animateSize) {
+ let currentClones = this._previewBin.get_children()
+ let newCloneOpts = getTweenOpts({ opacity: 255 })
+
+ this._previewBin.add_child(newCloneBin)
+
+ if (currentClones.length) {
+ let currentCloneBin = currentClones.pop()
+ let currentCloneOpts = getTweenOpts({
+ opacity: 0,
+ onComplete: () => currentCloneBin.destroy(),
+ })
+
+ if (newCloneBin.width > currentCloneBin.width) {
+ newCloneOpts.width = newCloneBin.width
+ newCloneBin.width = currentCloneBin.width
+ } else {
+ currentCloneOpts.width = newCloneBin.width
+ }
+
+ if (newCloneBin.height > currentCloneBin.height) {
+ newCloneOpts.height = newCloneBin.height
+ newCloneBin.height = currentCloneBin.height
+ } else {
+ currentCloneOpts.height = newCloneBin.height
+ }
+
+ currentClones.forEach((c) => c.destroy())
+ Utils.animate(currentCloneBin, currentCloneOpts)
+ } else if (animateSize) {
+ newCloneBin.width = 0
+ newCloneBin.height = 0
+ newCloneOpts.width = this.cloneWidth
+ newCloneOpts.height = this.cloneHeight
+ }
+
+ Utils.animate(newCloneBin, newCloneOpts)
+ }
+
+ _getWindowCloneBin(window) {
+ let frameRect = window.get_frame_rect()
+ let bufferRect = window.get_buffer_rect()
+ let clone = new Clutter.Clone({ source: window.get_compositor_private() })
+ let cloneBin = new St.Widget({
+ opacity: 0,
+ layout_manager:
+ frameRect.width != bufferRect.width ||
+ frameRect.height != bufferRect.height
+ ? new WindowCloneLayout(frameRect, bufferRect)
+ : new Clutter.BinLayout(),
+ })
+
+ cloneBin.add_child(clone)
+
+ return cloneBin
+ }
+
+ _getBinSize() {
+ let [fixedWidth, fixedHeight] = this._previewDimensions
+
+ return [
+ aspectRatio.x.fixed ? fixedWidth + this._padding * 2 : -1,
+ aspectRatio.y.fixed ? fixedHeight + this._padding * 2 : -1,
+ ]
+ }
+
+ _resizeClone(cloneBin, window) {
+ let frameRect =
+ cloneBin.layout_manager.frameRect || window.get_frame_rect()
+ let [fixedWidth, fixedHeight] = this._previewDimensions
+ let ratio = Math.min(
+ fixedWidth / frameRect.width,
+ fixedHeight / frameRect.height,
+ 1,
+ )
+ let cloneWidth = frameRect.width * ratio
+ let cloneHeight = frameRect.height * ratio
+
+ let clonePaddingTB =
+ cloneHeight < MIN_DIMENSION ? MIN_DIMENSION - cloneHeight : 0
+ let clonePaddingLR =
+ cloneWidth < MIN_DIMENSION ? MIN_DIMENSION - cloneWidth : 0
+ let clonePaddingTop = clonePaddingTB * 0.5
+ let clonePaddingLeft = clonePaddingLR * 0.5
+
+ this.cloneWidth = cloneWidth + clonePaddingLR * scaleFactor
+ this.cloneHeight = cloneHeight + clonePaddingTB * scaleFactor
+
+ cloneBin.set_style(
+ 'padding: ' + clonePaddingTop + 'px ' + clonePaddingLeft + 'px;',
+ )
+ cloneBin.layout_manager.ratio = ratio
+ cloneBin.layout_manager.padding = [
+ clonePaddingLeft * scaleFactor,
+ clonePaddingTop * scaleFactor,
+ ]
+
+ cloneBin.get_first_child().set_size(cloneWidth, cloneHeight)
+ }
+
+ _getPreviewDimensions() {
+ let size = SETTINGS.get_int('window-preview-size') * scaleFactor
+ let w, h
+
+ if (this._previewMenu.isVertical) {
+ w = size
+ h = (w * aspectRatio.y.size) / aspectRatio.x.size
+ } else {
+ h = size
+ w = (h * aspectRatio.x.size) / aspectRatio.y.size
+ }
+
+ return [w, h]
+ }
+ },
+)
+
+export const WindowCloneLayout = GObject.registerClass(
+ {},
+ class WindowCloneLayout extends Clutter.BinLayout {
+ _init(frameRect, bufferRect) {
+ super._init()
+
+ //the buffer_rect contains the transparent padding that must be removed
+ this.frameRect = frameRect
+ this.bufferRect = bufferRect
+ }
+
+ vfunc_allocate(actor, box) {
+ let [width, height] = box.get_size()
+
+ box.set_origin(
+ (this.bufferRect.x - this.frameRect.x) * this.ratio + this.padding[0],
+ (this.bufferRect.y - this.frameRect.y) * this.ratio + this.padding[1],
+ )
+
+ box.set_size(
+ width + (this.bufferRect.width - this.frameRect.width) * this.ratio,
+ height + (this.bufferRect.height - this.frameRect.height) * this.ratio,
+ )
+
+ actor.get_first_child().allocate(box)
+ }
+ },
+)
+
+export function setStyle(actor, style) {
+ actor.set_style(style)
+}
+
+export function getTweenOpts(opts) {
+ let defaults = {
+ time: animationTime,
+ transition: 'easeInOutQuad',
+ }
+
+ return Utils.mergeObjects(opts || {}, defaults)
+}
diff --git a/taskbar.js b/taskbar.js
deleted file mode 100644
index 7ded7ab..0000000
--- a/taskbar.js
+++ /dev/null
@@ -1,1282 +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 .
- *
- *
- * 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 Gio from 'gi://Gio';
-import GLib from 'gi://GLib';
-import GObject from 'gi://GObject';
-import Graphene from 'gi://Graphene';
-import Shell from 'gi://Shell';
-import St from 'gi://St';
-
-import * as AppFavorites from 'resource:///org/gnome/shell/ui/appFavorites.js';
-import * as Dash from 'resource:///org/gnome/shell/ui/dash.js';
-import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
-import * as Main from 'resource:///org/gnome/shell/ui/main.js';
-import {EventEmitter} from 'resource:///org/gnome/shell/misc/signals.js';
-
-import * as AppIcons from './appIcons.js';
-import * as PanelManager from './panelManager.js';
-import * as PanelSettings from './panelSettings.js';
-import * as Pos from './panelPositions.js';
-import * as Utils from './utils.js';
-import * as WindowPreview from './windowPreview.js';
-import {SETTINGS} from './extension.js';
-
-const SearchController = Main.overview.searchController;
-
-export const DASH_ANIMATION_TIME = .2; // Dash.DASH_ANIMATION_TIME is now private
-const DASH_ITEM_HOVER_TIMEOUT = .3; // Dash.DASH_ITEM_HOVER_TIMEOUT is now private
-export const MIN_ICON_SIZE = 4;
-export const APPICON_MARGIN = 4;
-export const APPICON_PADDING = 8;
-
-const T1 = 'ensureAppIconVisibilityTimeout'
-const T2 = 'showLabelTimeout'
-const T3 = 'resetHoverTimeout'
-
-
-/**
- * Extend DashItemContainer
- *
- * - set label position based on taskbar orientation
- *
- * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973.
- * thus use this ugly pattern.
- */
-
-export function extendDashItemContainer(dashItemContainer) {
- dashItemContainer.showLabel = AppIcons.ItemShowLabel;
-}
-
-/* This class is a fork of the upstream DashActor class (ui.dash.js)
- *
- * Summary of changes:
- * - modified chldBox calculations for when 'show-apps-at-top' option is checked
- * - handle horizontal dash
- */
-export const TaskbarActor = GObject.registerClass({
-}, class TaskbarActor extends St.Widget {
- _init(delegate) {
- this._delegate = delegate;
- this._currentBackgroundColor = 0;
- super._init({ name: 'zorintaskbarTaskbar',
- layout_manager: new Clutter.BoxLayout({ orientation: Clutter.Orientation[delegate.dtpPanel.getOrientation().toUpperCase()] }),
- clip_to_allocation: true });
- }
-
- vfunc_allocate(box) {
- this.set_allocation(box);
-
- let panel = this._delegate.dtpPanel;
- let availFixedSize = box[panel.fixedCoord.c2] - box[panel.fixedCoord.c1];
- let availVarSize = box[panel.varCoord.c2] - box[panel.varCoord.c1];
- let [dummy, scrollview, leftFade, rightFade] = this.get_children();
- let [, natSize] = this[panel.sizeFunc](availFixedSize);
- let childBox = new Clutter.ActorBox();
- let orientation = panel.getOrientation();
-
- dummy.allocate(childBox);
-
- childBox[panel.varCoord.c1] = box[panel.varCoord.c1];
- childBox[panel.varCoord.c2] = Math.min(availVarSize, natSize);
- childBox[panel.fixedCoord.c1] = box[panel.fixedCoord.c1];
- childBox[panel.fixedCoord.c2] = box[panel.fixedCoord.c2];
-
- scrollview.allocate(childBox);
-
- let [value, , upper, , , pageSize] = scrollview[orientation[0] + 'adjustment'].get_values();
- upper = Math.floor(upper);
- scrollview._dtpFadeSize = upper > pageSize ? this._delegate.iconSize : 0;
-
- if (this._currentBackgroundColor !== panel.dynamicTransparency.currentBackgroundColor) {
- this._currentBackgroundColor = panel.dynamicTransparency.currentBackgroundColor;
- let gradientStyle = 'background-gradient-start: ' + this._currentBackgroundColor +
- 'background-gradient-direction: ' + orientation;
-
- leftFade.set_style(gradientStyle);
- rightFade.set_style(gradientStyle);
- }
-
- childBox[panel.varCoord.c2] = childBox[panel.varCoord.c1] + (value > 0 ? scrollview._dtpFadeSize : 0);
- leftFade.allocate(childBox);
-
- childBox[panel.varCoord.c1] = box[panel.varCoord.c2] - (value + pageSize < upper ? scrollview._dtpFadeSize : 0);
- childBox[panel.varCoord.c2] = box[panel.varCoord.c2];
- rightFade.allocate(childBox);
- }
-
- // We want to request the natural size of all our children
- // as our natural width, so we chain up to StWidget (which
- // then calls BoxLayout)
- vfunc_get_preferred_width(forHeight) {
- let [, natWidth] = St.Widget.prototype.vfunc_get_preferred_width.call(this, forHeight);
-
- return [0, natWidth];
- }
-
- vfunc_get_preferred_height(forWidth) {
- let [, natHeight] = St.Widget.prototype.vfunc_get_preferred_height.call(this, forWidth);
-
- return [0, natHeight];
- }
-});
-
-/* This class is a fork of the upstream dash class (ui.dash.js)
- *
- * Summary of changes:
- * - disconnect global signals adding a destroy method;
- * - play animations even when not in overview mode
- * - set a maximum icon size
- * - show running and/or favorite applications
- * - emit a custom signal when an app icon is added
- * - Add scrollview
- * Ensure actor is visible on keyfocus inside the scrollview
- * - add 128px icon size, might be useful for hidpi display
- * - Sync minimization application target position.
- */
-
-export const Taskbar = class extends EventEmitter {
-
- constructor(panel) {
- super();
-
- this.dtpPanel = panel;
-
- // start at smallest size due to running indicator drawing area expanding but not shrinking
- this.iconSize = 16;
-
- this._shownInitially = false;
-
- this._signalsHandler = new Utils.GlobalSignalsHandler();
- this._timeoutsHandler = new Utils.TimeoutsHandler();
-
- this._labelShowing = false;
- this.fullScrollView = 0;
-
- let isVertical = panel.checkIfVertical();
-
- this._box = new St.BoxLayout({ vertical: isVertical,
- clip_to_allocation: false,
- x_align: Clutter.ActorAlign.START,
- y_align: Clutter.ActorAlign.START });
-
- this._container = new TaskbarActor(this);
- this._scrollView = new St.ScrollView({ name: 'zorintaskbarScrollview',
- hscrollbar_policy: St.PolicyType.NEVER,
- vscrollbar_policy: St.PolicyType.NEVER,
- enable_mouse_scrolling: true });
-
- this._scrollView.connect('scroll-event', this._onScrollEvent.bind(this));
- this._scrollView.add_child(this._box);
-
- this._showAppsIconWrapper = panel.showAppsIconWrapper;
- this._showAppsIconWrapper.connect('menu-state-changed', (showAppsIconWrapper, opened) => {
- this._itemMenuStateChanged(showAppsIconWrapper, opened);
- });
- // an instance of the showAppsIcon class is encapsulated in the wrapper
- this._showAppsIcon = this._showAppsIconWrapper.realShowAppsIcon;
- this.showAppsButton = this._showAppsIcon.toggleButton;
-
- if (isVertical) {
- this.showAppsButton.set_width(panel.geom.w);
- }
-
- this.showAppsButton.connect('notify::checked', this._onShowAppsButtonToggled.bind(this));
-
- this.showAppsButton.checked = (SearchController._showAppsButton) ? SearchController._showAppsButton.checked : false;
-
- this._showAppsIcon.childScale = 1;
- this._showAppsIcon.childOpacity = 255;
- this._showAppsIcon.icon.setIconSize(this.iconSize);
- this._hookUpLabel(this._showAppsIcon, this._showAppsIconWrapper);
-
- this._container.add_child(new St.Widget({ width: 0, reactive: false }));
- this._container.add_child(this._scrollView);
-
- let orientation = panel.getOrientation();
- let fadeStyle = 'background-gradient-direction:' + orientation;
- let fade1 = new St.Widget({ style_class: 'scrollview-fade', reactive: false });
- let fade2 = new St.Widget({ style_class: 'scrollview-fade',
- reactive: false,
- pivot_point: new Graphene.Point({ x: .5, y: .5 }),
- rotation_angle_z: 180 });
-
- fade1.set_style(fadeStyle);
- fade2.set_style(fadeStyle);
-
- this._container.add_child(fade1);
- this._container.add_child(fade2);
-
- this.previewMenu = new WindowPreview.PreviewMenu(panel);
- this.previewMenu.enable();
-
- let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
- this.actor = new St.Bin({
- child: this._container,
- y_align: Clutter.ActorAlign.START,
- x_align: rtl ? Clutter.ActorAlign.END : Clutter.ActorAlign.START
- });
-
- const adjustment = this._scrollView[orientation[0] + 'adjustment'];
-
- this._workId = Main.initializeDeferredWork(this._box, this._redisplay.bind(this));
-
- this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
-
- this._appSystem = Shell.AppSystem.get_default();
-
- this.iconAnimator = new PanelManager.IconAnimator(this.dtpPanel.panel);
-
- this._signalsHandler.add(
- [
- this.dtpPanel.panel,
- 'notify::height',
- () => this._queueRedisplay()
- ],
- [
- this.dtpPanel.panel,
- 'notify::width',
- () => this._queueRedisplay()
- ],
- [
- this._appSystem,
- 'installed-changed',
- () => {
- AppFavorites.getAppFavorites().reload();
- this._queueRedisplay();
- }
- ],
- [
- this._appSystem,
- 'app-state-changed',
- this._queueRedisplay.bind(this)
- ],
- [
- AppFavorites.getAppFavorites(),
- 'changed',
- this._queueRedisplay.bind(this)
- ],
- [
- global.window_manager,
- 'switch-workspace',
- () => this._connectWorkspaceSignals()
- ],
- [
- Utils.DisplayWrapper.getScreen(),
- [
- 'window-entered-monitor',
- 'window-left-monitor'
- ],
- () => {
- if (SETTINGS.get_boolean('isolate-monitors')) {
- this._queueRedisplay();
- }
- }
- ],
- [
- Main.overview,
- 'item-drag-begin',
- this._onDragBegin.bind(this)
- ],
- [
- Main.overview,
- 'item-drag-end',
- this._onDragEnd.bind(this)
- ],
- [
- Main.overview,
- 'item-drag-cancelled',
- this._onDragCancelled.bind(this)
- ],
- [
- // Ensure the ShowAppsButton status is kept in sync
- SearchController._showAppsButton,
- 'notify::checked',
- this._syncShowAppsButtonToggled.bind(this)
- ],
- [
- SETTINGS,
- [
- 'changed::show-favorites',
- 'changed::show-running-apps',
- 'changed::show-favorites-all-monitors'
- ],
- () => {
- setAttributes()
- this._redisplay()
- }
- ],
- [
- SETTINGS,
- 'changed::group-apps',
- () => {
- setAttributes()
- this._connectWorkspaceSignals();
- }
- ],
- [
- SETTINGS,
- [
- 'changed::group-apps-use-launchers',
- 'changed::taskbar-locked'
- ],
- () => {
- setAttributes()
- this.resetAppIcons()
- }
- ],
- [
- adjustment,
- [
- 'notify::upper',
- 'notify::pageSize'
- ],
- () => this._onScrollSizeChange(adjustment)
- ]
- );
-
- let setAttributes = () => {
- this.isGroupApps = SETTINGS.get_boolean('group-apps');
- this.usingLaunchers = !this.isGroupApps && SETTINGS.get_boolean('group-apps-use-launchers');
- this.showFavorites = SETTINGS.get_boolean('show-favorites') &&
- (this.dtpPanel.isPrimary || SETTINGS.get_boolean('show-favorites-all-monitors'))
- this.showRunningApps = SETTINGS.get_boolean('show-running-apps')
- this.allowSplitApps = this.usingLaunchers || (!this.isGroupApps && !this.showFavorites)
- }
-
- setAttributes()
-
- this._onScrollSizeChange(adjustment);
- this._connectWorkspaceSignals();
- }
-
- destroy() {
- if (this._waitIdleId) {
- GLib.source_remove(this._waitIdleId);
- this._waitIdleId = 0;
- }
-
- this._timeoutsHandler.destroy();
- this.iconAnimator.destroy();
-
- this._signalsHandler.destroy();
- this._signalsHandler = 0;
-
- this._container.destroy();
-
- this.previewMenu.disable();
- this.previewMenu.destroy();
-
- this._disconnectWorkspaceSignals();
- }
-
- _onScrollEvent(actor, event) {
-
- let orientation = this.dtpPanel.getOrientation();
-
- // reset timeout to avid conflicts with the mousehover event
- this._timeoutsHandler.add([T1, 0,
- () => this._swiping = false
- ]);
-
- // Skip to avoid double events mouse
- if (event.is_pointer_emulated())
- return Clutter.EVENT_STOP;
-
- let adjustment, delta;
-
- adjustment = this._scrollView[orientation[0] + 'adjustment'];
-
- let increment = adjustment.step_increment;
-
- switch ( event.get_scroll_direction() ) {
- case Clutter.ScrollDirection.UP:
- case Clutter.ScrollDirection.LEFT:
- delta = -increment;
- break;
- case Clutter.ScrollDirection.DOWN:
- case Clutter.ScrollDirection.RIGHT:
- delta = +increment;
- break;
- case Clutter.ScrollDirection.SMOOTH:
- let [dx, dy] = event.get_scroll_delta();
- delta = dy*increment;
- delta += dx*increment;
- break;
-
- }
-
- adjustment.set_value(adjustment.get_value() + delta);
-
- return Clutter.EVENT_STOP;
-
- }
-
- _onScrollSizeChange(adjustment) {
- // Update minimization animation target position on scrollview change.
- this._updateAppIcons();
-
- // When applications are ungrouped and there is some empty space on the horizontal taskbar,
- // force a fixed label width to prevent the icons from "wiggling" when an animation runs
- // (adding or removing an icon). When the taskbar is full, revert to a dynamic label width
- // to allow them to resize and make room for new icons.
- if (!this.dtpPanel.checkIfVertical() && !this.isGroupApps) {
- let initial = this.fullScrollView;
-
- if (!this.fullScrollView && Math.floor(adjustment.upper) > adjustment.page_size) {
- this.fullScrollView = adjustment.page_size;
- } else if (adjustment.page_size < this.fullScrollView) {
- this.fullScrollView = 0;
- }
-
- if (initial != this.fullScrollView && !this._waitIdleId) {
- this._waitIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
- this._getAppIcons().forEach(a => a.updateTitleStyle())
- this._waitIdleId = 0;
-
- return GLib.SOURCE_REMOVE;
- });
- }
- }
- }
-
- _onDragBegin() {
- this._dragCancelled = false;
- this._dragMonitor = {
- dragMotion: this._onDragMotion.bind(this)
- };
- DND.addDragMonitor(this._dragMonitor);
-
- if (this._box.get_n_children() == 0) {
- this._emptyDropTarget = new Dash.EmptyDropTargetItem();
- this._box.insert_child_at_index(this._emptyDropTarget, 0);
- this._emptyDropTarget.show(true);
- }
-
- this._toggleFavoriteHighlight(true);
- }
-
- _onDragCancelled() {
- this._dragCancelled = true;
-
- if (this._dragInfo) {
- this._box.set_child_at_index(this._dragInfo[1]._dashItemContainer, this._dragInfo[0]);
- }
-
- this._endDrag();
- }
-
- _onDragEnd() {
- if (this._dragCancelled)
- return;
-
- this._endDrag();
- }
-
- _endDrag() {
- if (this._dragInfo && this._dragInfo[1]._dashItemContainer instanceof DragPlaceholderItem) {
- this._box.remove_child(this._dragInfo[1]._dashItemContainer);
- this._dragInfo[1]._dashItemContainer.destroy();
- delete this._dragInfo[1]._dashItemContainer;
- }
-
- this._dragInfo = null;
- this._clearEmptyDropTarget();
- this._showAppsIcon.setDragApp(null);
- DND.removeDragMonitor(this._dragMonitor);
-
- this._dragMonitor = null;
- this.emit('end-drag');
-
- this._toggleFavoriteHighlight();
- }
-
- _onDragMotion(dragEvent) {
- let app = Dash.Dash.getAppFromSource(dragEvent.source);
- if (app == null)
- return DND.DragMotionResult.CONTINUE;
-
- let showAppsHovered = this._showAppsIcon.contains(dragEvent.targetActor);
-
- if (showAppsHovered)
- this._showAppsIcon.setDragApp(app);
- else
- this._showAppsIcon.setDragApp(null);
-
- return DND.DragMotionResult.CONTINUE;
- }
-
- _toggleFavoriteHighlight(show) {
- let appFavorites = AppFavorites.getAppFavorites();
- let cssFuncName = (show ? 'add' : 'remove') + '_style_class_name';
-
- if (this.showFavorites)
- this._getAppIcons().filter(appIcon => (this.usingLaunchers && appIcon.isLauncher) ||
- (!this.usingLaunchers && appFavorites.isFavorite(appIcon.app.get_id())))
- .forEach(fav => fav._container[cssFuncName]('favorite'));
- }
-
- handleIsolatedWorkspaceSwitch() {
- this._shownInitially = this.isGroupApps;
- this._queueRedisplay();
- }
-
- _connectWorkspaceSignals() {
- this._disconnectWorkspaceSignals();
-
- this._lastWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace();
-
- this._workspaceWindowAddedId = this._lastWorkspace.connect('window-added', () => this._queueRedisplay());
- this._workspaceWindowRemovedId = this._lastWorkspace.connect('window-removed', () => this._queueRedisplay());
- }
-
- _disconnectWorkspaceSignals() {
- if (this._lastWorkspace) {
- this._lastWorkspace.disconnect(this._workspaceWindowAddedId);
- this._lastWorkspace.disconnect(this._workspaceWindowRemovedId);
-
- this._lastWorkspace = null;
- }
- }
-
- _queueRedisplay() {
- Main.queueDeferredWork(this._workId);
- }
-
- _hookUpLabel(item, syncHandler) {
- item.child.connect('notify::hover', () => {
- this._syncLabel(item, syncHandler);
- });
-
- syncHandler.connect('sync-tooltip', () => {
- this._syncLabel(item, syncHandler);
- });
- }
-
- _createAppItem(app, window, isLauncher) {
- let appIcon = new AppIcons.TaskbarAppIcon(
- {
- app,
- window,
- isLauncher
- },
- this.dtpPanel,
- {
- setSizeManually: true,
- showLabel: false,
- isDraggable: !SETTINGS.get_boolean('taskbar-locked'),
- },
- this.previewMenu,
- this.iconAnimator
- );
-
- if (appIcon._draggable) {
- appIcon._draggable.connect('drag-begin',
- () => {
- appIcon.opacity = 0;
- appIcon.isDragged = 1;
- });
- appIcon._draggable.connect('drag-end',
- () => {
- appIcon.opacity = 255;
- delete appIcon.isDragged;
- this._updateAppIcons();
- });
- }
-
- appIcon.connect('menu-state-changed',
- (appIcon, opened) => {
- this._itemMenuStateChanged(item, opened);
- });
-
- let item = new TaskbarItemContainer();
-
- item._dtpPanel = this.dtpPanel
- extendDashItemContainer(item);
-
- item.setChild(appIcon);
- appIcon._dashItemContainer = item;
-
- appIcon.connect('notify::hover', () => {
- if (appIcon.hover){
- this._timeoutsHandler.add([T1, 100,
- () => Utils.ensureActorVisibleInScrollView(this._scrollView, appIcon, this._scrollView._dtpFadeSize)
- ])
- } else {
- this._timeoutsHandler.remove(T1)
- }
- });
-
- appIcon.connect('clicked',
- (actor) => {
- Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize);
- });
-
- appIcon.connect('key-focus-in', (actor) => {
- let [x_shift, y_shift] = Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize);
-
- // This signal is triggered also by mouse click. The popup menu is opened at the original
- // coordinates. Thus correct for the shift which is going to be applied to the scrollview.
- if (appIcon._menu) {
- appIcon._menu._boxPointer.xOffset = -x_shift;
- appIcon._menu._boxPointer.yOffset = -y_shift;
- }
- });
-
- // Override default AppIcon label_actor, now the
- // accessible_name is set at DashItemContainer.setLabelText
- appIcon.label_actor = null;
- item.setLabelText(app.get_name());
-
- appIcon.icon.setIconSize(this.iconSize);
- this._hookUpLabel(item, appIcon);
-
- return item;
- }
-
- // Return an array with the "proper" appIcons currently in the taskbar
- _getAppIcons() {
- // Only consider children which are "proper" icons and which are not
- // animating out (which means they will be destroyed at the end of
- // the animation)
- return this._getTaskbarIcons().map(function(actor){
- return actor.child._delegate;
- });
- }
-
- _getTaskbarIcons(includeAnimated) {
- return this._box.get_children().filter(function(actor) {
- return actor.child &&
- actor.child._delegate &&
- actor.child._delegate.icon &&
- (includeAnimated || !actor.animatingOut);
- });
- }
-
- _updateAppIcons() {
- let appIcons = this._getAppIcons();
-
- appIcons.filter(icon => icon.constructor === AppIcons.TaskbarAppIcon).forEach(icon => {
- icon.updateIcon();
- });
- }
-
- _itemMenuStateChanged(item, opened) {
- // When the menu closes, it calls sync_hover, which means
- // that the notify::hover handler does everything we need to.
- if (opened) {
- this._timeoutsHandler.remove(T2)
-
- item.hideLabel();
- } else {
- // I want to listen from outside when a menu is closed. I used to
- // add a custom signal to the appIcon, since gnome 3.8 the signal
- // calling this callback was added upstream.
- this.emit('menu-closed');
- }
- }
-
- _syncLabel(item, syncHandler) {
- let shouldShow = syncHandler ? syncHandler.shouldShowTooltip() : item.child.get_hover();
-
- if (shouldShow) {
- if (!this._timeoutsHandler.getId(T2)) {
- let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
-
- this._timeoutsHandler.add([T2, timeout,
- () => {
- this._labelShowing = true;
- item.showLabel();
- }
- ]);
-
- this._timeoutsHandler.remove(T3)
- }
- } else {
- this._timeoutsHandler.remove(T2)
-
- item.hideLabel();
- if (this._labelShowing) {
- this._timeoutsHandler.add([T3, DASH_ITEM_HOVER_TIMEOUT,
- () => this._labelShowing = false
- ]);
- }
- }
- }
-
- _adjustIconSize() {
- const thisMonitorIndex = this.dtpPanel.monitor.index;
- let panelSize = PanelSettings.getPanelSize(SETTINGS, thisMonitorIndex);
- let availSize = panelSize - APPICON_PADDING * 2;
- let minIconSize = MIN_ICON_SIZE + panelSize % 2;
-
- if (availSize == this.iconSize)
- return;
-
- if (availSize < minIconSize) {
- availSize = minIconSize;
- }
-
- // For the icon size, we only consider children which are "proper"
- // icons and which are not animating out (which means they will be
- // destroyed at the end of the animation)
- let iconChildren = this._getTaskbarIcons().concat([this._showAppsIcon]);
- let scale = this.iconSize / availSize;
-
- this.iconSize = availSize;
-
- for (let i = 0; i < iconChildren.length; i++) {
- let icon = iconChildren[i].child._delegate.icon;
-
- // Set the new size immediately, to keep the icons' sizes
- // in sync with this.iconSize
- icon.setIconSize(this.iconSize);
-
- // Don't animate the icon size change when the overview
- // is transitioning, or when initially filling
- // the taskbar
- if (Main.overview.animationInProgress ||
- !this._shownInitially)
- continue;
-
- let [targetWidth, targetHeight] = icon.icon.get_size();
-
- // Scale the icon's texture to the previous size and
- // tween to the new size
- icon.icon.set_size(icon.icon.width * scale, icon.icon.height * scale);
-
- Utils.animate(icon.icon,
- { width: targetWidth,
- height: targetHeight,
- time: DASH_ANIMATION_TIME,
- transition: 'easeOutQuad',
- });
- }
- }
-
- sortAppsCompareFunction(appA, appB) {
- return getAppStableSequence(appA, this.dtpPanel.monitor) -
- getAppStableSequence(appB, this.dtpPanel.monitor);
- }
-
- getAppInfos() {
- //get the user's favorite apps
- let favoriteApps = this.showFavorites ? AppFavorites.getAppFavorites().getFavorites() : [];
-
- //find the apps that should be in the taskbar: the favorites first, then add the running apps
- // When using isolation, we filter out apps that have no windows in
- // the current workspace (this check is done in AppIcons.getInterestingWindows)
- let runningApps = this.showRunningApps ? this._getRunningApps().sort(this.sortAppsCompareFunction.bind(this)) : [];
-
- if (this.allowSplitApps) {
- return this._createAppInfos(favoriteApps, [], true)
- .concat(this._createAppInfos(runningApps)
- .filter(appInfo => appInfo.windows.length));
- } else {
- return this._createAppInfos(favoriteApps.concat(runningApps.filter(app => favoriteApps.indexOf(app) < 0)))
- .filter(appInfo => appInfo.windows.length || favoriteApps.indexOf(appInfo.app) >= 0);
- }
- }
-
- _redisplay() {
- if (!this._signalsHandler) {
- return;
- }
-
- //get the currently displayed appIcons
- let currentAppIcons = this._getTaskbarIcons();
- let expectedAppInfos = this.getAppInfos();
-
- //remove the appIcons which are not in the expected apps list
- for (let i = currentAppIcons.length - 1; i > -1; --i) {
- let appIcon = currentAppIcons[i].child._delegate;
- let appIndex = Utils.findIndex(expectedAppInfos, appInfo => appInfo.app == appIcon.app &&
- (!this.allowSplitApps || this.isGroupApps || appInfo.windows[0] == appIcon.window) &&
- appInfo.isLauncher == appIcon.isLauncher);
-
- if (appIndex < 0 ||
- (appIcon.window && (this.isGroupApps || expectedAppInfos[appIndex].windows.indexOf(appIcon.window) < 0)) ||
- (!appIcon.window && !appIcon.isLauncher &&
- !this.isGroupApps && expectedAppInfos[appIndex].windows.length)) {
- currentAppIcons[i][this._shownInitially ? 'animateOutAndDestroy' : 'destroy']();
- currentAppIcons.splice(i, 1);
- }
- }
-
- //if needed, reorder the existing appIcons and create the missing ones
- let currentPosition = 0;
- for (let i = 0, l = expectedAppInfos.length; i < l; ++i) {
- let neededAppIcons = this.isGroupApps || !expectedAppInfos[i].windows.length ?
- [{ app: expectedAppInfos[i].app, window: null, isLauncher: expectedAppInfos[i].isLauncher }] :
- expectedAppInfos[i].windows.map(window => ({ app: expectedAppInfos[i].app, window: window, isLauncher: false }));
-
- for (let j = 0, ll = neededAppIcons.length; j < ll; ++j) {
- //check if the icon already exists
- let matchingAppIconIndex = Utils.findIndex(currentAppIcons, appIcon => appIcon.child._delegate.app == neededAppIcons[j].app &&
- appIcon.child._delegate.window == neededAppIcons[j].window);
-
- if (matchingAppIconIndex > 0 && matchingAppIconIndex != currentPosition) {
- //moved icon, reposition it
- this._box.remove_child(currentAppIcons[matchingAppIconIndex]);
- this._box.insert_child_at_index(currentAppIcons[matchingAppIconIndex], currentPosition);
- } else if (matchingAppIconIndex < 0) {
- //the icon doesn't exist yet, create a new one
- let newAppIcon = this._createAppItem(neededAppIcons[j].app, neededAppIcons[j].window, neededAppIcons[j].isLauncher);
-
- this._box.insert_child_at_index(newAppIcon, currentPosition);
- currentAppIcons.splice(currentPosition, 0, newAppIcon);
-
- // Skip animations on first run when adding the initial set
- // of items, to avoid all items zooming in at once
- newAppIcon.show(this._shownInitially);
- }
-
- ++currentPosition;
- }
- }
-
- this._adjustIconSize();
-
- // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744
- // Without it, StBoxLayout may use a stale size cache
- this._box.queue_relayout();
-
- // This is required for icon reordering when the scrollview is used.
- this._updateAppIcons();
-
- // This will update the size, and the corresponding number for each icon on the primary panel
- if (this.dtpPanel.isPrimary) {
- this._updateNumberOverlay();
- }
-
- this._shownInitially = true;
- }
-
- _getRunningApps() {
- let tracker = Shell.WindowTracker.get_default();
- let windows = global.get_window_actors();
- let apps = [];
-
- for (let i = 0, l = windows.length; i < l; ++i) {
- let app = tracker.get_window_app(windows[i].metaWindow);
-
- if (app && apps.indexOf(app) < 0) {
- apps.push(app);
- }
- }
-
- return apps;
- }
-
- _createAppInfos(apps, defaultWindows, defaultIsLauncher) {
- if (this.allowSplitApps && !defaultIsLauncher) {
- let separateApps = []
-
- if (apps.length) {
- let tracker = Shell.WindowTracker.get_default();
- let windows = AppIcons.getInterestingWindows(null, this.dtpPanel.monitor)
- .sort(sortWindowsCompareFunction)
-
- windows.forEach(w => {
- let windowApp = tracker.get_window_app(w)
-
- if (apps.indexOf(windowApp) >= 0)
- separateApps.push({
- app: windowApp,
- isLauncher: false,
- windows: [w]
- })
- })
- }
-
- return separateApps
- }
-
- return apps.map(app => ({
- app: app,
- isLauncher: defaultIsLauncher || false,
- windows: defaultWindows || AppIcons.getInterestingWindows(app, this.dtpPanel.monitor)
- .sort(sortWindowsCompareFunction)
- }));
- }
-
- // Reset the displayed apps icon to mantain the correct order
- resetAppIcons (geometryChange) {
- let children = this._getTaskbarIcons(true);
-
- for (let i = 0; i < children.length; i++) {
- let item = children[i];
- item.destroy();
- }
-
- // to avoid ugly animations, just suppress them like when taskbar is first loaded.
- this._shownInitially = false;
- this._redisplay();
-
- if (geometryChange && this.dtpPanel.checkIfVertical()) {
- this.previewMenu._updateClip();
- }
- }
-
- _updateNumberOverlay() {
- let seenApps = {};
- let counter = 0;
-
- this._getAppIcons().forEach(icon => {
- if (!seenApps[icon.app] || this.allowSplitApps) {
- seenApps[icon.app] = 1;
- counter++;
- }
-
- if (counter <= 10) {
- icon.setNumberOverlay(counter == 10 ? 0 : counter);
- } else {
- // No overlay after 10
- icon.setNumberOverlay(-1);
- }
-
- icon.updateHotkeyNumberOverlay();
- });
-
- if (SETTINGS.get_boolean('hot-keys') &&
- SETTINGS.get_string('hotkeys-overlay-combo') === 'ALWAYS')
- this.toggleNumberOverlay(true);
- }
-
- toggleNumberOverlay(activate) {
- let appIcons = this._getAppIcons();
- appIcons.forEach(function(icon) {
- icon.toggleNumberOverlay(activate);
- });
- }
-
- _clearEmptyDropTarget() {
- if (this._emptyDropTarget) {
- this._emptyDropTarget.animateOutAndDestroy();
- this._emptyDropTarget = null;
- }
- }
-
- handleDragOver(source, actor, x, y, time) {
- if (source == Main.xdndHandler)
- return DND.DragMotionResult.CONTINUE;
-
- // Don't allow favoriting of transient apps
- if (source.app == null || source.app.is_window_backed())
- return DND.DragMotionResult.NO_DROP;
-
- if (!this._settings.is_writable('favorite-apps'))
- return DND.DragMotionResult.NO_DROP;
-
- let isVertical = this.dtpPanel.checkIfVertical();
-
- if (!this._box.contains(source) && !source._dashItemContainer) {
- //not an appIcon of the taskbar, probably from the applications view
- source._dashItemContainer = new DragPlaceholderItem(source, this.iconSize, isVertical);
- this._box.insert_child_above(source._dashItemContainer, null);
- }
-
- let sizeProp = isVertical ? 'height' : 'width';
- let posProp = isVertical ? 'y' : 'x';
- let pos = isVertical ? y : x;
-
- let currentAppIcons = this._getAppIcons();
- let sourceIndex = currentAppIcons.indexOf(source);
- let hoveredIndex = Utils.findIndex(currentAppIcons,
- appIcon => pos >= appIcon._dashItemContainer[posProp] &&
- pos <= (appIcon._dashItemContainer[posProp] + appIcon._dashItemContainer[sizeProp]));
-
- if (!this._dragInfo) {
- this._dragInfo = [sourceIndex, source];
- }
-
- if (hoveredIndex >= 0) {
- let isLeft = pos < currentAppIcons[hoveredIndex]._dashItemContainer[posProp] + currentAppIcons[hoveredIndex]._dashItemContainer[sizeProp] * .5;
- let prevIcon = currentAppIcons[hoveredIndex - 1]
- let nextIcon = currentAppIcons[hoveredIndex + 1]
-
- // Don't allow positioning before or after self and between icons of same app if ungrouped and showing favorites
- if (!(hoveredIndex === sourceIndex ||
- (isLeft && hoveredIndex - 1 == sourceIndex) ||
- (!this.allowSplitApps && isLeft && hoveredIndex - 1 >= 0 && source.app != prevIcon.app &&
- prevIcon.app == currentAppIcons[hoveredIndex].app) ||
- (!isLeft && hoveredIndex + 1 == sourceIndex) ||
- (!this.allowSplitApps && !isLeft && hoveredIndex + 1 < currentAppIcons.length && source.app != nextIcon.app &&
- nextIcon.app == currentAppIcons[hoveredIndex].app))) {
- this._box.set_child_at_index(source._dashItemContainer, hoveredIndex);
-
- // Ensure the next and previous icon are visible when moving the icon
- // (I assume there's room for both of them)
- if (hoveredIndex > 1)
- Utils.ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex-1], this._scrollView._dtpFadeSize);
- if (hoveredIndex < this._box.get_children().length-1)
- Utils.ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex+1], this._scrollView._dtpFadeSize);
- }
- }
-
- return this._dragInfo[0] !== sourceIndex ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.CONTINUE;
- }
-
- // Draggable target interface
- acceptDrop (source, actor, x, y, time) {
- // Don't allow favoriting of transient apps
- if (!this._dragInfo || !source.app || source.app.is_window_backed() ||
- !this._settings.is_writable('favorite-apps')) {
- return false;
- }
-
- let appIcons = this._getAppIcons();
- let sourceIndex = appIcons.indexOf(source);
- let usingLaunchers = !this.isGroupApps && this.usingLaunchers;
-
- // dragging the icon to its original position
- if (this._dragInfo[0] === sourceIndex) {
- return true;
- }
-
- let appFavorites = AppFavorites.getAppFavorites();
- let sourceAppId = source.app.get_id();
- let appIsFavorite = this.showFavorites && appFavorites.isFavorite(sourceAppId);
- let replacingIndex = sourceIndex + (sourceIndex > this._dragInfo[0] ? -1 : 1);
- let favoriteIndex = replacingIndex >= 0 ? appFavorites.getFavorites().indexOf(appIcons[replacingIndex].app) : 0;
- let sameApps = this.allowSplitApps ? [] : appIcons.filter(a => a != source && a.app == source.app);
- let favoritesCount = 0;
- let position = 0;
- let interestingWindows = {};
- let getAppWindows = app => {
- if (!interestingWindows[app]) {
- interestingWindows[app] = AppIcons.getInterestingWindows(app, this.dtpPanel.monitor);
- }
-
- let appWindows = interestingWindows[app]; //prevents "reference to undefined property Symbol.toPrimitive" warning
- return appWindows;
- };
-
- if (sameApps.length &&
- ((!appIcons[sourceIndex - 1] || appIcons[sourceIndex - 1].app !== source.app) &&
- (!appIcons[sourceIndex + 1] || appIcons[sourceIndex + 1].app !== source.app))) {
- appIcons.splice(appIcons.indexOf(sameApps[0]), sameApps.length);
- Array.prototype.splice.apply(appIcons, [sourceIndex + 1, 0].concat(sameApps));
- }
-
- for (let i = 0, l = appIcons.length; i < l; ++i) {
- let windows = [];
-
- if (!usingLaunchers || (!source.isLauncher && !appIcons[i].isLauncher)) {
- windows = appIcons[i].window ? [appIcons[i].window] : getAppWindows(appIcons[i].app);
- }
-
- windows.forEach(w => w._dtpPosition = position++);
-
- if (this.showFavorites &&
- ((usingLaunchers && appIcons[i].isLauncher) ||
- (!usingLaunchers && appFavorites.isFavorite(appIcons[i].app.get_id())))) {
- ++favoritesCount;
- }
- }
-
- if (sourceIndex < favoritesCount) {
- if (appIsFavorite) {
- appFavorites.moveFavoriteToPos(sourceAppId, favoriteIndex);
- } else {
- appFavorites.addFavoriteAtPos(sourceAppId, favoriteIndex);
- }
- } else if (appIsFavorite && this.showFavorites && (!usingLaunchers || source.isLauncher)) {
- appFavorites.removeFavorite(sourceAppId);
- }
-
- appFavorites.emit('changed');
-
- return true;
- }
-
- _onShowAppsButtonToggled() {
- // Sync the status of the default appButtons. Only if the two statuses are
- // different, that means the user interacted with the extension provided
- // application button, cutomize the behaviour. Otherwise the shell has changed the
- // status (due to the _syncShowAppsButtonToggled function below) and it
- // has already performed the desired action.
- let selector = SearchController;
-
- if (selector._showAppsButton &&
- selector._showAppsButton.checked !== this.showAppsButton.checked) {
- // find visible view
-
- if (this.showAppsButton.checked) {
- //override escape key to return to the desktop when entering the overview using the showapps button
- SearchController._onStageKeyPress = function(actor, event) {
- if (Main.modalCount == 1 && event.get_key_symbol() === Clutter.KEY_Escape) {
- this._searchActive ? this.reset() : Main.overview.hide();
-
- return Clutter.EVENT_STOP;
- }
-
- return Object.getPrototypeOf(this)._onStageKeyPress.call(this, actor, event);
- };
-
- let overviewHiddenId = Main.overview.connect('hidden', () => {
- Main.overview.disconnect(overviewHiddenId);
- delete SearchController._onStageKeyPress;
- });
-
- // force exiting overview if needed
- if (!Main.overview._shown) {
- this.forcedOverview = true;
- }
-
- //temporarily use as primary the monitor on which the showapps btn was clicked, this is
- //restored by the panel when exiting the overview
- this.dtpPanel.panelManager.setFocusedMonitor(this.dtpPanel.monitor);
-
- // Finally show the overview
- selector._showAppsButton.checked = true;
- Main.overview.show(2 /*APP_GRID*/);
- }
- else {
- if (this.forcedOverview) {
- // force exiting overview if needed
- Main.overview.hide();
- } else {
- selector._showAppsButton.checked = false;
- }
-
- this.forcedOverview = false;
- }
- }
- }
-
- _syncShowAppsButtonToggled() {
- let status = SearchController._showAppsButton.checked;
- if (this.showAppsButton.checked !== status)
- this.showAppsButton.checked = status;
- }
-
- showShowAppsButton() {
- this.showAppsButton.visible = true;
- this.showAppsButton.set_width(-1);
- this.showAppsButton.set_height(-1);
- }
-
- popupFocusedAppSecondaryMenu() {
- let appIcons = this._getAppIcons();
- let tracker = Shell.WindowTracker.get_default();
-
- for(let i in appIcons) {
- if(appIcons[i].app == tracker.focus_app) {
- let appIcon = appIcons[i];
- if(appIcon._menu && appIcon._menu.isOpen)
- appIcon._menu.close();
- else
- appIcon.popupMenu();
-
- appIcon.sync_hover();
- break;
- }
- }
- }
-};
-
-export const TaskbarItemContainer = GObject.registerClass({
-
-}, class TaskbarItemContainer extends Dash.DashItemContainer {
-
- _init() {
- super._init()
- this.x_expand = this.y_expand = false
- }
-
- vfunc_allocate(box) {
- if (this.child == null)
- return;
-
- this.set_allocation(box);
-
- let availWidth = box.x2 - box.x1;
- let availHeight = box.y2 - box.y1;
- let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] = this.child.get_preferred_size();
- let [childScaleX, childScaleY] = this.child.get_scale();
-
- let childWidth = Math.min(natChildWidth * childScaleX, availWidth);
- let childHeight = Math.min(natChildHeight * childScaleY, availHeight);
- let childBox = new Clutter.ActorBox();
-
- childBox.x1 = (availWidth - childWidth) / 2;
- childBox.y1 = (availHeight - childHeight) / 2;
- childBox.x2 = childBox.x1 + childWidth;
- childBox.y2 = childBox.y1 + childHeight;
-
- this.child.allocate(childBox);
- }
-
- // In case appIcon is removed from the taskbar while it is hovered,
- // restore opacity before dashItemContainer.animateOutAndDestroy does the destroy animation.
- animateOutAndDestroy() {
- if (this._raisedClone) {
- this._raisedClone.source.opacity = 255;
- this._raisedClone.destroy();
- }
-
- super.animateOutAndDestroy();
- }
-});
-
-const DragPlaceholderItem = GObject.registerClass({
-}, class DragPlaceholderItem extends St.Widget {
-
- _init(appIcon, iconSize, isVertical) {
- super._init({ style: AppIcons.getIconContainerStyle(isVertical), layout_manager: new Clutter.BinLayout() });
-
- this.child = { _delegate: appIcon };
-
- this._clone = new Clutter.Clone({
- source: appIcon.icon._iconBin,
- width: iconSize,
- height: iconSize
- });
-
- this.add_child(this._clone);
- }
-
- destroy() {
- this._clone.destroy();
- super.destroy();
- }
-});
-
-export function getAppStableSequence(app, monitor) {
- let windows = AppIcons.getInterestingWindows(app, monitor);
-
- return windows.reduce((prevWindow, window) => {
- return Math.min(prevWindow, getWindowStableSequence(window));
- }, Infinity);
-}
-
-export function sortWindowsCompareFunction(windowA, windowB) {
- return getWindowStableSequence(windowA) - getWindowStableSequence(windowB);
-}
-
-export function getWindowStableSequence(window) {
- return ('_dtpPosition' in window ? window._dtpPosition : window.get_stable_sequence());
-}
diff --git a/transparency.js b/transparency.js
deleted file mode 100644
index 994299d..0000000
--- a/transparency.js
+++ /dev/null
@@ -1,200 +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 .
- *
- * 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._updateComplementaryStyles();
- this._setBackground();
- }
-
- _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-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.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[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 && 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
- }
- }
-
- _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;
- }
-}
diff --git a/ui/BoxIntellihideOptions.ui b/ui/BoxIntellihideOptions.ui
index 80669ae..81eb2e1 100644
--- a/ui/BoxIntellihideOptions.ui
+++ b/ui/BoxIntellihideOptions.ui
@@ -1,19 +1,18 @@
-
+
+
-
+
-
-
-
Require pressure at the edge of the screen to reveal the panel
@@ -57,13 +52,10 @@
-
-
-
Allow the panel to be revealed while in fullscreen mode
@@ -74,11 +66,10 @@
-
- Only hide secondary panels
(requires multi-monitors option)
+ Only hide secondary panels
center
@@ -86,24 +77,41 @@
-
- Keyboard shortcut to reveal and hold the panel
Syntax: <Shift>, <Ctrl>, <Alt>, <Super>
+ Keyboard shortcut to reveal and hold the panel
+ e.g. <Super>i
+ center
+ 12
+
+
+
+
+
+
+ Persist state across restarts
+
+
+ center
+
+
+
+
+
+
+ (respects "Do Not Disturb" and requires show notification counter badge option)
+ Reveal and hold the panel on notification
+
+
center
- 12
- e.g. <Super>i
-
-
-
diff --git a/ui/BoxMiddleClickOptions.ui b/ui/BoxMiddleClickOptions.ui
index 023845e..5ce94db 100644
--- a/ui/BoxMiddleClickOptions.ui
+++ b/ui/BoxMiddleClickOptions.ui
@@ -29,6 +29,7 @@
- Cycle windows + minimize
- Toggle single / Preview multiple
- Toggle single / Cycle multiple
+ - Toggle single / Spread multiple
- Quit
@@ -57,6 +58,7 @@
- Cycle windows + minimize
- Toggle single / Preview multiple
- Toggle single / Cycle multiple
+ - Toggle single / Spread multiple
- Quit
@@ -85,6 +87,7 @@
- Cycle windows + minimize
- Toggle single / Preview multiple
- Toggle single / Cycle multiple
+ - Toggle single / Spread multiple
- Quit
@@ -97,4 +100,4 @@
-
\ No newline at end of file
+
diff --git a/ui/BoxOverlayShortcut.ui b/ui/BoxOverlayShortcut.ui
index 6ca0704..0f31552 100644
--- a/ui/BoxOverlayShortcut.ui
+++ b/ui/BoxOverlayShortcut.ui
@@ -1,23 +1,22 @@
-
+
+
-
+
- vertical
- 600
- 24
- 32
32
- 32
32
-
+ 32
+ 32
+ vertical
+ 24
+ 600
-
- Hotkeys prefix
Hotkeys will either be Super+Number or Super+Alt+Num
+ Hotkeys prefix
center
@@ -29,11 +28,10 @@
-
- Number overlay
Temporarily show the application numbers over the icons when using the hotkeys.
+ Number overlay
center
@@ -46,37 +44,34 @@
-
- Shortcut to show the overlay for 2 seconds
Syntax: <Shift>, <Ctrl>, <Alt>, <Super>
+ Shortcut to show the overlay for 2 seconds
+ e.g. <Super>q
center
- 12
- e.g. <Super>q
+ 12
-
- Show window previews on hotkey
Show previews when the application have multiple instances
+ Show window previews on hotkey
-
- center
-
-
+
+ center
+
+
-
- Hotkeys are activated with
Select which keyboard number keys are used to activate the hotkeys
+ Hotkeys are activated with
center
@@ -89,9 +84,7 @@
-
-
diff --git a/ui/SettingsAction.ui b/ui/SettingsAction.ui
index 758f6a2..a763d75 100644
--- a/ui/SettingsAction.ui
+++ b/ui/SettingsAction.ui
@@ -1,27 +1,25 @@
-
+
+
-
+
+ input-mouse-symbolic
Action
- view-pin-symbolic
-
-
Click action
-
- Click action
Behaviour when clicking on the icon of a running application.
+ Click action
- True
+ True
center
- emblem-system-symbolic
+ emblem-system-symbolic