gnome-shell-extensions/SOURCES/improve-workspace-names.patch
2025-10-07 07:49:06 +00:00

6491 lines
218 KiB
Diff

From 7e65ba671f3fe2999a7b5a473f934879a540d734 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 23 Mar 2022 19:59:14 +0100
Subject: [PATCH 01/43] build: Remove unused stylesheets
The only reason for installing empty stylesheets is minimizing
build system differences between extensions. That's not a very
good reason and we don't do this for other optional files like
schemas.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/223>
---
extensions/apps-menu/meson.build | 1 +
extensions/auto-move-windows/stylesheet.css | 1 -
extensions/classification-banner/meson.build | 1 +
extensions/custom-menu/stylesheet.css | 1 -
extensions/dash-to-dock/meson.build | 1 +
extensions/dash-to-panel/meson.build | 1 +
extensions/desktop-icons/meson.build | 1 +
extensions/drive-menu/meson.build | 1 +
extensions/gesture-inhibitor/stylesheet.css | 1 -
extensions/heads-up-display/meson.build | 1 +
extensions/launch-new-instance/stylesheet.css | 1 -
extensions/meson.build | 2 +-
extensions/meson.build.template | 1 +
extensions/native-window-placement/meson.build | 1 +
extensions/panel-favorites/meson.build | 1 +
extensions/places-menu/meson.build | 1 +
extensions/screenshot-window-sizer/meson.build | 1 +
extensions/top-icons/stylesheet.css | 1 -
extensions/updates-dialog/stylesheet.css | 1 -
extensions/user-theme/stylesheet.css | 1 -
extensions/window-list/meson.build | 1 +
extensions/windowsNavigator/meson.build | 1 +
extensions/workspace-indicator/meson.build | 1 +
23 files changed, 16 insertions(+), 8 deletions(-)
delete mode 100644 extensions/auto-move-windows/stylesheet.css
delete mode 100644 extensions/custom-menu/stylesheet.css
delete mode 100644 extensions/gesture-inhibitor/stylesheet.css
delete mode 100644 extensions/launch-new-instance/stylesheet.css
delete mode 100644 extensions/top-icons/stylesheet.css
delete mode 100644 extensions/updates-dialog/stylesheet.css
delete mode 100644 extensions/user-theme/stylesheet.css
diff --git a/extensions/apps-menu/meson.build b/extensions/apps-menu/meson.build
index 48504f63..6b9bb19c 100644
--- a/extensions/apps-menu/meson.build
+++ b/extensions/apps-menu/meson.build
@@ -3,3 +3,4 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
diff --git a/extensions/auto-move-windows/stylesheet.css b/extensions/auto-move-windows/stylesheet.css
deleted file mode 100644
index 25134b65..00000000
--- a/extensions/auto-move-windows/stylesheet.css
+++ /dev/null
@@ -1 +0,0 @@
-/* This extensions requires no special styling */
diff --git a/extensions/classification-banner/meson.build b/extensions/classification-banner/meson.build
index c55a7830..aa943741 100644
--- a/extensions/classification-banner/meson.build
+++ b/extensions/classification-banner/meson.build
@@ -3,6 +3,7 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
extension_sources += files('prefs.js')
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
diff --git a/extensions/custom-menu/stylesheet.css b/extensions/custom-menu/stylesheet.css
deleted file mode 100644
index 25134b65..00000000
--- a/extensions/custom-menu/stylesheet.css
+++ /dev/null
@@ -1 +0,0 @@
-/* This extensions requires no special styling */
diff --git a/extensions/dash-to-dock/meson.build b/extensions/dash-to-dock/meson.build
index 290374fb..749c2723 100644
--- a/extensions/dash-to-dock/meson.build
+++ b/extensions/dash-to-dock/meson.build
@@ -3,6 +3,7 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
extension_sources += files(
'appIconIndicators.js',
diff --git a/extensions/dash-to-panel/meson.build b/extensions/dash-to-panel/meson.build
index 70680479..0cae5eef 100644
--- a/extensions/dash-to-panel/meson.build
+++ b/extensions/dash-to-panel/meson.build
@@ -3,6 +3,7 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
extension_sources += files(
'appIcons.js',
diff --git a/extensions/desktop-icons/meson.build b/extensions/desktop-icons/meson.build
index 8431af62..3512db2c 100644
--- a/extensions/desktop-icons/meson.build
+++ b/extensions/desktop-icons/meson.build
@@ -3,6 +3,7 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
extension_schemas += files(join_paths('schemas', metadata_conf.get('gschemaname') + '.gschema.xml'))
diff --git a/extensions/drive-menu/meson.build b/extensions/drive-menu/meson.build
index 48504f63..6b9bb19c 100644
--- a/extensions/drive-menu/meson.build
+++ b/extensions/drive-menu/meson.build
@@ -3,3 +3,4 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
diff --git a/extensions/gesture-inhibitor/stylesheet.css b/extensions/gesture-inhibitor/stylesheet.css
deleted file mode 100644
index 37b93f21..00000000
--- a/extensions/gesture-inhibitor/stylesheet.css
+++ /dev/null
@@ -1 +0,0 @@
-/* Add your custom extension styling here */
diff --git a/extensions/heads-up-display/meson.build b/extensions/heads-up-display/meson.build
index 40c3de0a..678fd325 100644
--- a/extensions/heads-up-display/meson.build
+++ b/extensions/heads-up-display/meson.build
@@ -3,6 +3,7 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
extension_sources += files('headsUpMessage.js', 'prefs.js')
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
diff --git a/extensions/launch-new-instance/stylesheet.css b/extensions/launch-new-instance/stylesheet.css
deleted file mode 100644
index 25134b65..00000000
--- a/extensions/launch-new-instance/stylesheet.css
+++ /dev/null
@@ -1 +0,0 @@
-/* This extensions requires no special styling */
diff --git a/extensions/meson.build b/extensions/meson.build
index d1bf92c9..e8945ed3 100644
--- a/extensions/meson.build
+++ b/extensions/meson.build
@@ -15,7 +15,7 @@ foreach e : all_extensions
metadata_conf.set('url', 'https://gitlab.gnome.org/GNOME/gnome-shell-extensions')
extension_sources = files(e + '/extension.js')
- extension_data = files(e + '/stylesheet.css')
+ extension_data = []
subdir(e)
diff --git a/extensions/meson.build.template b/extensions/meson.build.template
index e83e528b..a9915994 100644
--- a/extensions/meson.build.template
+++ b/extensions/meson.build.template
@@ -4,5 +4,6 @@ extension_data += configure_file(
configuration: metadata_conf
)
+# extension_data += files('stylesheet.css')
# extension_sources += files('prefs.js')
# extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
diff --git a/extensions/native-window-placement/meson.build b/extensions/native-window-placement/meson.build
index 585c02da..cf73fc03 100644
--- a/extensions/native-window-placement/meson.build
+++ b/extensions/native-window-placement/meson.build
@@ -5,3 +5,4 @@ extension_data += configure_file(
)
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
+extension_data += files('stylesheet.css')
diff --git a/extensions/panel-favorites/meson.build b/extensions/panel-favorites/meson.build
index ab6967fa..d335e362 100644
--- a/extensions/panel-favorites/meson.build
+++ b/extensions/panel-favorites/meson.build
@@ -9,3 +9,4 @@ extension_sources += files(
)
extension_schemas += files('schemas/' + metadata_conf.get('gschemaname') + '.gschema.xml')
+extension_data += files('stylesheet.css')
diff --git a/extensions/places-menu/meson.build b/extensions/places-menu/meson.build
index d9a59691..cbc2a02b 100644
--- a/extensions/places-menu/meson.build
+++ b/extensions/places-menu/meson.build
@@ -3,5 +3,6 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
extension_sources += files('placeDisplay.js')
diff --git a/extensions/screenshot-window-sizer/meson.build b/extensions/screenshot-window-sizer/meson.build
index 585c02da..8257dee0 100644
--- a/extensions/screenshot-window-sizer/meson.build
+++ b/extensions/screenshot-window-sizer/meson.build
@@ -3,5 +3,6 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
diff --git a/extensions/top-icons/stylesheet.css b/extensions/top-icons/stylesheet.css
deleted file mode 100644
index 25134b65..00000000
--- a/extensions/top-icons/stylesheet.css
+++ /dev/null
@@ -1 +0,0 @@
-/* This extensions requires no special styling */
diff --git a/extensions/updates-dialog/stylesheet.css b/extensions/updates-dialog/stylesheet.css
deleted file mode 100644
index 25134b65..00000000
--- a/extensions/updates-dialog/stylesheet.css
+++ /dev/null
@@ -1 +0,0 @@
-/* This extensions requires no special styling */
diff --git a/extensions/user-theme/stylesheet.css b/extensions/user-theme/stylesheet.css
deleted file mode 100644
index 6d914832..00000000
--- a/extensions/user-theme/stylesheet.css
+++ /dev/null
@@ -1 +0,0 @@
-/* none used */
diff --git a/extensions/window-list/meson.build b/extensions/window-list/meson.build
index 34d7c3fd..599f45e1 100644
--- a/extensions/window-list/meson.build
+++ b/extensions/window-list/meson.build
@@ -3,6 +3,7 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
extension_sources += files('prefs.js', 'windowPicker.js', 'workspaceIndicator.js')
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
diff --git a/extensions/windowsNavigator/meson.build b/extensions/windowsNavigator/meson.build
index 48504f63..6b9bb19c 100644
--- a/extensions/windowsNavigator/meson.build
+++ b/extensions/windowsNavigator/meson.build
@@ -3,3 +3,4 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
diff --git a/extensions/workspace-indicator/meson.build b/extensions/workspace-indicator/meson.build
index 71efa039..19858a39 100644
--- a/extensions/workspace-indicator/meson.build
+++ b/extensions/workspace-indicator/meson.build
@@ -3,5 +3,6 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
extension_sources += files('prefs.js')
--
2.50.0
From c84bfeb065d0200dee5e5ac1eb7ba30feb105360 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Oct 2020 02:34:41 +0200
Subject: [PATCH 02/43] workspace-indicator: Use custom layout manager for
thumbnails
The current code positions window previews explicitly using a fixed
layout manager. For that it relies on a valid parent allocation,
which is error-prone and frequently results in warnings.
Address this by moving the positioning code into a custom layout
manager, and only update the visibility from the window preview.
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/260
---
extensions/workspace-indicator/extension.js | 71 +++++++++++----------
1 file changed, 38 insertions(+), 33 deletions(-)
diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js
index d377f288..101ef7be 100644
--- a/extensions/workspace-indicator/extension.js
+++ b/extensions/workspace-indicator/extension.js
@@ -35,27 +35,15 @@ let WindowPreview = GObject.registerClass({
this.connect('destroy', this._onDestroy.bind(this));
this._sizeChangedId = this._window.connect('size-changed',
- this._relayout.bind(this));
+ () => this.queue_relayout());
this._positionChangedId = this._window.connect('position-changed',
- this._relayout.bind(this));
+ () => this.queue_relayout());
this._minimizedChangedId = this._window.connect('notify::minimized',
- this._relayout.bind(this));
+ this._updateVisible.bind(this));
this._monitorEnteredId = global.display.connect('window-entered-monitor',
- this._relayout.bind(this));
+ this._updateVisible.bind(this));
this._monitorLeftId = global.display.connect('window-left-monitor',
- this._relayout.bind(this));
-
- // Do initial layout when we get a parent
- let id = this.connect('parent-set', () => {
- this.disconnect(id);
- if (!this.get_parent())
- return;
- this._laterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
- this._laterId = 0;
- this._relayout();
- return false;
- });
- });
+ this._updateVisible.bind(this));
this._focusChangedId = global.display.connect('notify::focus-window',
this._onFocusChanged.bind(this));
@@ -67,6 +55,10 @@ let WindowPreview = GObject.registerClass({
return this._window.get_compositor_private();
}
+ get metaWindow() {
+ return this._window;
+ }
+
_onDestroy() {
this._window.disconnect(this._sizeChangedId);
this._window.disconnect(this._positionChangedId);
@@ -74,8 +66,6 @@ let WindowPreview = GObject.registerClass({
global.display.disconnect(this._monitorEnteredId);
global.display.disconnect(this._monitorLeftId);
global.display.disconnect(this._focusChangedId);
- if (this._laterId)
- Meta.later_remove(this._laterId);
}
_onFocusChanged() {
@@ -85,25 +75,40 @@ let WindowPreview = GObject.registerClass({
this.remove_style_class_name('active');
}
- _relayout() {
+ _updateVisible() {
let monitor = Main.layoutManager.findIndexForActor(this);
this.visible = monitor == this._window.get_monitor() &&
this._window.showing_on_its_workspace();
+ }
+});
- if (!this.visible)
- return;
+let WorkspaceLayout = GObject.registerClass(
+class WorkspaceLayout extends Clutter.LayoutManager {
+ vfunc_get_preferred_width() {
+ return [0, 0];
+ }
- let workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
- let hscale = this.get_parent().allocation.get_width() / workArea.width;
- let vscale = this.get_parent().allocation.get_height() / workArea.height;
+ vfunc_get_preferred_height() {
+ return [0, 0];
+ }
- let frameRect = this._window.get_frame_rect();
- this.set_size(
- Math.round(Math.min(frameRect.width, workArea.width) * hscale),
- Math.round(Math.min(frameRect.height, workArea.height) * vscale));
- this.set_position(
- Math.round(frameRect.x * hscale),
- Math.round(frameRect.y * vscale));
+ vfunc_allocate(container, box, flags) {
+ const monitor = Main.layoutManager.findIndexForActor(container);
+ const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
+ const hscale = box.get_width() / workArea.width;
+ const vscale = box.get_height() / workArea.height;
+
+ for (const child of container.get_children()) {
+ const childBox = new Clutter.ActorBox();
+ const frameRect = child.metaWindow.get_frame_rect();
+ childBox.set_size(
+ Math.min(frameRect.width, workArea.width) * hscale,
+ Math.min(frameRect.height, workArea.height) * vscale);
+ childBox.set_origin(
+ Math.round(frameRect.x * hscale),
+ Math.round(frameRect.y * vscale));
+ child.allocate(childBox, flags);
+ }
}
});
@@ -114,7 +119,7 @@ let WorkspaceThumbnail = GObject.registerClass({
super._init({
style_class: 'workspace',
child: new Clutter.Actor({
- layout_manager: new Clutter.BinLayout(),
+ layout_manager: new WorkspaceLayout(),
clip_to_allocation: true
}),
x_fill: true,
--
2.50.0
From e2fd7a6f4ab4f783bc475a6a9cf3156ab4ddecad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 12:38:33 +0100
Subject: [PATCH 03/43] workspace-indicator: Move indicator code into separate
file
Shortly after the window-list extension was added, it gained a
workspace switcher based on the workspace indicator extension.
Duplicating the code wasn't a big issue while the switcher was
a simple menu, but since it gained previews with a fair bit of
custom styling, syncing changes between the two extensions has
become tedious, in particular as the two copies have slightly
diverged over time.
In order to allow the two copies to converge again, the indicator
code needs to be separate from the extension boilerplate, so
split out the code into a separate module.
---
extensions/workspace-indicator/extension.js | 443 +-----------------
extensions/workspace-indicator/meson.build | 2 +-
.../workspace-indicator/workspaceIndicator.js | 443 ++++++++++++++++++
po/POTFILES.in | 2 +-
4 files changed, 447 insertions(+), 443 deletions(-)
create mode 100644 extensions/workspace-indicator/workspaceIndicator.js
diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js
index 101ef7be..6f7d07c5 100644
--- a/extensions/workspace-indicator/extension.js
+++ b/extensions/workspace-indicator/extension.js
@@ -1,450 +1,11 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
/* exported init enable disable */
-const { Clutter, Gio, GObject, Meta, St } = imports.gi;
-
-const DND = imports.ui.dnd;
const ExtensionUtils = imports.misc.extensionUtils;
const Main = imports.ui.main;
-const PanelMenu = imports.ui.panelMenu;
-const PopupMenu = imports.ui.popupMenu;
-const Tweener = imports.ui.tweener;
-
-const Gettext = imports.gettext.domain('gnome-shell-extensions');
-const _ = Gettext.gettext;
-
-const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
-const WORKSPACE_KEY = 'workspace-names';
-
-const TOOLTIP_OFFSET = 6;
-const TOOLTIP_ANIMATION_TIME = 150;
-
-let WindowPreview = GObject.registerClass({
- GTypeName: 'WorkspaceIndicatorWindowPreview'
-}, class WindowPreview extends St.Button {
- _init(window) {
- super._init({
- style_class: 'workspace-indicator-window-preview'
- });
-
- this._delegate = this;
- DND.makeDraggable(this, { restoreOnSuccess: true });
-
- this._window = window;
-
- this.connect('destroy', this._onDestroy.bind(this));
-
- this._sizeChangedId = this._window.connect('size-changed',
- () => this.queue_relayout());
- this._positionChangedId = this._window.connect('position-changed',
- () => this.queue_relayout());
- this._minimizedChangedId = this._window.connect('notify::minimized',
- this._updateVisible.bind(this));
- this._monitorEnteredId = global.display.connect('window-entered-monitor',
- this._updateVisible.bind(this));
- this._monitorLeftId = global.display.connect('window-left-monitor',
- this._updateVisible.bind(this));
-
- this._focusChangedId = global.display.connect('notify::focus-window',
- this._onFocusChanged.bind(this));
- this._onFocusChanged();
- }
-
- // needed for DND
- get realWindow() {
- return this._window.get_compositor_private();
- }
-
- get metaWindow() {
- return this._window;
- }
-
- _onDestroy() {
- this._window.disconnect(this._sizeChangedId);
- this._window.disconnect(this._positionChangedId);
- this._window.disconnect(this._minimizedChangedId);
- global.display.disconnect(this._monitorEnteredId);
- global.display.disconnect(this._monitorLeftId);
- global.display.disconnect(this._focusChangedId);
- }
-
- _onFocusChanged() {
- if (global.display.focus_window == this._window)
- this.add_style_class_name('active');
- else
- this.remove_style_class_name('active');
- }
-
- _updateVisible() {
- let monitor = Main.layoutManager.findIndexForActor(this);
- this.visible = monitor == this._window.get_monitor() &&
- this._window.showing_on_its_workspace();
- }
-});
-
-let WorkspaceLayout = GObject.registerClass(
-class WorkspaceLayout extends Clutter.LayoutManager {
- vfunc_get_preferred_width() {
- return [0, 0];
- }
-
- vfunc_get_preferred_height() {
- return [0, 0];
- }
-
- vfunc_allocate(container, box, flags) {
- const monitor = Main.layoutManager.findIndexForActor(container);
- const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
- const hscale = box.get_width() / workArea.width;
- const vscale = box.get_height() / workArea.height;
-
- for (const child of container.get_children()) {
- const childBox = new Clutter.ActorBox();
- const frameRect = child.metaWindow.get_frame_rect();
- childBox.set_size(
- Math.min(frameRect.width, workArea.width) * hscale,
- Math.min(frameRect.height, workArea.height) * vscale);
- childBox.set_origin(
- Math.round(frameRect.x * hscale),
- Math.round(frameRect.y * vscale));
- child.allocate(childBox, flags);
- }
- }
-});
-
-let WorkspaceThumbnail = GObject.registerClass({
- GTypeName: 'WorkspaceIndicatorWorkspaceThumbnail'
-}, class WorkspaceThumbnail extends St.Button {
- _init(index) {
- super._init({
- style_class: 'workspace',
- child: new Clutter.Actor({
- layout_manager: new WorkspaceLayout(),
- clip_to_allocation: true
- }),
- x_fill: true,
- y_fill: true
- });
-
- this._tooltip = new St.Label({
- style_class: 'dash-label',
- visible: false,
- });
- Main.uiGroup.add_child(this._tooltip);
-
- this.connect('destroy', this._onDestroy.bind(this));
- this.connect('notify::hover', this._syncTooltip.bind(this));
-
- this._index = index;
- this._delegate = this; // needed for DND
-
- this._windowPreviews = new Map();
-
- let workspaceManager = global.workspace_manager;
- this._workspace = workspaceManager.get_workspace_by_index(index);
-
- this._windowAddedId = this._workspace.connect('window-added',
- (ws, window) => {
- this._addWindow(window);
- });
- this._windowRemovedId = this._workspace.connect('window-removed',
- (ws, window) => {
- this._removeWindow(window);
- });
- this._restackedId = global.display.connect('restacked',
- this._onRestacked.bind(this));
-
- this._workspace.list_windows().forEach(w => this._addWindow(w));
- this._onRestacked();
- }
-
- acceptDrop(source) {
- if (!source.realWindow)
- return false;
-
- let window = source.realWindow.get_meta_window();
- this._moveWindow(window);
- return true;
- }
-
- handleDragOver(source) {
- if (source.realWindow)
- return DND.DragMotionResult.MOVE_DROP;
- else
- return DND.DragMotionResult.CONTINUE;
- }
-
- _addWindow(window) {
- if (this._windowPreviews.has(window))
- return;
-
- let preview = new WindowPreview(window);
- preview.connect('clicked', (a, btn) => this.emit('clicked', btn));
- this._windowPreviews.set(window, preview);
- this.child.add_child(preview);
- }
-
- _removeWindow(window) {
- let preview = this._windowPreviews.get(window);
- if (!preview)
- return;
-
- this._windowPreviews.delete(window);
- preview.destroy();
- }
-
- _onRestacked() {
- let lastPreview = null;
- let windows = global.get_window_actors().map(a => a.meta_window);
- for (let i = 0; i < windows.length; i++) {
- let preview = this._windowPreviews.get(windows[i]);
- if (!preview)
- continue;
-
- this.child.set_child_above_sibling(preview, lastPreview);
- lastPreview = preview;
- }
- }
-
- _moveWindow(window) {
- let monitorIndex = Main.layoutManager.findIndexForActor(this);
- if (monitorIndex != window.get_monitor())
- window.move_to_monitor(monitorIndex);
- window.change_workspace_by_index(this._index, false);
- }
-
- // eslint-disable-next-line camelcase
- on_clicked() {
- let ws = global.workspace_manager.get_workspace_by_index(this._index);
- if (ws)
- ws.activate(global.get_current_time());
- }
-
- _syncTooltip() {
- if (this.hover) {
- this._tooltip.text = Meta.prefs_get_workspace_name(this._index);
- this._tooltip.opacity = 0;
- this._tooltip.show();
-
- const [stageX, stageY] = this.get_transformed_position();
- const thumbWidth = this.allocation.get_width();
- const thumbHeight = this.allocation.get_height();
- const tipWidth = this._tooltip.width;
- const xOffset = Math.floor((thumbWidth - tipWidth) / 2);
- const monitor = Main.layoutManager.findMonitorForActor(this);
- const x = Math.min(
- Math.max(stageX + xOffset, monitor.x),
- monitor.x + monitor.width - tipWidth);
- const y = stageY + thumbHeight + TOOLTIP_OFFSET;
- this._tooltip.set_position(x, y);
- }
-
- Tweener.addTween(this._tooltip, {
- opacity: this.hover ? 255 : 0,
- time: TOOLTIP_ANIMATION_TIME / 1000,
- transition: 'easeOutQuad',
- onComplete: () => (this._tooltip.visible = this.hover),
- });
- }
-
- _onDestroy() {
- this._tooltip.destroy();
-
- this._workspace.disconnect(this._windowAddedId);
- this._workspace.disconnect(this._windowRemovedId);
- global.display.disconnect(this._restackedId);
- }
-});
-
-let WorkspaceIndicator = GObject.registerClass(
-class WorkspaceIndicator extends PanelMenu.Button {
- _init() {
- super._init(0.0, _('Workspace Indicator'));
-
- let container = new St.Widget({
- layout_manager: new Clutter.BinLayout(),
- x_expand: true,
- y_expand: true
- });
- this.add_actor(container);
-
- let workspaceManager = global.workspace_manager;
-
- this._currentWorkspace = workspaceManager.get_active_workspace_index();
- this._statusLabel = new St.Label({
- style_class: 'panel-workspace-indicator',
- y_align: Clutter.ActorAlign.CENTER,
- text: this._labelText()
- });
-
- container.add_actor(this._statusLabel);
-
- this._thumbnailsBox = new St.BoxLayout({
- style_class: 'panel-workspace-indicator-box',
- y_expand: true,
- reactive: true
- });
-
- container.add_actor(this._thumbnailsBox);
-
- this._workspacesItems = [];
- this._workspaceSection = new PopupMenu.PopupMenuSection();
- this.menu.addMenuItem(this._workspaceSection);
-
- this._workspaceManagerSignals = [
- workspaceManager.connect_after('notify::n-workspaces',
- this._nWorkspacesChanged.bind(this)),
- workspaceManager.connect_after('workspace-switched',
- this._onWorkspaceSwitched.bind(this)),
- workspaceManager.connect('notify::layout-rows',
- this._onWorkspaceOrientationChanged.bind(this))
- ];
-
- this.connect('scroll-event', this._onScrollEvent.bind(this));
- this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
- this._createWorkspacesSection();
- this._updateThumbnails();
- this._onWorkspaceOrientationChanged();
-
- this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA });
- this._settingsChangedId = this._settings.connect(
- `changed::${WORKSPACE_KEY}`,
- this._updateMenuLabels.bind(this));
- }
-
- _onDestroy() {
- for (let i = 0; i < this._workspaceManagerSignals.length; i++)
- global.workspace_manager.disconnect(this._workspaceManagerSignals[i]);
-
- if (this._settingsChangedId) {
- this._settings.disconnect(this._settingsChangedId);
- this._settingsChangedId = 0;
- }
-
- Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
-
- super._onDestroy();
- }
-
- _onWorkspaceOrientationChanged() {
- let vertical = global.workspace_manager.layout_rows == -1;
- this.reactive = vertical;
-
- this._statusLabel.visible = vertical;
- this._thumbnailsBox.visible = !vertical;
-
- // Disable offscreen-redirect when showing the workspace switcher
- // so that clip-to-allocation works
- Main.panel.set_offscreen_redirect(vertical
- ? Clutter.OffscreenRedirect.ALWAYS
- : Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY);
- }
-
- _onWorkspaceSwitched() {
- this._currentWorkspace = global.workspace_manager.get_active_workspace_index();
-
- this._updateMenuOrnament();
- this._updateActiveThumbnail();
-
- this._statusLabel.set_text(this._labelText());
- }
-
- _nWorkspacesChanged() {
- this._createWorkspacesSection();
- this._updateThumbnails();
- }
-
- _updateMenuOrnament() {
- for (let i = 0; i < this._workspacesItems.length; i++) {
- this._workspacesItems[i].setOrnament(i == this._currentWorkspace
- ? PopupMenu.Ornament.DOT
- : PopupMenu.Ornament.NONE);
- }
- }
-
- _updateActiveThumbnail() {
- let thumbs = this._thumbnailsBox.get_children();
- for (let i = 0; i < thumbs.length; i++) {
- if (i == this._currentWorkspace)
- thumbs[i].add_style_class_name('active');
- else
- thumbs[i].remove_style_class_name('active');
- }
- }
-
- _labelText(workspaceIndex) {
- if (workspaceIndex == undefined) {
- workspaceIndex = this._currentWorkspace;
- return (workspaceIndex + 1).toString();
- }
- return Meta.prefs_get_workspace_name(workspaceIndex);
- }
-
- _updateMenuLabels() {
- for (let i = 0; i < this._workspacesItems.length; i++)
- this._workspacesItems[i].label.text = this._labelText(i);
- }
-
- _createWorkspacesSection() {
- let workspaceManager = global.workspace_manager;
-
- this._workspaceSection.removeAll();
- this._workspacesItems = [];
- this._currentWorkspace = workspaceManager.get_active_workspace_index();
-
- let i = 0;
- for (; i < workspaceManager.n_workspaces; i++) {
- this._workspacesItems[i] = new PopupMenu.PopupMenuItem(this._labelText(i));
- this._workspaceSection.addMenuItem(this._workspacesItems[i]);
- this._workspacesItems[i].workspaceId = i;
- this._workspacesItems[i].label_actor = this._statusLabel;
- this._workspacesItems[i].connect('activate', (actor, _event) => {
- this._activate(actor.workspaceId);
- });
-
- if (i == this._currentWorkspace)
- this._workspacesItems[i].setOrnament(PopupMenu.Ornament.DOT);
- }
-
- this._statusLabel.set_text(this._labelText());
- }
-
- _updateThumbnails() {
- let workspaceManager = global.workspace_manager;
-
- this._thumbnailsBox.destroy_all_children();
-
- for (let i = 0; i < workspaceManager.n_workspaces; i++) {
- let thumb = new WorkspaceThumbnail(i);
- this._thumbnailsBox.add_actor(thumb);
- }
- this._updateActiveThumbnail();
- }
-
- _activate(index) {
- let workspaceManager = global.workspace_manager;
-
- if (index >= 0 && index < workspaceManager.n_workspaces) {
- let metaWorkspace = workspaceManager.get_workspace_by_index(index);
- metaWorkspace.activate(global.get_current_time());
- }
- }
-
- _onScrollEvent(actor, event) {
- let direction = event.get_scroll_direction();
- let diff = 0;
- if (direction == Clutter.ScrollDirection.DOWN) {
- diff = 1;
- } else if (direction == Clutter.ScrollDirection.UP) {
- diff = -1;
- } else {
- return;
- }
- let newIndex = global.workspace_manager.get_active_workspace_index() + diff;
- this._activate(newIndex);
- }
-});
+const Me = ExtensionUtils.getCurrentExtension();
+const { WorkspaceIndicator } = Me.imports.workspaceIndicator;
function init() {
ExtensionUtils.initTranslations();
diff --git a/extensions/workspace-indicator/meson.build b/extensions/workspace-indicator/meson.build
index 19858a39..eb25b9cc 100644
--- a/extensions/workspace-indicator/meson.build
+++ b/extensions/workspace-indicator/meson.build
@@ -5,4 +5,4 @@ extension_data += configure_file(
)
extension_data += files('stylesheet.css')
-extension_sources += files('prefs.js')
+extension_sources += files('prefs.js', 'workspaceIndicator.js')
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
new file mode 100644
index 00000000..83a0dffa
--- /dev/null
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -0,0 +1,443 @@
+const { Clutter, Gio, GObject, Meta, St } = imports.gi;
+
+const DND = imports.ui.dnd;
+const Main = imports.ui.main;
+const PanelMenu = imports.ui.panelMenu;
+const PopupMenu = imports.ui.popupMenu;
+const Tweener = imports.ui.tweener;
+
+const Gettext = imports.gettext.domain('gnome-shell-extensions');
+const _ = Gettext.gettext;
+
+const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
+const WORKSPACE_KEY = 'workspace-names';
+
+const TOOLTIP_OFFSET = 6;
+const TOOLTIP_ANIMATION_TIME = 150;
+
+let WindowPreview = GObject.registerClass({
+ GTypeName: 'WorkspaceIndicatorWindowPreview'
+}, class WindowPreview extends St.Button {
+ _init(window) {
+ super._init({
+ style_class: 'workspace-indicator-window-preview'
+ });
+
+ this._delegate = this;
+ DND.makeDraggable(this, { restoreOnSuccess: true });
+
+ this._window = window;
+
+ this.connect('destroy', this._onDestroy.bind(this));
+
+ this._sizeChangedId = this._window.connect('size-changed',
+ () => this.queue_relayout());
+ this._positionChangedId = this._window.connect('position-changed',
+ () => this.queue_relayout());
+ this._minimizedChangedId = this._window.connect('notify::minimized',
+ this._updateVisible.bind(this));
+ this._monitorEnteredId = global.display.connect('window-entered-monitor',
+ this._updateVisible.bind(this));
+ this._monitorLeftId = global.display.connect('window-left-monitor',
+ this._updateVisible.bind(this));
+
+ this._focusChangedId = global.display.connect('notify::focus-window',
+ this._onFocusChanged.bind(this));
+ this._onFocusChanged();
+ }
+
+ // needed for DND
+ get realWindow() {
+ return this._window.get_compositor_private();
+ }
+
+ get metaWindow() {
+ return this._window;
+ }
+
+ _onDestroy() {
+ this._window.disconnect(this._sizeChangedId);
+ this._window.disconnect(this._positionChangedId);
+ this._window.disconnect(this._minimizedChangedId);
+ global.display.disconnect(this._monitorEnteredId);
+ global.display.disconnect(this._monitorLeftId);
+ global.display.disconnect(this._focusChangedId);
+ }
+
+ _onFocusChanged() {
+ if (global.display.focus_window == this._window)
+ this.add_style_class_name('active');
+ else
+ this.remove_style_class_name('active');
+ }
+
+ _updateVisible() {
+ let monitor = Main.layoutManager.findIndexForActor(this);
+ this.visible = monitor == this._window.get_monitor() &&
+ this._window.showing_on_its_workspace();
+ }
+});
+
+let WorkspaceLayout = GObject.registerClass(
+class WorkspaceLayout extends Clutter.LayoutManager {
+ vfunc_get_preferred_width() {
+ return [0, 0];
+ }
+
+ vfunc_get_preferred_height() {
+ return [0, 0];
+ }
+
+ vfunc_allocate(container, box, flags) {
+ const monitor = Main.layoutManager.findIndexForActor(container);
+ const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
+ const hscale = box.get_width() / workArea.width;
+ const vscale = box.get_height() / workArea.height;
+
+ for (const child of container.get_children()) {
+ const childBox = new Clutter.ActorBox();
+ const frameRect = child.metaWindow.get_frame_rect();
+ childBox.set_size(
+ Math.min(frameRect.width, workArea.width) * hscale,
+ Math.min(frameRect.height, workArea.height) * vscale);
+ childBox.set_origin(
+ Math.round(frameRect.x * hscale),
+ Math.round(frameRect.y * vscale));
+ child.allocate(childBox, flags);
+ }
+ }
+});
+
+let WorkspaceThumbnail = GObject.registerClass({
+ GTypeName: 'WorkspaceIndicatorWorkspaceThumbnail'
+}, class WorkspaceThumbnail extends St.Button {
+ _init(index) {
+ super._init({
+ style_class: 'workspace',
+ child: new Clutter.Actor({
+ layout_manager: new WorkspaceLayout(),
+ clip_to_allocation: true
+ }),
+ x_fill: true,
+ y_fill: true
+ });
+
+ this._tooltip = new St.Label({
+ style_class: 'dash-label',
+ visible: false,
+ });
+ Main.uiGroup.add_child(this._tooltip);
+
+ this.connect('destroy', this._onDestroy.bind(this));
+ this.connect('notify::hover', this._syncTooltip.bind(this));
+
+ this._index = index;
+ this._delegate = this; // needed for DND
+
+ this._windowPreviews = new Map();
+
+ let workspaceManager = global.workspace_manager;
+ this._workspace = workspaceManager.get_workspace_by_index(index);
+
+ this._windowAddedId = this._workspace.connect('window-added',
+ (ws, window) => {
+ this._addWindow(window);
+ });
+ this._windowRemovedId = this._workspace.connect('window-removed',
+ (ws, window) => {
+ this._removeWindow(window);
+ });
+ this._restackedId = global.display.connect('restacked',
+ this._onRestacked.bind(this));
+
+ this._workspace.list_windows().forEach(w => this._addWindow(w));
+ this._onRestacked();
+ }
+
+ acceptDrop(source) {
+ if (!source.realWindow)
+ return false;
+
+ let window = source.realWindow.get_meta_window();
+ this._moveWindow(window);
+ return true;
+ }
+
+ handleDragOver(source) {
+ if (source.realWindow)
+ return DND.DragMotionResult.MOVE_DROP;
+ else
+ return DND.DragMotionResult.CONTINUE;
+ }
+
+ _addWindow(window) {
+ if (this._windowPreviews.has(window))
+ return;
+
+ let preview = new WindowPreview(window);
+ preview.connect('clicked', (a, btn) => this.emit('clicked', btn));
+ this._windowPreviews.set(window, preview);
+ this.child.add_child(preview);
+ }
+
+ _removeWindow(window) {
+ let preview = this._windowPreviews.get(window);
+ if (!preview)
+ return;
+
+ this._windowPreviews.delete(window);
+ preview.destroy();
+ }
+
+ _onRestacked() {
+ let lastPreview = null;
+ let windows = global.get_window_actors().map(a => a.meta_window);
+ for (let i = 0; i < windows.length; i++) {
+ let preview = this._windowPreviews.get(windows[i]);
+ if (!preview)
+ continue;
+
+ this.child.set_child_above_sibling(preview, lastPreview);
+ lastPreview = preview;
+ }
+ }
+
+ _moveWindow(window) {
+ let monitorIndex = Main.layoutManager.findIndexForActor(this);
+ if (monitorIndex != window.get_monitor())
+ window.move_to_monitor(monitorIndex);
+ window.change_workspace_by_index(this._index, false);
+ }
+
+ // eslint-disable-next-line camelcase
+ on_clicked() {
+ let ws = global.workspace_manager.get_workspace_by_index(this._index);
+ if (ws)
+ ws.activate(global.get_current_time());
+ }
+
+ _syncTooltip() {
+ if (this.hover) {
+ this._tooltip.text = Meta.prefs_get_workspace_name(this._index);
+ this._tooltip.opacity = 0;
+ this._tooltip.show();
+
+ const [stageX, stageY] = this.get_transformed_position();
+ const thumbWidth = this.allocation.get_width();
+ const thumbHeight = this.allocation.get_height();
+ const tipWidth = this._tooltip.width;
+ const xOffset = Math.floor((thumbWidth - tipWidth) / 2);
+ const monitor = Main.layoutManager.findMonitorForActor(this);
+ const x = Math.min(
+ Math.max(stageX + xOffset, monitor.x),
+ monitor.x + monitor.width - tipWidth);
+ const y = stageY + thumbHeight + TOOLTIP_OFFSET;
+ this._tooltip.set_position(x, y);
+ }
+
+ Tweener.addTween(this._tooltip, {
+ opacity: this.hover ? 255 : 0,
+ time: TOOLTIP_ANIMATION_TIME / 1000,
+ transition: 'easeOutQuad',
+ onComplete: () => (this._tooltip.visible = this.hover),
+ });
+ }
+
+ _onDestroy() {
+ this._tooltip.destroy();
+
+ this._workspace.disconnect(this._windowAddedId);
+ this._workspace.disconnect(this._windowRemovedId);
+ global.display.disconnect(this._restackedId);
+ }
+});
+
+let WorkspaceIndicator = GObject.registerClass(
+class WorkspaceIndicator extends PanelMenu.Button {
+ _init() {
+ super._init(0.0, _('Workspace Indicator'));
+
+ let container = new St.Widget({
+ layout_manager: new Clutter.BinLayout(),
+ x_expand: true,
+ y_expand: true
+ });
+ this.add_actor(container);
+
+ let workspaceManager = global.workspace_manager;
+
+ this._currentWorkspace = workspaceManager.get_active_workspace_index();
+ this._statusLabel = new St.Label({
+ style_class: 'panel-workspace-indicator',
+ y_align: Clutter.ActorAlign.CENTER,
+ text: this._labelText()
+ });
+
+ container.add_actor(this._statusLabel);
+
+ this._thumbnailsBox = new St.BoxLayout({
+ style_class: 'panel-workspace-indicator-box',
+ y_expand: true,
+ reactive: true
+ });
+
+ container.add_actor(this._thumbnailsBox);
+
+ this._workspacesItems = [];
+ this._workspaceSection = new PopupMenu.PopupMenuSection();
+ this.menu.addMenuItem(this._workspaceSection);
+
+ this._workspaceManagerSignals = [
+ workspaceManager.connect_after('notify::n-workspaces',
+ this._nWorkspacesChanged.bind(this)),
+ workspaceManager.connect_after('workspace-switched',
+ this._onWorkspaceSwitched.bind(this)),
+ workspaceManager.connect('notify::layout-rows',
+ this._onWorkspaceOrientationChanged.bind(this))
+ ];
+
+ this.connect('scroll-event', this._onScrollEvent.bind(this));
+ this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
+ this._createWorkspacesSection();
+ this._updateThumbnails();
+ this._onWorkspaceOrientationChanged();
+
+ this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA });
+ this._settingsChangedId = this._settings.connect(
+ `changed::${WORKSPACE_KEY}`,
+ this._updateMenuLabels.bind(this));
+ }
+
+ _onDestroy() {
+ for (let i = 0; i < this._workspaceManagerSignals.length; i++)
+ global.workspace_manager.disconnect(this._workspaceManagerSignals[i]);
+
+ if (this._settingsChangedId) {
+ this._settings.disconnect(this._settingsChangedId);
+ this._settingsChangedId = 0;
+ }
+
+ Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
+
+ super._onDestroy();
+ }
+
+ _onWorkspaceOrientationChanged() {
+ let vertical = global.workspace_manager.layout_rows == -1;
+ this.reactive = vertical;
+
+ this._statusLabel.visible = vertical;
+ this._thumbnailsBox.visible = !vertical;
+
+ // Disable offscreen-redirect when showing the workspace switcher
+ // so that clip-to-allocation works
+ Main.panel.set_offscreen_redirect(vertical
+ ? Clutter.OffscreenRedirect.ALWAYS
+ : Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY);
+ }
+
+ _onWorkspaceSwitched() {
+ this._currentWorkspace = global.workspace_manager.get_active_workspace_index();
+
+ this._updateMenuOrnament();
+ this._updateActiveThumbnail();
+
+ this._statusLabel.set_text(this._labelText());
+ }
+
+ _nWorkspacesChanged() {
+ this._createWorkspacesSection();
+ this._updateThumbnails();
+ }
+
+ _updateMenuOrnament() {
+ for (let i = 0; i < this._workspacesItems.length; i++) {
+ this._workspacesItems[i].setOrnament(i == this._currentWorkspace
+ ? PopupMenu.Ornament.DOT
+ : PopupMenu.Ornament.NONE);
+ }
+ }
+
+ _updateActiveThumbnail() {
+ let thumbs = this._thumbnailsBox.get_children();
+ for (let i = 0; i < thumbs.length; i++) {
+ if (i == this._currentWorkspace)
+ thumbs[i].add_style_class_name('active');
+ else
+ thumbs[i].remove_style_class_name('active');
+ }
+ }
+
+ _labelText(workspaceIndex) {
+ if (workspaceIndex == undefined) {
+ workspaceIndex = this._currentWorkspace;
+ return (workspaceIndex + 1).toString();
+ }
+ return Meta.prefs_get_workspace_name(workspaceIndex);
+ }
+
+ _updateMenuLabels() {
+ for (let i = 0; i < this._workspacesItems.length; i++)
+ this._workspacesItems[i].label.text = this._labelText(i);
+ }
+
+ _createWorkspacesSection() {
+ let workspaceManager = global.workspace_manager;
+
+ this._workspaceSection.removeAll();
+ this._workspacesItems = [];
+ this._currentWorkspace = workspaceManager.get_active_workspace_index();
+
+ let i = 0;
+ for (; i < workspaceManager.n_workspaces; i++) {
+ this._workspacesItems[i] = new PopupMenu.PopupMenuItem(this._labelText(i));
+ this._workspaceSection.addMenuItem(this._workspacesItems[i]);
+ this._workspacesItems[i].workspaceId = i;
+ this._workspacesItems[i].label_actor = this._statusLabel;
+ this._workspacesItems[i].connect('activate', (actor, _event) => {
+ this._activate(actor.workspaceId);
+ });
+
+ if (i == this._currentWorkspace)
+ this._workspacesItems[i].setOrnament(PopupMenu.Ornament.DOT);
+ }
+
+ this._statusLabel.set_text(this._labelText());
+ }
+
+ _updateThumbnails() {
+ let workspaceManager = global.workspace_manager;
+
+ this._thumbnailsBox.destroy_all_children();
+
+ for (let i = 0; i < workspaceManager.n_workspaces; i++) {
+ let thumb = new WorkspaceThumbnail(i);
+ this._thumbnailsBox.add_actor(thumb);
+ }
+ this._updateActiveThumbnail();
+ }
+
+ _activate(index) {
+ let workspaceManager = global.workspace_manager;
+
+ if (index >= 0 && index < workspaceManager.n_workspaces) {
+ let metaWorkspace = workspaceManager.get_workspace_by_index(index);
+ metaWorkspace.activate(global.get_current_time());
+ }
+ }
+
+ _onScrollEvent(actor, event) {
+ let direction = event.get_scroll_direction();
+ let diff = 0;
+ if (direction == Clutter.ScrollDirection.DOWN) {
+ diff = 1;
+ } else if (direction == Clutter.ScrollDirection.UP) {
+ diff = -1;
+ } else {
+ return;
+ }
+
+ let newIndex = global.workspace_manager.get_active_workspace_index() + diff;
+ this._activate(newIndex);
+ }
+});
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 55f0e9aa..5cdb710f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -18,5 +18,5 @@ extensions/window-list/extension.js
extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml
extensions/window-list/prefs.js
extensions/windowsNavigator/extension.js
-extensions/workspace-indicator/extension.js
extensions/workspace-indicator/prefs.js
+extensions/workspace-indicator/workspaceIndicator.js
--
2.50.0
From dd928d44f1fbc1536c4ae30bad2130c1fc4432ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 19:09:38 +0100
Subject: [PATCH 04/43] workspace-indicator: Use descendant style selectors
Add a style class to the indicator itself, and only select
descendant elements. This allows using the briefer class names
from the window-list extension without too much risk of conflicts.
---
extensions/workspace-indicator/stylesheet.css | 32 +++++++------------
.../workspace-indicator/workspaceIndicator.js | 6 ++--
2 files changed, 16 insertions(+), 22 deletions(-)
diff --git a/extensions/workspace-indicator/stylesheet.css b/extensions/workspace-indicator/stylesheet.css
index 8c101e79..3f89359b 100644
--- a/extensions/workspace-indicator/stylesheet.css
+++ b/extensions/workspace-indicator/stylesheet.css
@@ -1,29 +1,21 @@
-.panel-workspace-indicator {
- padding: 0 8px;
- border: 1px solid #cccccc;
+.workspace-indicator .status-label {
+ padding: 0 8px;
}
-.panel-workspace-indicator-box {
- padding: 2px 0;
+.workspace-indicator .workspaces-box {
+ padding: 4px 0;
+ spacing: 4px;
}
-.panel-workspace-indicator-box .workspace {
- border: 1px solid #cccccc;
- width: 48px;
+.workspace-indicator .workspace {
+ width: 40px;
+ border: 2px solid #000;
+ border-radius: 2px;
+ background-color: #595959;
}
-.panel-workspace-indicator,
-.panel-workspace-indicator-box .workspace.active {
- background-color: rgba(200, 200, 200, .5);
-}
-
-.panel-workspace-indicator-box .workspace {
- background-color: rgba(200, 200, 200, .3);
- border-left-width: 0;
-}
-
-.panel-workspace-indicator-box .workspace:first-child {
- border-left-width: 1px;
+.workspace-indicator .workspace.active {
+ border-color: #fff;
}
.workspace-indicator-window-preview {
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 83a0dffa..2b102117 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -257,6 +257,8 @@ class WorkspaceIndicator extends PanelMenu.Button {
_init() {
super._init(0.0, _('Workspace Indicator'));
+ this.add_style_class_name('workspace-indicator');
+
let container = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_expand: true,
@@ -268,7 +270,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._currentWorkspace = workspaceManager.get_active_workspace_index();
this._statusLabel = new St.Label({
- style_class: 'panel-workspace-indicator',
+ style_class: 'status-label',
y_align: Clutter.ActorAlign.CENTER,
text: this._labelText()
});
@@ -276,7 +278,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
container.add_actor(this._statusLabel);
this._thumbnailsBox = new St.BoxLayout({
- style_class: 'panel-workspace-indicator-box',
+ style_class: 'workspaces-box',
y_expand: true,
reactive: true
});
--
2.50.0
From 9a92b49c1835e44b5f3ddf2088f24cf3dd82b8c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 12:48:43 +0100
Subject: [PATCH 05/43] window-list: Use consistent style class prefix
This will eventually allow us to re-use the workspace-indicator
extension without changing anything but the used prefix.
---
extensions/window-list/classic.css | 4 ++--
extensions/window-list/stylesheet.css | 11 +++++------
extensions/window-list/workspaceIndicator.js | 2 +-
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css
index 7079d3ef..02286041 100644
--- a/extensions/window-list/classic.css
+++ b/extensions/window-list/classic.css
@@ -57,12 +57,12 @@
background-color: #ccc;
}
-.window-list-window-preview {
+.window-list-workspace-indicator-window-preview {
background-color: #ededed;
border: 1px solid #ccc;
}
-.window-list-window-preview.active {
+.window-list-workspace-indicator-window-preview.active {
background-color: #f6f5f4;
border: 2px solid #888;
}
diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css
index 2c98aafe..4c9ca671 100644
--- a/extensions/window-list/stylesheet.css
+++ b/extensions/window-list/stylesheet.css
@@ -121,14 +121,13 @@
background-color: rgba(200, 200, 200, .3);
}
-.window-list-window-preview {
- background-color: #252525;
- border: 1px solid #ccc;
+.window-list-workspace-indicator-window-preview {
+ background-color: #bebebe;
+ border: 1px solid #828282;
}
-.window-list-window-preview.active {
- background-color: #353535;
- border: 2px solid #ccc;
+.window-list-workspace-indicator-window-preview.active {
+ background-color: #d4d4d4;
}
.notification {
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
index 8ae9b288..4e8f1aff 100644
--- a/extensions/window-list/workspaceIndicator.js
+++ b/extensions/window-list/workspaceIndicator.js
@@ -18,7 +18,7 @@ let WindowPreview = GObject.registerClass({
}, class WindowPreview extends St.Button {
_init(window) {
super._init({
- style_class: 'window-list-window-preview'
+ style_class: 'window-list-workspace-indicator-window-preview',
});
this._delegate = this;
--
2.50.0
From 6db2bc97a0aba60650abff4e82a1b5683db474c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 23 Feb 2024 01:59:15 +0100
Subject: [PATCH 06/43] workspace-indicator: Allow overriding base style class
This will allow reusing the code from the window-list extension
without limiting the ability to specify styling that only applies
to one of the extensions.
---
.../workspace-indicator/workspaceIndicator.js | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 2b102117..57a3f7ec 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -15,12 +15,14 @@ const WORKSPACE_KEY = 'workspace-names';
const TOOLTIP_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150;
+let baseStyleClassName = '';
+
let WindowPreview = GObject.registerClass({
GTypeName: 'WorkspaceIndicatorWindowPreview'
}, class WindowPreview extends St.Button {
_init(window) {
super._init({
- style_class: 'workspace-indicator-window-preview'
+ style_class: `${baseStyleClassName}-window-preview`,
});
this._delegate = this;
@@ -254,10 +256,15 @@ let WorkspaceThumbnail = GObject.registerClass({
let WorkspaceIndicator = GObject.registerClass(
class WorkspaceIndicator extends PanelMenu.Button {
- _init() {
+ _init(params = {}) {
super._init(0.0, _('Workspace Indicator'));
- this.add_style_class_name('workspace-indicator');
+ const {
+ baseStyleClass = 'workspace-indicator',
+ } = params;
+
+ baseStyleClassName = baseStyleClass;
+ this.add_style_class_name(baseStyleClassName);
let container = new St.Widget({
layout_manager: new Clutter.BinLayout(),
--
2.50.0
From 8f4cc8742093a791bf64470ea2e04b18c37a59e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 11 Jul 2025 12:09:18 +0200
Subject: [PATCH 07/43] workspace-indicator: Support prefix for GType names
GTypes have to be unique, so to allow the code to be eventually
shared with the window-list extension, support adding a custom
prefix to type names.
---
.../workspace-indicator/workspaceIndicator.js | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 57a3f7ec..2a026c5d 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -17,8 +17,10 @@ const TOOLTIP_ANIMATION_TIME = 150;
let baseStyleClassName = '';
+const TypePrefix = window.TypePrefix || '';
+
let WindowPreview = GObject.registerClass({
- GTypeName: 'WorkspaceIndicatorWindowPreview'
+ GTypeName: `${TypePrefix}WorkspaceIndicatorWindowPreview`
}, class WindowPreview extends St.Button {
_init(window) {
super._init({
@@ -80,8 +82,9 @@ let WindowPreview = GObject.registerClass({
}
});
-let WorkspaceLayout = GObject.registerClass(
-class WorkspaceLayout extends Clutter.LayoutManager {
+let WorkspaceLayout = GObject.registerClass({
+ GTypeName: `${TypePrefix}WorkspaceIndicatorWorkspaceLayout`
+}, class WorkspaceLayout extends Clutter.LayoutManager {
vfunc_get_preferred_width() {
return [0, 0];
}
@@ -111,7 +114,7 @@ class WorkspaceLayout extends Clutter.LayoutManager {
});
let WorkspaceThumbnail = GObject.registerClass({
- GTypeName: 'WorkspaceIndicatorWorkspaceThumbnail'
+ GTypeName: `${TypePrefix}WorkspaceIndicatorWorkspaceThumbnail`
}, class WorkspaceThumbnail extends St.Button {
_init(index) {
super._init({
@@ -254,8 +257,9 @@ let WorkspaceThumbnail = GObject.registerClass({
}
});
-let WorkspaceIndicator = GObject.registerClass(
-class WorkspaceIndicator extends PanelMenu.Button {
+let WorkspaceIndicator = GObject.registerClass({
+ GTypeName: `${TypePrefix}WorkspaceIndicator`
+}, class WorkspaceIndicator extends PanelMenu.Button {
_init(params = {}) {
super._init(0.0, _('Workspace Indicator'));
--
2.50.0
From 09116b6f8e6477c4347fec0f035e74d508b08288 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 23 Feb 2024 01:58:50 +0100
Subject: [PATCH 08/43] window-list: Override base style class
Apply the changes from the last commit to the workspace-indicator
copy, and override the base style class from the extension.
This will eventually allow us to share the exact same code between
the two extensions, but still use individual styling if necessary.
---
extensions/window-list/extension.js | 4 +++-
extensions/window-list/workspaceIndicator.js | 15 ++++++++++++---
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 11ac393b..e1bbc0de 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -813,7 +813,9 @@ class WindowList {
let indicatorsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.END });
box.add(indicatorsBox);
- this._workspaceIndicator = new WorkspaceIndicator();
+ this._workspaceIndicator = new WorkspaceIndicator({
+ baseStyleClass: 'window-list-workspace-indicator',
+ });
indicatorsBox.add(this._workspaceIndicator.container, { expand: false, y_fill: true });
this._mutterSettings = new Gio.Settings({ schema_id: 'org.gnome.mutter' });
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
index 4e8f1aff..48a8eb22 100644
--- a/extensions/window-list/workspaceIndicator.js
+++ b/extensions/window-list/workspaceIndicator.js
@@ -13,12 +13,14 @@ const _ = Gettext.gettext;
const TOOLTIP_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150;
+let baseStyleClassName = '';
+
let WindowPreview = GObject.registerClass({
GTypeName: 'WindowListWindowPreview'
}, class WindowPreview extends St.Button {
_init(window) {
super._init({
- style_class: 'window-list-workspace-indicator-window-preview',
+ style_class: `${baseStyleClassName}-window-preview`,
});
this._delegate = this;
@@ -248,10 +250,17 @@ let WorkspaceThumbnail = GObject.registerClass({
var WorkspaceIndicator = GObject.registerClass({
GTypeName: 'WindowListWorkspaceIndicator'
}, class WorkspaceIndicator extends PanelMenu.Button {
- _init() {
+ _init(params = {}) {
super._init(0.0, _('Workspace Indicator'), true);
+
+ const {
+ baseStyleClass = 'workspace-indicator',
+ } = params;
+
+ baseStyleClassName = baseStyleClass;
+ this.add_style_class_name(baseStyleClassName);
+
this.setMenu(new PopupMenu.PopupMenu(this, 0.0, St.Side.BOTTOM));
- this.add_style_class_name('window-list-workspace-indicator');
this.menu.actor.remove_style_class_name('panel-menu');
let container = new St.Widget({
--
2.50.0
From 86b017644c4a7cb394558f4b96785957aef480ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 11 Jul 2025 12:29:50 +0200
Subject: [PATCH 09/43] window-list: Set TypePrefix for GType names
Apply the changes from the last commit to the workspace-indicator
copy, and set the type prefix from the extension.
This will eventually allow us to share the exact same code between
the two extensions, without creating conflicting GTypes.
---
extensions/window-list/extension.js | 3 +++
extensions/window-list/workspaceIndicator.js | 8 +++++---
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index e1bbc0de..ed886919 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -10,7 +10,10 @@ const Tweener = imports.ui.tweener;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const { WindowPicker, WindowPickerToggle } = Me.imports.windowPicker;
+
+window.TypePrefix = 'WindowList';
const { WorkspaceIndicator } = Me.imports.workspaceIndicator;
+delete window.TypePrefix;
const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
index 48a8eb22..c362539e 100644
--- a/extensions/window-list/workspaceIndicator.js
+++ b/extensions/window-list/workspaceIndicator.js
@@ -15,8 +15,10 @@ const TOOLTIP_ANIMATION_TIME = 150;
let baseStyleClassName = '';
+const TypePrefix = window.TypePrefix || '';
+
let WindowPreview = GObject.registerClass({
- GTypeName: 'WindowListWindowPreview'
+ GTypeName: `${TypePrefix}WorkspaceIndicatorWindowPreview`
}, class WindowPreview extends St.Button {
_init(window) {
super._init({
@@ -104,7 +106,7 @@ let WindowPreview = GObject.registerClass({
});
let WorkspaceThumbnail = GObject.registerClass({
- GTypeName: 'WindowListWorkspaceThumbnail'
+ GTypeName: `${TypePrefix}WorkspaceIndicatorWorkspaceThumbnail`
}, class WorkspaceThumbnail extends St.Button {
_init(index) {
super._init({
@@ -248,7 +250,7 @@ let WorkspaceThumbnail = GObject.registerClass({
});
var WorkspaceIndicator = GObject.registerClass({
- GTypeName: 'WindowListWorkspaceIndicator'
+ GTypeName: `${TypePrefix}WorkspaceIndicator`
}, class WorkspaceIndicator extends PanelMenu.Button {
_init(params = {}) {
super._init(0.0, _('Workspace Indicator'), true);
--
2.50.0
From e0d18355ae3af843bc35412f4379d26af0a9ddcd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 12:48:43 +0100
Subject: [PATCH 10/43] window-list: Externally adjust workspace menu
In order to use a PanelMenu.Button in the bottom bar, we have
to tweak its menu a bit.
We currently handle this inside the indicator, but that means the
code diverges from the original code in the workspace-indicator
extension.
Avoid this by using a small subclass that handles the adjustments.
---
extensions/window-list/extension.js | 23 ++++++++++++++++++--
extensions/window-list/workspaceIndicator.js | 5 +----
2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index ed886919..394fec1f 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -1,5 +1,5 @@
/* exported init */
-const { Clutter, Gio, GLib, Gtk, Meta, Shell, St } = imports.gi;
+const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St } = imports.gi;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
@@ -816,7 +816,7 @@ class WindowList {
let indicatorsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.END });
box.add(indicatorsBox);
- this._workspaceIndicator = new WorkspaceIndicator({
+ this._workspaceIndicator = new BottomWorkspaceIndicator({
baseStyleClass: 'window-list-workspace-indicator',
});
indicatorsBox.add(this._workspaceIndicator.container, { expand: false, y_fill: true });
@@ -1226,6 +1226,25 @@ class WindowList {
}
}
+const BottomWorkspaceIndicator = GObject.registerClass(
+class BottomWorkspaceIndicator extends WorkspaceIndicator {
+ _init(params) {
+ super._init(params);
+
+ this.remove_style_class_name('panel-button');
+ }
+
+ setMenu(menu) {
+ super.setMenu(menu);
+
+ if (!menu)
+ return;
+
+ this.menu.actor.updateArrowSide(St.Side.BOTTOM);
+ this.menu.actor.remove_style_class_name('panel-menu');
+ }
+});
+
class Extension {
constructor() {
this._windowLists = null;
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
index c362539e..574ebdca 100644
--- a/extensions/window-list/workspaceIndicator.js
+++ b/extensions/window-list/workspaceIndicator.js
@@ -253,7 +253,7 @@ var WorkspaceIndicator = GObject.registerClass({
GTypeName: `${TypePrefix}WorkspaceIndicator`
}, class WorkspaceIndicator extends PanelMenu.Button {
_init(params = {}) {
- super._init(0.0, _('Workspace Indicator'), true);
+ super._init(0.0, _('Workspace Indicator'));
const {
baseStyleClass = 'workspace-indicator',
@@ -262,9 +262,6 @@ var WorkspaceIndicator = GObject.registerClass({
baseStyleClassName = baseStyleClass;
this.add_style_class_name(baseStyleClassName);
- this.setMenu(new PopupMenu.PopupMenu(this, 0.0, St.Side.BOTTOM));
- this.menu.actor.remove_style_class_name('panel-menu');
-
let container = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_expand: true,
--
2.50.0
From e3b79e9d113570a89227cd7cb598e20fe61c9bd0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 21 Mar 2024 16:49:35 +0100
Subject: [PATCH 11/43] window-list: Handle changes to workspace menu
For now the menu is always set at construction time, however this
will change in the future. Prepare for that by handling the
`menu-set` signal, similar to the top bar.
---
extensions/window-list/extension.js | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 394fec1f..aada9525 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -831,7 +831,9 @@ class WindowList {
this._updateWorkspaceIndicatorVisibility();
this._menuManager = new PopupMenu.PopupMenuManager(this);
- this._menuManager.addMenu(this._workspaceIndicator.menu);
+ this._workspaceIndicator.connect('menu-set',
+ () => this._onWorkspaceMenuSet());
+ this._onWorkspaceMenuSet();
Main.layoutManager.addChrome(this.actor, {
affectsStruts: true,
@@ -931,6 +933,11 @@ class WindowList {
children[newActive].activate();
}
+ _onWorkspaceMenuSet() {
+ if (this._workspaceIndicator.menu)
+ this._menuManager.addMenu(this._workspaceIndicator.menu);
+ }
+
_updatePosition() {
this.actor.set_position(this._monitor.x,
this._monitor.y + this._monitor.height - this.actor.height);
--
2.50.0
From c8bf13f4e85c1e90535588234a68e66068d02805 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 15:58:39 +0100
Subject: [PATCH 12/43] workspace-indicator: Don't use SCHEMA/KEY constants
Each constant is only used once, so all they do is disconnect
the actual value from the code that uses it.
The copy in the window-list extension just uses the strings directly,
do the same here.
---
extensions/workspace-indicator/workspaceIndicator.js | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 2a026c5d..b1dfc970 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -9,9 +9,6 @@ const Tweener = imports.ui.tweener;
const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
-const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
-const WORKSPACE_KEY = 'workspace-names';
-
const TOOLTIP_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150;
@@ -315,9 +312,9 @@ let WorkspaceIndicator = GObject.registerClass({
this._updateThumbnails();
this._onWorkspaceOrientationChanged();
- this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA });
+ this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' });
this._settingsChangedId = this._settings.connect(
- `changed::${WORKSPACE_KEY}`,
+ 'changed::workspace-names',
this._updateMenuLabels.bind(this));
}
--
2.50.0
From dbb82cf4778e324defa564584badc136c4f54448 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 18:59:23 +0100
Subject: [PATCH 13/43] workspace-indicator: Use existing property
We already track the current workspace index, use that
instead of getting it from the workspace manager again.
---
extensions/workspace-indicator/workspaceIndicator.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index b1dfc970..7177a810 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -447,7 +447,7 @@ let WorkspaceIndicator = GObject.registerClass({
return;
}
- let newIndex = global.workspace_manager.get_active_workspace_index() + diff;
+ const newIndex = this._currentWorkspace + diff;
this._activate(newIndex);
}
});
--
2.50.0
From c929efb231745e4e66182a9ee08c5cef2725e9d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 16:14:24 +0100
Subject: [PATCH 14/43] workspace-indicator: Don't use menu section
We never added anything else to the menu, so we can just operate
on the entire menu instead of an intermediate section.
This removes another difference with the window-list copy.
---
extensions/workspace-indicator/workspaceIndicator.js | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 7177a810..9563bbc1 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -294,8 +294,6 @@ let WorkspaceIndicator = GObject.registerClass({
container.add_actor(this._thumbnailsBox);
this._workspacesItems = [];
- this._workspaceSection = new PopupMenu.PopupMenuSection();
- this.menu.addMenuItem(this._workspaceSection);
this._workspaceManagerSignals = [
workspaceManager.connect_after('notify::n-workspaces',
@@ -308,7 +306,7 @@ let WorkspaceIndicator = GObject.registerClass({
this.connect('scroll-event', this._onScrollEvent.bind(this));
this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
- this._createWorkspacesSection();
+ this._updateMenu();
this._updateThumbnails();
this._onWorkspaceOrientationChanged();
@@ -356,7 +354,7 @@ let WorkspaceIndicator = GObject.registerClass({
}
_nWorkspacesChanged() {
- this._createWorkspacesSection();
+ this._updateMenu();
this._updateThumbnails();
}
@@ -391,17 +389,17 @@ let WorkspaceIndicator = GObject.registerClass({
this._workspacesItems[i].label.text = this._labelText(i);
}
- _createWorkspacesSection() {
+ _updateMenu() {
let workspaceManager = global.workspace_manager;
- this._workspaceSection.removeAll();
+ this.menu.removeAll();
this._workspacesItems = [];
this._currentWorkspace = workspaceManager.get_active_workspace_index();
let i = 0;
for (; i < workspaceManager.n_workspaces; i++) {
this._workspacesItems[i] = new PopupMenu.PopupMenuItem(this._labelText(i));
- this._workspaceSection.addMenuItem(this._workspacesItems[i]);
+ this.menu.addMenuItem(this._workspacesItems[i]);
this._workspacesItems[i].workspaceId = i;
this._workspacesItems[i].label_actor = this._statusLabel;
this._workspacesItems[i].connect('activate', (actor, _event) => {
--
2.50.0
From 8d38e180ac3a6832185820589f5f4afa450f4cf1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 13:05:15 +0100
Subject: [PATCH 15/43] workspace-indicator: Support showing tooltips above
The indicator is located in the top bar, so tooltips are always
shown below the previews. However supporting showing tooltips
above previews when space permits allows the same code to be
used in the copy that is included with the window-list extension.
---
extensions/workspace-indicator/workspaceIndicator.js | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 9563bbc1..b87420ac 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -225,15 +225,16 @@ let WorkspaceThumbnail = GObject.registerClass({
this._tooltip.show();
const [stageX, stageY] = this.get_transformed_position();
- const thumbWidth = this.allocation.get_width();
- const thumbHeight = this.allocation.get_height();
- const tipWidth = this._tooltip.width;
+ const [thumbWidth, thumbHeight] = this.allocation.get_size();
+ const [tipWidth, tipHeight] = this._tooltip.get_size();
const xOffset = Math.floor((thumbWidth - tipWidth) / 2);
const monitor = Main.layoutManager.findMonitorForActor(this);
const x = Math.min(
Math.max(stageX + xOffset, monitor.x),
monitor.x + monitor.width - tipWidth);
- const y = stageY + thumbHeight + TOOLTIP_OFFSET;
+ const y = stageY - monitor.y > thumbHeight + TOOLTIP_OFFSET
+ ? stageY - tipHeight - TOOLTIP_OFFSET // show above
+ : stageY + thumbHeight + TOOLTIP_OFFSET; // show below
this._tooltip.set_position(x, y);
}
--
2.50.0
From a7d7412b8683e843db154c10fe9ffcd01b38d544 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 17:37:16 +0100
Subject: [PATCH 16/43] workspace-indicator: Only change top bar redirect when
in top bar
While this is always the case for the workspace indicator, adding
the check will allow to use the same code in the window list.
---
.../workspace-indicator/workspaceIndicator.js | 23 +++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index b87420ac..b772b66d 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -307,6 +307,16 @@ let WorkspaceIndicator = GObject.registerClass({
this.connect('scroll-event', this._onScrollEvent.bind(this));
this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
+
+ this._inTopBar = false;
+ this.connect('notify::realized', () => {
+ if (!this.realized)
+ return;
+
+ this._inTopBar = Main.panel.contains(this);
+ this._updateTopBarRedirect();
+ });
+
this._updateMenu();
this._updateThumbnails();
this._onWorkspaceOrientationChanged();
@@ -326,7 +336,9 @@ let WorkspaceIndicator = GObject.registerClass({
this._settingsChangedId = 0;
}
- Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
+ if (this._inTopBar)
+ Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
+ this._inTopBar = false;
super._onDestroy();
}
@@ -338,9 +350,16 @@ let WorkspaceIndicator = GObject.registerClass({
this._statusLabel.visible = vertical;
this._thumbnailsBox.visible = !vertical;
+ this._updateTopBarRedirect();
+ }
+
+ _updateTopBarRedirect() {
+ if (!this._inTopBar)
+ return;
+
// Disable offscreen-redirect when showing the workspace switcher
// so that clip-to-allocation works
- Main.panel.set_offscreen_redirect(vertical
+ Main.panel.set_offscreen_redirect(this._thumbnailsBox.visible
? Clutter.OffscreenRedirect.ALWAYS
: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY);
}
--
2.50.0
From e654fa6be51139099f6eaa13f28130a3da0fd556 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 16:13:00 +0100
Subject: [PATCH 17/43] workspace-indicator: Small cleanup
The code to update the menu labels is a bit cleaner in the
window-list extension, so use that.
---
.../workspace-indicator/workspaceIndicator.js | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index b772b66d..f707be79 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -416,18 +416,18 @@ let WorkspaceIndicator = GObject.registerClass({
this._workspacesItems = [];
this._currentWorkspace = workspaceManager.get_active_workspace_index();
- let i = 0;
- for (; i < workspaceManager.n_workspaces; i++) {
- this._workspacesItems[i] = new PopupMenu.PopupMenuItem(this._labelText(i));
- this.menu.addMenuItem(this._workspacesItems[i]);
- this._workspacesItems[i].workspaceId = i;
- this._workspacesItems[i].label_actor = this._statusLabel;
- this._workspacesItems[i].connect('activate', (actor, _event) => {
- this._activate(actor.workspaceId);
- });
+ for (let i = 0; i < workspaceManager.n_workspaces; i++) {
+ const item = new PopupMenu.PopupMenuItem(this._labelText(i));
- if (i == this._currentWorkspace)
- this._workspacesItems[i].setOrnament(PopupMenu.Ornament.DOT);
+ item.connect('activate',
+ () => this._activate(i));
+
+ item.setOrnament(i === this._currentWorkspace
+ ? PopupMenu.Ornament.DOT
+ : PopupMenu.Ornament.NONE);
+
+ this.menu.addMenuItem(item);
+ this._workspacesItems[i] = item;
}
this._statusLabel.set_text(this._labelText());
--
2.50.0
From 3db67516e6bc00f2b9c85aa59b28d9521028fbc9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 16:13:00 +0100
Subject: [PATCH 18/43] workspace-indicator: Simplify getting status text
Currently the same method is used to get the label text for the
indicator itself and for the menu items.
A method that behaves significantly different depending on whether
a parameter is passed is confusing, so only deal with the indicator
label and directly use the mutter API to get the workspace names
for menu items.
---
.../workspace-indicator/workspaceIndicator.js | 24 +++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index f707be79..6783b315 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -281,7 +281,7 @@ let WorkspaceIndicator = GObject.registerClass({
this._statusLabel = new St.Label({
style_class: 'status-label',
y_align: Clutter.ActorAlign.CENTER,
- text: this._labelText()
+ text: this._getStatusText(),
});
container.add_actor(this._statusLabel);
@@ -370,7 +370,7 @@ let WorkspaceIndicator = GObject.registerClass({
this._updateMenuOrnament();
this._updateActiveThumbnail();
- this._statusLabel.set_text(this._labelText());
+ this._statusLabel.set_text(this._getStatusText());
}
_nWorkspacesChanged() {
@@ -396,17 +396,16 @@ let WorkspaceIndicator = GObject.registerClass({
}
}
- _labelText(workspaceIndex) {
- if (workspaceIndex == undefined) {
- workspaceIndex = this._currentWorkspace;
- return (workspaceIndex + 1).toString();
- }
- return Meta.prefs_get_workspace_name(workspaceIndex);
+ _getStatusText() {
+ const current = this._currentWorkspace + 1;
+ return `${current}`;
}
_updateMenuLabels() {
- for (let i = 0; i < this._workspacesItems.length; i++)
- this._workspacesItems[i].label.text = this._labelText(i);
+ for (let i = 0; i < this._workspacesItems.length; i++) {
+ const item = this._workspacesItems[i];
+ item.label.text = Meta.prefs_get_workspace_name(i);
+ }
}
_updateMenu() {
@@ -417,7 +416,8 @@ let WorkspaceIndicator = GObject.registerClass({
this._currentWorkspace = workspaceManager.get_active_workspace_index();
for (let i = 0; i < workspaceManager.n_workspaces; i++) {
- const item = new PopupMenu.PopupMenuItem(this._labelText(i));
+ const name = Meta.prefs_get_workspace_name(i);
+ const item = new PopupMenu.PopupMenuItem(name);
item.connect('activate',
() => this._activate(i));
@@ -430,7 +430,7 @@ let WorkspaceIndicator = GObject.registerClass({
this._workspacesItems[i] = item;
}
- this._statusLabel.set_text(this._labelText());
+ this._statusLabel.set_text(this._getStatusText());
}
_updateThumbnails() {
--
2.50.0
From 6ae80e3c952f4fb2e557dbd4dc4ab304f9e82eae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 22 Feb 2024 04:45:23 +0100
Subject: [PATCH 19/43] workspace-indicator: Tweak preview style
Sync sizes and padding with the window-list previews.
Tone down the colors a bit, but less then the current window-list
style where workspaces blend too much into the background and
the selection is unclear.
---
extensions/workspace-indicator/stylesheet.css | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/extensions/workspace-indicator/stylesheet.css b/extensions/workspace-indicator/stylesheet.css
index 3f89359b..c8c2370f 100644
--- a/extensions/workspace-indicator/stylesheet.css
+++ b/extensions/workspace-indicator/stylesheet.css
@@ -3,24 +3,25 @@
}
.workspace-indicator .workspaces-box {
- padding: 4px 0;
- spacing: 4px;
+ padding: 5px;
+ spacing: 3px;
}
.workspace-indicator .workspace {
- width: 40px;
- border: 2px solid #000;
- border-radius: 2px;
- background-color: #595959;
+ width: 52px;
+ border: 2px solid transparent;
+ border-radius: 4px;
+ background-color: #3f3f3f;
}
.workspace-indicator .workspace.active {
- border-color: #fff;
+ border-color: #9f9f9f;
}
.workspace-indicator-window-preview {
- background-color: #252525;
- border: 1px solid #ccc;
+ background-color: #bebebe;
+ border: 1px solid #828282;
+ border-radius: 1px;
}
.workspace-indicator-window-preview {
--
2.50.0
From a034be112b74ea09bfa53840ab3c85ce6593bd88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 23:22:58 +0100
Subject: [PATCH 20/43] workspace-indicator: Support light style
The window-list extension already includes light styling for
its copy of the workspace indicator. Just copy that over to
support the light variant here as well.
---
extensions/workspace-indicator/meson.build | 6 +++-
.../workspace-indicator/stylesheet-dark.css | 29 +++++++++++++++++
.../workspace-indicator/stylesheet-light.css | 25 +++++++++++++++
extensions/workspace-indicator/stylesheet.css | 31 +------------------
4 files changed, 60 insertions(+), 31 deletions(-)
create mode 100644 extensions/workspace-indicator/stylesheet-dark.css
create mode 100644 extensions/workspace-indicator/stylesheet-light.css
diff --git a/extensions/workspace-indicator/meson.build b/extensions/workspace-indicator/meson.build
index eb25b9cc..0bf9f023 100644
--- a/extensions/workspace-indicator/meson.build
+++ b/extensions/workspace-indicator/meson.build
@@ -3,6 +3,10 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
-extension_data += files('stylesheet.css')
+extension_data += files(
+ 'stylesheet.css',
+ 'stylesheet-dark.css',
+ 'stylesheet-light.css',
+)
extension_sources += files('prefs.js', 'workspaceIndicator.js')
diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css
new file mode 100644
index 00000000..f74f7e88
--- /dev/null
+++ b/extensions/workspace-indicator/stylesheet-dark.css
@@ -0,0 +1,29 @@
+.workspace-indicator .status-label {
+ padding: 0 8px;
+}
+
+.workspace-indicator .workspaces-box {
+ padding: 5px;
+ spacing: 3px;
+}
+
+.workspace-indicator .workspace {
+ width: 52px;
+ border: 2px solid transparent;
+ border-radius: 4px;
+ background-color: #3f3f3f;
+}
+
+.workspace-indicator .workspace.active {
+ border-color: #9f9f9f;
+}
+
+.workspace-indicator-window-preview {
+ background-color: #bebebe;
+ border: 1px solid #828282;
+ border-radius: 1px;
+}
+
+.workspace-indicator-window-preview.active {
+ background-color: #d4d4d4;
+}
diff --git a/extensions/workspace-indicator/stylesheet-light.css b/extensions/workspace-indicator/stylesheet-light.css
new file mode 100644
index 00000000..049b6a38
--- /dev/null
+++ b/extensions/workspace-indicator/stylesheet-light.css
@@ -0,0 +1,25 @@
+/*
+ * SPDX-FileCopyrightText: 2013 Florian Müllner <fmuellner@gnome.org>
+ * SPDX-FileCopyrightText: 2015 Jakub Steiner <jimmac@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+@import url("stylesheet-dark.css");
+
+.workspace-indicator .workspace {
+ background-color: #ccc;
+}
+
+.workspace-indicator .workspace.active {
+ border-color: #888;
+}
+
+.workspace-indicator-window-preview {
+ background-color: #ededed;
+ border: 1px solid #ccc;
+}
+
+.workspace-indicator-window-preview.active {
+ background-color: #f6f5f4;
+}
diff --git a/extensions/workspace-indicator/stylesheet.css b/extensions/workspace-indicator/stylesheet.css
index c8c2370f..b0f7d171 100644
--- a/extensions/workspace-indicator/stylesheet.css
+++ b/extensions/workspace-indicator/stylesheet.css
@@ -1,30 +1 @@
-.workspace-indicator .status-label {
- padding: 0 8px;
-}
-
-.workspace-indicator .workspaces-box {
- padding: 5px;
- spacing: 3px;
-}
-
-.workspace-indicator .workspace {
- width: 52px;
- border: 2px solid transparent;
- border-radius: 4px;
- background-color: #3f3f3f;
-}
-
-.workspace-indicator .workspace.active {
- border-color: #9f9f9f;
-}
-
-.workspace-indicator-window-preview {
- background-color: #bebebe;
- border: 1px solid #828282;
- border-radius: 1px;
-}
-
-.workspace-indicator-window-preview {
- background-color: #353535;
- border: 2px solid #ccc;
-}
+@import url("stylesheet-dark.css");
--
2.50.0
From 7bad2503adfbdcf5dfa67288fd7a5abcdd299fb0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 13:08:52 +0100
Subject: [PATCH 21/43] window-list: Use actual copy of workspace-indicator
We are now at a point where the code from the workspace-indicator
extension is usable from the window-list.
However instead of updating the copy, go one step further and
remove it altogether, and copy the required files at build time.
This ensures that future changes are picked up by both extensions
without duplicating any work.
---
extensions/window-list/classic.css | 20 +-
extensions/window-list/meson.build | 29 +-
extensions/window-list/stylesheet.css | 2 +
extensions/window-list/workspaceIndicator.js | 451 -------------------
4 files changed, 31 insertions(+), 471 deletions(-)
delete mode 100644 extensions/window-list/workspaceIndicator.js
diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css
index 02286041..d7ceb062 100644
--- a/extensions/window-list/classic.css
+++ b/extensions/window-list/classic.css
@@ -1,4 +1,5 @@
@import url("stylesheet.css");
+@import url("stylesheet-workspace-switcher-light.css");
#panel.bottom-panel {
border-top-width: 1px;
@@ -47,22 +48,3 @@
color: #888;
box-shadow: none;
}
-
-/* workspace switcher */
-.window-list-workspace-indicator .workspace {
- background-color: #ddd;
-}
-
-.window-list-workspace-indicator .workspace.active {
- background-color: #ccc;
-}
-
-.window-list-workspace-indicator-window-preview {
- background-color: #ededed;
- border: 1px solid #ccc;
-}
-
-.window-list-workspace-indicator-window-preview.active {
- background-color: #f6f5f4;
- border: 2px solid #888;
-}
diff --git a/extensions/window-list/meson.build b/extensions/window-list/meson.build
index 599f45e1..12d2b174 100644
--- a/extensions/window-list/meson.build
+++ b/extensions/window-list/meson.build
@@ -5,7 +5,34 @@ extension_data += configure_file(
)
extension_data += files('stylesheet.css')
-extension_sources += files('prefs.js', 'windowPicker.js', 'workspaceIndicator.js')
+transform_stylesheet = [
+ 'sed', '-E',
+ '-e', 's:^\.(workspace-indicator):.window-list-\\1:',
+ '-e', '/^@import/d',
+ '@INPUT@',
+ ]
+
+workspaceIndicatorSources = [
+ configure_file(
+ input: '../workspace-indicator/workspaceIndicator.js',
+ output: '@PLAINNAME@',
+ copy: true,
+ ),
+ configure_file(
+ input: '../workspace-indicator/stylesheet-dark.css',
+ output: 'stylesheet-workspace-switcher-dark.css',
+ command: transform_stylesheet,
+ capture: true,
+ ),
+ configure_file(
+ input: '../workspace-indicator/stylesheet-light.css',
+ output: 'stylesheet-workspace-switcher-light.css',
+ command: transform_stylesheet,
+ capture: true,
+ ),
+]
+
+extension_sources += files('prefs.js', 'windowPicker.js') + workspaceIndicatorSources
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
if classic_mode_enabled
diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css
index 4c9ca671..2aa35922 100644
--- a/extensions/window-list/stylesheet.css
+++ b/extensions/window-list/stylesheet.css
@@ -1,3 +1,5 @@
+@import url("stylesheet-workspace-switcher-dark.css");
+
.bottom-panel {
/* .window-button-icon height +
.window-button vertical padding +
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
deleted file mode 100644
index 574ebdca..00000000
--- a/extensions/window-list/workspaceIndicator.js
+++ /dev/null
@@ -1,451 +0,0 @@
-/* exported WorkspaceIndicator */
-const { Clutter, Gio, GObject, Meta, St } = imports.gi;
-
-const DND = imports.ui.dnd;
-const Main = imports.ui.main;
-const PanelMenu = imports.ui.panelMenu;
-const PopupMenu = imports.ui.popupMenu;
-const Tweener = imports.ui.tweener;
-
-const Gettext = imports.gettext.domain('gnome-shell-extensions');
-const _ = Gettext.gettext;
-
-const TOOLTIP_OFFSET = 6;
-const TOOLTIP_ANIMATION_TIME = 150;
-
-let baseStyleClassName = '';
-
-const TypePrefix = window.TypePrefix || '';
-
-let WindowPreview = GObject.registerClass({
- GTypeName: `${TypePrefix}WorkspaceIndicatorWindowPreview`
-}, class WindowPreview extends St.Button {
- _init(window) {
- super._init({
- style_class: `${baseStyleClassName}-window-preview`,
- });
-
- this._delegate = this;
- DND.makeDraggable(this, { restoreOnSuccess: true });
-
- this._window = window;
-
- this.connect('destroy', this._onDestroy.bind(this));
-
- this._sizeChangedId = this._window.connect('size-changed',
- this._relayout.bind(this));
- this._positionChangedId = this._window.connect('position-changed',
- this._relayout.bind(this));
- this._minimizedChangedId = this._window.connect('notify::minimized',
- this._relayout.bind(this));
- this._monitorEnteredId = global.display.connect('window-entered-monitor',
- this._relayout.bind(this));
- this._monitorLeftId = global.display.connect('window-left-monitor',
- this._relayout.bind(this));
-
- // Do initial layout when we get a parent
- let id = this.connect('parent-set', () => {
- this.disconnect(id);
- if (!this.get_parent())
- return;
- this._laterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
- this._laterId = 0;
- this._relayout();
- return false;
- });
- });
-
- this._focusChangedId = global.display.connect('notify::focus-window',
- this._onFocusChanged.bind(this));
- this._onFocusChanged();
- }
-
- // needed for DND
- get realWindow() {
- return this._window.get_compositor_private();
- }
-
- _onDestroy() {
- this._window.disconnect(this._sizeChangedId);
- this._window.disconnect(this._positionChangedId);
- this._window.disconnect(this._minimizedChangedId);
- global.display.disconnect(this._monitorEnteredId);
- global.display.disconnect(this._monitorLeftId);
- global.display.disconnect(this._focusChangedId);
- if (this._laterId)
- Meta.later_remove(this._laterId);
- }
-
- _onFocusChanged() {
- if (global.display.focus_window == this._window)
- this.add_style_class_name('active');
- else
- this.remove_style_class_name('active');
- }
-
- _relayout() {
- let monitor = Main.layoutManager.findIndexForActor(this);
- this.visible = monitor == this._window.get_monitor() &&
- this._window.showing_on_its_workspace();
-
- if (!this.visible)
- return;
-
- let workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
- let hscale = this.get_parent().allocation.get_width() / workArea.width;
- let vscale = this.get_parent().allocation.get_height() / workArea.height;
-
- let frameRect = this._window.get_frame_rect();
- this.set_size(
- Math.round(Math.min(frameRect.width, workArea.width) * hscale),
- Math.round(Math.min(frameRect.height, workArea.height) * vscale));
- this.set_position(
- Math.round(frameRect.x * hscale),
- Math.round(frameRect.y * vscale));
- }
-});
-
-let WorkspaceThumbnail = GObject.registerClass({
- GTypeName: `${TypePrefix}WorkspaceIndicatorWorkspaceThumbnail`
-}, class WorkspaceThumbnail extends St.Button {
- _init(index) {
- super._init({
- style_class: 'workspace',
- child: new Clutter.Actor({
- layout_manager: new Clutter.BinLayout(),
- clip_to_allocation: true
- }),
- x_fill: true,
- y_fill: true
- });
-
- this._tooltip = new St.Label({
- style_class: 'dash-label',
- visible: false,
- });
- Main.uiGroup.add_child(this._tooltip);
-
- this.connect('destroy', this._onDestroy.bind(this));
- this.connect('notify::hover', this._syncTooltip.bind(this));
-
- this._index = index;
- this._delegate = this; // needed for DND
-
- this._windowPreviews = new Map();
-
- let workspaceManager = global.workspace_manager;
- this._workspace = workspaceManager.get_workspace_by_index(index);
-
- this._windowAddedId = this._workspace.connect('window-added',
- (ws, window) => {
- this._addWindow(window);
- });
- this._windowRemovedId = this._workspace.connect('window-removed',
- (ws, window) => {
- this._removeWindow(window);
- });
- this._restackedId = global.display.connect('restacked',
- this._onRestacked.bind(this));
-
- this._workspace.list_windows().forEach(w => this._addWindow(w));
- this._onRestacked();
- }
-
- acceptDrop(source) {
- if (!source.realWindow)
- return false;
-
- let window = source.realWindow.get_meta_window();
- this._moveWindow(window);
- return true;
- }
-
- handleDragOver(source) {
- if (source.realWindow)
- return DND.DragMotionResult.MOVE_DROP;
- else
- return DND.DragMotionResult.CONTINUE;
- }
-
- _addWindow(window) {
- if (this._windowPreviews.has(window))
- return;
-
- let preview = new WindowPreview(window);
- preview.connect('clicked', (a, btn) => this.emit('clicked', btn));
- this._windowPreviews.set(window, preview);
- this.child.add_child(preview);
- }
-
- _removeWindow(window) {
- let preview = this._windowPreviews.get(window);
- if (!preview)
- return;
-
- this._windowPreviews.delete(window);
- preview.destroy();
- }
-
- _onRestacked() {
- let lastPreview = null;
- let windows = global.get_window_actors().map(a => a.meta_window);
- for (let i = 0; i < windows.length; i++) {
- let preview = this._windowPreviews.get(windows[i]);
- if (!preview)
- continue;
-
- this.child.set_child_above_sibling(preview, lastPreview);
- lastPreview = preview;
- }
- }
-
- _moveWindow(window) {
- let monitorIndex = Main.layoutManager.findIndexForActor(this);
- if (monitorIndex != window.get_monitor())
- window.move_to_monitor(monitorIndex);
- window.change_workspace_by_index(this._index, false);
- }
-
- // eslint-disable-next-line camelcase
- on_clicked() {
- let ws = global.workspace_manager.get_workspace_by_index(this._index);
- if (ws)
- ws.activate(global.get_current_time());
- }
-
- _syncTooltip() {
- if (this.hover) {
- this._tooltip.text = Meta.prefs_get_workspace_name(this._index);
- this._tooltip.opacity = 0;
- this._tooltip.show();
-
- const [stageX, stageY] = this.get_transformed_position();
- const thumbWidth = this.allocation.get_width();
- const tipWidth = this._tooltip.width;
- const tipHeight = this._tooltip.height;
- const xOffset = Math.floor((thumbWidth - tipWidth) / 2);
- const monitor = Main.layoutManager.findMonitorForActor(this);
- const x = Math.min(
- Math.max(stageX + xOffset, monitor.x),
- monitor.x + monitor.width - tipWidth);
- const y = stageY - tipHeight - TOOLTIP_OFFSET;
- this._tooltip.set_position(x, y);
- }
-
- Tweener.addTween(this._tooltip, {
- opacity: this.hover ? 255 : 0,
- time: TOOLTIP_ANIMATION_TIME / 1000,
- transition: 'easeOutQuad',
- onComplete: () => (this._tooltip.visible = this.hover),
- });
- }
-
- _onDestroy() {
- this._tooltip.destroy();
-
- this._workspace.disconnect(this._windowAddedId);
- this._workspace.disconnect(this._windowRemovedId);
- global.display.disconnect(this._restackedId);
- }
-});
-
-var WorkspaceIndicator = GObject.registerClass({
- GTypeName: `${TypePrefix}WorkspaceIndicator`
-}, class WorkspaceIndicator extends PanelMenu.Button {
- _init(params = {}) {
- super._init(0.0, _('Workspace Indicator'));
-
- const {
- baseStyleClass = 'workspace-indicator',
- } = params;
-
- baseStyleClassName = baseStyleClass;
- this.add_style_class_name(baseStyleClassName);
-
- let container = new St.Widget({
- layout_manager: new Clutter.BinLayout(),
- x_expand: true,
- y_expand: true
- });
- this.add_actor(container);
-
- let workspaceManager = global.workspace_manager;
-
- this._currentWorkspace = workspaceManager.get_active_workspace_index();
- this._statusLabel = new St.Label({ text: this._getStatusText() });
-
- this._statusBin = new St.Bin({
- style_class: 'status-label-bin',
- x_expand: true,
- y_expand: true,
- child: this._statusLabel
- });
- container.add_actor(this._statusBin);
-
- this._thumbnailsBox = new St.BoxLayout({
- style_class: 'workspaces-box',
- y_expand: true,
- reactive: true
- });
- this._thumbnailsBox.connect('scroll-event',
- this._onScrollEvent.bind(this));
- container.add_actor(this._thumbnailsBox);
-
- this._workspacesItems = [];
-
- this._workspaceManagerSignals = [
- workspaceManager.connect('notify::n-workspaces',
- this._nWorkspacesChanged.bind(this)),
- workspaceManager.connect_after('workspace-switched',
- this._onWorkspaceSwitched.bind(this)),
- workspaceManager.connect('notify::layout-rows',
- this._onWorkspaceOrientationChanged.bind(this))
- ];
-
- this.connect('scroll-event', this._onScrollEvent.bind(this));
- this._updateMenu();
- this._updateThumbnails();
- this._onWorkspaceOrientationChanged();
-
- this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' });
- this._settingsChangedId = this._settings.connect(
- 'changed::workspace-names', this._updateMenuLabels.bind(this));
- }
-
- _onDestroy() {
- for (let i = 0; i < this._workspaceManagerSignals.length; i++)
- global.workspace_manager.disconnect(this._workspaceManagerSignals[i]);
-
- if (this._settingsChangedId) {
- this._settings.disconnect(this._settingsChangedId);
- this._settingsChangedId = 0;
- }
-
- super._onDestroy();
- }
-
- _onWorkspaceOrientationChanged() {
- let vertical = global.workspace_manager.layout_rows == -1;
- this.reactive = vertical;
-
- this._statusBin.visible = vertical;
- this._thumbnailsBox.visible = !vertical;
- }
-
- _onWorkspaceSwitched() {
- let workspaceManager = global.workspace_manager;
- this._currentWorkspace = workspaceManager.get_active_workspace_index();
-
- this._updateMenuOrnament();
- this._updateActiveThumbnail();
-
- this._statusLabel.set_text(this._getStatusText());
- }
-
- _nWorkspacesChanged() {
- this._updateMenu();
- this._updateThumbnails();
- }
-
- _updateMenuOrnament() {
- for (let i = 0; i < this._workspacesItems.length; i++) {
- this._workspacesItems[i].setOrnament(i == this._currentWorkspace
- ? PopupMenu.Ornament.DOT
- : PopupMenu.Ornament.NONE);
- }
- }
-
- _updateActiveThumbnail() {
- let thumbs = this._thumbnailsBox.get_children();
- for (let i = 0; i < thumbs.length; i++) {
- if (i == this._currentWorkspace)
- thumbs[i].add_style_class_name('active');
- else
- thumbs[i].remove_style_class_name('active');
- }
- }
-
- _getStatusText() {
- let workspaceManager = global.workspace_manager;
- let current = workspaceManager.get_active_workspace_index();
- let total = workspaceManager.n_workspaces;
-
- return '%d / %d'.format(current + 1, total);
- }
-
- _updateMenuLabels() {
- for (let i = 0; i < this._workspacesItems.length; i++) {
- let item = this._workspacesItems[i];
- let name = Meta.prefs_get_workspace_name(i);
- item.label.text = name;
- }
- }
-
- _updateMenu() {
- let workspaceManager = global.workspace_manager;
-
- this.menu.removeAll();
- this._workspacesItems = [];
- this._currentWorkspace = workspaceManager.get_active_workspace_index();
-
- for (let i = 0; i < workspaceManager.n_workspaces; i++) {
- let name = Meta.prefs_get_workspace_name(i);
- let item = new PopupMenu.PopupMenuItem(name);
- item.workspaceId = i;
-
- item.connect('activate', (item, _event) => {
- this._activate(item.workspaceId);
- });
-
- if (i == this._currentWorkspace)
- item.setOrnament(PopupMenu.Ornament.DOT);
-
- this.menu.addMenuItem(item);
- this._workspacesItems[i] = item;
- }
-
- this._statusLabel.set_text(this._getStatusText());
- }
-
- _updateThumbnails() {
- let workspaceManager = global.workspace_manager;
-
- this._thumbnailsBox.destroy_all_children();
-
- for (let i = 0; i < workspaceManager.n_workspaces; i++) {
- let thumb = new WorkspaceThumbnail(i);
- this._thumbnailsBox.add_actor(thumb);
- }
- this._updateActiveThumbnail();
- }
-
- _activate(index) {
- let workspaceManager = global.workspace_manager;
-
- if (index >= 0 && index < workspaceManager.n_workspaces) {
- let metaWorkspace = workspaceManager.get_workspace_by_index(index);
- metaWorkspace.activate(global.get_current_time());
- }
- }
-
- _onScrollEvent(actor, event) {
- let direction = event.get_scroll_direction();
- let diff = 0;
- if (direction == Clutter.ScrollDirection.DOWN) {
- diff = 1;
- } else if (direction == Clutter.ScrollDirection.UP) {
- diff = -1;
- } else {
- return;
- }
-
- let newIndex = this._currentWorkspace + diff;
- this._activate(newIndex);
- }
-
- _allocate(actor, box, flags) {
- if (actor.get_n_children() > 0)
- actor.get_first_child().allocate(box, flags);
- }
-});
-
--
2.50.0
From 08c0fab926838cb4f3dcf5c3b1b9356c0f0e9f57 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 20 Feb 2024 17:27:57 +0100
Subject: [PATCH 22/43] workspace-indicator: Split out WorkspacePreviews
The previews will become a bit more complex soon, so spit them out
into a dedicated class.
---
.../workspace-indicator/workspaceIndicator.js | 139 +++++++++++-------
1 file changed, 88 insertions(+), 51 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 6783b315..0a5e7b26 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -255,6 +255,88 @@ let WorkspaceThumbnail = GObject.registerClass({
}
});
+const WorkspacePreviews = GObject.registerClass({
+ GTypeName: `${TypePrefix}WorkspaceIndicatorWorkspacePreviews`
+}, class WorkspacePreviews extends Clutter.Actor {
+ _init() {
+ super._init({
+ layout_manager: new Clutter.BinLayout(),
+ reactive: true,
+ y_expand: true,
+ });
+
+ this.connect('scroll-event',
+ (a, event) => this.handleScrollEvent(event));
+ this.connect('destroy', () => this._onDestroy());
+
+ const {workspaceManager} = global;
+
+ this._workspaceManagerSignals = [
+ workspaceManager.connect_after('notify::n-workspaces',
+ () => this._updateThumbnails()),
+ workspaceManager.connect_after('workspace-switched',
+ () => this._updateActiveThumbnail()),
+ ];
+
+ this._thumbnailsBox = new St.BoxLayout({
+ style_class: 'workspaces-box',
+ y_expand: true,
+ });
+ this.add_child(this._thumbnailsBox);
+
+ this._updateThumbnails();
+ }
+
+ handleScrollEvent(event) {
+ const direction = event.get_scroll_direction();
+ let diff = 0;
+ if (direction == Clutter.ScrollDirection.DOWN)
+ diff = 1;
+ else if (direction == Clutter.ScrollDirection.UP)
+ diff = -1;
+ else
+ return;
+
+ const {workspaceManager} = global;
+ const currentIndex = workspaceManager.get_active_workspace_index();
+ const newIndex = currentIndex + diff;
+ const workspace = workspaceManager.get_workspace_by_index(newIndex);
+ if (workspace)
+ workspace.activate(global.get_current_time());
+ }
+
+ _updateThumbnails() {
+ const {nWorkspaces} = global.workspace_manager;
+
+ this._thumbnailsBox.destroy_all_children();
+
+ for (let i = 0; i < nWorkspaces; i++) {
+ const thumb = new WorkspaceThumbnail(i);
+ this._thumbnailsBox.add_child(thumb);
+ }
+ this._updateActiveThumbnail();
+ }
+
+ _updateActiveThumbnail() {
+ const {workspaceManager} = global;
+ const activeIndex = workspaceManager.get_active_workspace_index();
+ let thumbs = this._thumbnailsBox.get_children();
+ for (let i = 0; i < thumbs.length; i++) {
+ if (i == activeIndex)
+ thumbs[i].add_style_class_name('active');
+ else
+ thumbs[i].remove_style_class_name('active');
+ }
+ }
+
+ _onDestroy() {
+ global.workspace_manager.disconnect(this._nWorkspacesChanged);
+ for (let i = 0; i < this._workspaceManagerSignals.length; i++)
+ global.workspace_manager.disconnect(this._workspaceManagerSignals[i]);
+ this._workspaceManagerSignals = [];
+ }
+});
+
let WorkspaceIndicator = GObject.registerClass({
GTypeName: `${TypePrefix}WorkspaceIndicator`
}, class WorkspaceIndicator extends PanelMenu.Button {
@@ -286,13 +368,8 @@ let WorkspaceIndicator = GObject.registerClass({
container.add_actor(this._statusLabel);
- this._thumbnailsBox = new St.BoxLayout({
- style_class: 'workspaces-box',
- y_expand: true,
- reactive: true
- });
-
- container.add_actor(this._thumbnailsBox);
+ this._thumbnails = new WorkspacePreviews();
+ container.add_child(this._thumbnails);
this._workspacesItems = [];
@@ -305,8 +382,8 @@ let WorkspaceIndicator = GObject.registerClass({
this._onWorkspaceOrientationChanged.bind(this))
];
- this.connect('scroll-event', this._onScrollEvent.bind(this));
- this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
+ this.connect('scroll-event',
+ (o, event) => this._thumbnails.handleScrollEvent(event));
this._inTopBar = false;
this.connect('notify::realized', () => {
@@ -318,7 +395,6 @@ let WorkspaceIndicator = GObject.registerClass({
});
this._updateMenu();
- this._updateThumbnails();
this._onWorkspaceOrientationChanged();
this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' });
@@ -348,7 +424,7 @@ let WorkspaceIndicator = GObject.registerClass({
this.reactive = vertical;
this._statusLabel.visible = vertical;
- this._thumbnailsBox.visible = !vertical;
+ this._thumbnails.visible = !vertical;
this._updateTopBarRedirect();
}
@@ -359,7 +435,7 @@ let WorkspaceIndicator = GObject.registerClass({
// Disable offscreen-redirect when showing the workspace switcher
// so that clip-to-allocation works
- Main.panel.set_offscreen_redirect(this._thumbnailsBox.visible
+ Main.panel.set_offscreen_redirect(this._thumbnails.visible
? Clutter.OffscreenRedirect.ALWAYS
: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY);
}
@@ -368,14 +444,12 @@ let WorkspaceIndicator = GObject.registerClass({
this._currentWorkspace = global.workspace_manager.get_active_workspace_index();
this._updateMenuOrnament();
- this._updateActiveThumbnail();
this._statusLabel.set_text(this._getStatusText());
}
_nWorkspacesChanged() {
this._updateMenu();
- this._updateThumbnails();
}
_updateMenuOrnament() {
@@ -386,16 +460,6 @@ let WorkspaceIndicator = GObject.registerClass({
}
}
- _updateActiveThumbnail() {
- let thumbs = this._thumbnailsBox.get_children();
- for (let i = 0; i < thumbs.length; i++) {
- if (i == this._currentWorkspace)
- thumbs[i].add_style_class_name('active');
- else
- thumbs[i].remove_style_class_name('active');
- }
- }
-
_getStatusText() {
const current = this._currentWorkspace + 1;
return `${current}`;
@@ -433,18 +497,6 @@ let WorkspaceIndicator = GObject.registerClass({
this._statusLabel.set_text(this._getStatusText());
}
- _updateThumbnails() {
- let workspaceManager = global.workspace_manager;
-
- this._thumbnailsBox.destroy_all_children();
-
- for (let i = 0; i < workspaceManager.n_workspaces; i++) {
- let thumb = new WorkspaceThumbnail(i);
- this._thumbnailsBox.add_actor(thumb);
- }
- this._updateActiveThumbnail();
- }
-
_activate(index) {
let workspaceManager = global.workspace_manager;
@@ -453,19 +505,4 @@ let WorkspaceIndicator = GObject.registerClass({
metaWorkspace.activate(global.get_current_time());
}
}
-
- _onScrollEvent(actor, event) {
- let direction = event.get_scroll_direction();
- let diff = 0;
- if (direction == Clutter.ScrollDirection.DOWN) {
- diff = 1;
- } else if (direction == Clutter.ScrollDirection.UP) {
- diff = -1;
- } else {
- return;
- }
-
- const newIndex = this._currentWorkspace + diff;
- this._activate(newIndex);
- }
});
--
2.50.0
From 6e8c0b128350d4d8555e2f4750bd551654596917 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 19 Feb 2024 14:42:04 +0100
Subject: [PATCH 23/43] workspace-indicator: Handle preview overflow
We currently avoid previews from overflowing in most setups by
artificially limiting them to a maximum of six workspaces.
Add some proper handling to also cover cases where space is more
limited, and to allow removing the restriction in the future.
For that, wrap the previews in an auto-scrolling scroll view
and add overflow indicators on each side.
---
.../workspace-indicator/stylesheet-dark.css | 4 ++
.../workspace-indicator/workspaceIndicator.js | 68 ++++++++++++++++++-
2 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css
index f74f7e88..61d1e982 100644
--- a/extensions/workspace-indicator/stylesheet-dark.css
+++ b/extensions/workspace-indicator/stylesheet-dark.css
@@ -2,6 +2,10 @@
padding: 0 8px;
}
+.workspace-indicator .workspaces-view.hfade {
+ -st-hfade-offset: 20px;
+}
+
.workspace-indicator .workspaces-box {
padding: 5px;
spacing: 3px;
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 0a5e7b26..1e3db810 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -12,6 +12,8 @@ const _ = Gettext.gettext;
const TOOLTIP_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150;
+const SCROLL_TIME = 100;
+
let baseStyleClassName = '';
const TypePrefix = window.TypePrefix || '';
@@ -276,13 +278,30 @@ const WorkspacePreviews = GObject.registerClass({
() => this._updateThumbnails()),
workspaceManager.connect_after('workspace-switched',
() => this._updateActiveThumbnail()),
+ workspaceManager.connect('workspace-switched',
+ () => this._updateScrollPosition()),
];
+ this.connect('notify::mapped', () => {
+ if (this.mapped)
+ this._updateScrollPosition();
+ });
+
this._thumbnailsBox = new St.BoxLayout({
style_class: 'workspaces-box',
y_expand: true,
});
- this.add_child(this._thumbnailsBox);
+
+ this._scrollView = new St.ScrollView({
+ style_class: 'workspaces-view hfade',
+ enable_mouse_scrolling: false,
+ hscrollbar_policy: St.PolicyType.EXTERNAL,
+ vscrollbar_policy: St.PolicyType.NEVER,
+ y_expand: true,
+ });
+ this._scrollView.add_actor(this._thumbnailsBox);
+
+ this.add_child(this._scrollView);
this._updateThumbnails();
}
@@ -315,6 +334,9 @@ const WorkspacePreviews = GObject.registerClass({
this._thumbnailsBox.add_child(thumb);
}
this._updateActiveThumbnail();
+
+ if (this.mapped)
+ this._updateScrollPosition();
}
_updateActiveThumbnail() {
@@ -329,6 +351,50 @@ const WorkspacePreviews = GObject.registerClass({
}
}
+ _updateScrollPosition() {
+ const adjustment = this._scrollView.hscroll.adjustment;
+ const {upper, pageSize} = adjustment;
+ let {value} = adjustment;
+
+ const {workspaceManager} = global;
+ const activeIndex = workspaceManager.get_active_workspace_index();
+ const activeWorkspace =
+ this._thumbnailsBox.get_child_at_index(activeIndex);
+
+ if (!activeWorkspace)
+ return;
+
+ let offset = 0;
+ const hfade = this._scrollView.get_effect('fade');
+ if (hfade)
+ offset = this._scrollView.get_theme_node().get_length('-st-hfade-offset');
+
+ let {x1, x2} = activeWorkspace.get_allocation_box();
+ let parent = activeWorkspace.get_parent();
+ while (parent !== this._scrollView) {
+ if (!parent)
+ throw new Error('actor not in scroll view');
+
+ const box = parent.get_allocation_box();
+ x1 += box.x1;
+ x2 += box.x1;
+ parent = parent.get_parent();
+ }
+
+ if (x1 < value + offset)
+ value = Math.max(0, x1 - offset);
+ else if (x2 > value + pageSize - offset)
+ value = Math.min(upper, x2 + offset - pageSize);
+ else
+ return;
+
+ Tweener.addTween(adjustment, {
+ value,
+ time: SCROLL_TIME / 1000,
+ transition: 'easeOutQuad',
+ });
+ }
+
_onDestroy() {
global.workspace_manager.disconnect(this._nWorkspacesChanged);
for (let i = 0; i < this._workspaceManagerSignals.length; i++)
--
2.50.0
From 355a224ca85344c876784bcebc119f6dbf657693 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 20 Feb 2024 22:00:57 +0100
Subject: [PATCH 24/43] workspace-indicator: Make previews configurable
Now that previews scroll when there are too many workspaces,
there is no longer a reason for the 6-workspace limit.
However some users do prefer the menu, so rather than drop it,
turn it into a proper preference.
Closes
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/336
---
....shell.extensions.classic.gschema.override | 3 ++
extensions/window-list/extension.js | 1 +
...e.shell.extensions.window-list.gschema.xml | 4 ++
extensions/workspace-indicator/extension.js | 4 +-
extensions/workspace-indicator/meson.build | 1 +
extensions/workspace-indicator/prefs.js | 43 ++++++++++++++++++-
...extensions.workspace-indicator.gschema.xml | 15 +++++++
.../workspace-indicator/workspaceIndicator.js | 20 +++++----
po/POTFILES.in | 1 +
9 files changed, 82 insertions(+), 10 deletions(-)
create mode 100644 extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml
diff --git a/data/00_org.gnome.shell.extensions.classic.gschema.override b/data/00_org.gnome.shell.extensions.classic.gschema.override
index c6701074..04155bfe 100644
--- a/data/00_org.gnome.shell.extensions.classic.gschema.override
+++ b/data/00_org.gnome.shell.extensions.classic.gschema.override
@@ -7,3 +7,6 @@ button-layout='appmenu:minimize,maximize,close'
[org.gnome.desktop.wm.keybindings:GNOME-Classic]
switch-applications=[]
switch-windows=['<Super>Tab','<Alt>Tab']
+
+[org.gnome.shell.extensions.window-list:GNOME-Classic]
+embed-previews=true
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index aada9525..b2357939 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -818,6 +818,7 @@ class WindowList {
this._workspaceIndicator = new BottomWorkspaceIndicator({
baseStyleClass: 'window-list-workspace-indicator',
+ settings: ExtensionUtils.getSettings(),
});
indicatorsBox.add(this._workspaceIndicator.container, { expand: false, y_fill: true });
diff --git a/extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml b/extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml
index b7459417..a9174494 100644
--- a/extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml
+++ b/extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml
@@ -23,5 +23,9 @@
only on the primary one.
</description>
</key>
+ <key name="embed-previews" type="b">
+ <default>false</default>
+ <summary>Show workspace previews in window list</summary>
+ </key>
</schema>
</schemalist>
diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js
index 6f7d07c5..ec991993 100644
--- a/extensions/workspace-indicator/extension.js
+++ b/extensions/workspace-indicator/extension.js
@@ -14,7 +14,9 @@ function init() {
let _indicator;
function enable() {
- _indicator = new WorkspaceIndicator;
+ _indicator = new WorkspaceIndicator({
+ settings: ExtensionUtils.getSettings(),
+ });
Main.panel.addToStatusArea('workspace-indicator', _indicator);
}
diff --git a/extensions/workspace-indicator/meson.build b/extensions/workspace-indicator/meson.build
index 0bf9f023..a88db78a 100644
--- a/extensions/workspace-indicator/meson.build
+++ b/extensions/workspace-indicator/meson.build
@@ -8,5 +8,6 @@ extension_data += files(
'stylesheet-dark.css',
'stylesheet-light.css',
)
+extension_schemas += files('schemas/' + metadata_conf.get('gschemaname') + '.gschema.xml')
extension_sources += files('prefs.js', 'workspaceIndicator.js')
diff --git a/extensions/workspace-indicator/prefs.js b/extensions/workspace-indicator/prefs.js
index d8640559..d787f481 100644
--- a/extensions/workspace-indicator/prefs.js
+++ b/extensions/workspace-indicator/prefs.js
@@ -12,6 +12,34 @@ const ExtensionUtils = imports.misc.extensionUtils;
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
const WORKSPACE_KEY = 'workspace-names';
+const GeneralGroup = GObject.registerClass(
+class GeneralGroup extends Gtk.Box {
+ _init() {
+ super._init({
+ orientation: Gtk.Orientation.VERTICAL,
+ });
+
+ const row = new Gtk.Box();
+ this.add(row);
+
+ row.add(new Gtk.Label({
+ label: _('Show Previews In Top Bar'),
+ }));
+
+ const sw = new Gtk.Switch({
+ hexpand: true,
+ halign: Gtk.Align.END,
+ });
+ row.add(sw);
+
+ const settings = ExtensionUtils.getSettings();
+
+ settings.bind('embed-previews',
+ sw, 'active',
+ Gio.SettingsBindFlags.DEFAULT);
+ }
+});
+
const WorkspaceNameModel = GObject.registerClass(
class WorkspaceNameModel extends Gtk.ListStore {
_init(params) {
@@ -127,7 +155,20 @@ class WorkspaceSettingsWidget extends Gtk.Grid {
this.margin = 12;
this.orientation = Gtk.Orientation.VERTICAL;
- this.add(new Gtk.Label({
+ const box = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ halign: Gtk.Align.CENTER,
+ spacing: 12,
+ margin_top: 36,
+ margin_bottom: 36,
+ margin_start: 36,
+ margin_end: 36,
+ });
+ this.add(box);
+
+ box.add(new GeneralGroup());
+
+ box.add(new Gtk.Label({
label: '<b>%s</b>'.format(_('Workspace Names')),
use_markup: true,
margin_bottom: 6,
diff --git a/extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml b/extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml
new file mode 100644
index 00000000..e5059849
--- /dev/null
+++ b/extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml
@@ -0,0 +1,15 @@
+<!--
+SPDX-FileCopyrightText: 2024 Florian Müllner <fmuellner@gnome.org>
+
+SPDX-License-Identifier: GPL-2.0-or-later
+-->
+
+<schemalist gettext-domain="gnome-shell-extensions">
+ <schema id="org.gnome.shell.extensions.workspace-indicator"
+ path="/org/gnome/shell/extensions/workspace-indicator/">
+ <key name="embed-previews" type="b">
+ <default>false</default>
+ <summary>Show workspace previews in top bar</summary>
+ </key>
+ </schema>
+</schemalist>
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 1e3db810..fd497dc9 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -411,8 +411,11 @@ let WorkspaceIndicator = GObject.registerClass({
const {
baseStyleClass = 'workspace-indicator',
+ settings,
} = params;
+ this._settings = settings;
+
baseStyleClassName = baseStyleClass;
this.add_style_class_name(baseStyleClassName);
@@ -444,8 +447,6 @@ let WorkspaceIndicator = GObject.registerClass({
this._nWorkspacesChanged.bind(this)),
workspaceManager.connect_after('workspace-switched',
this._onWorkspaceSwitched.bind(this)),
- workspaceManager.connect('notify::layout-rows',
- this._onWorkspaceOrientationChanged.bind(this))
];
this.connect('scroll-event',
@@ -461,12 +462,15 @@ let WorkspaceIndicator = GObject.registerClass({
});
this._updateMenu();
- this._onWorkspaceOrientationChanged();
this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' });
this._settingsChangedId = this._settings.connect(
'changed::workspace-names',
this._updateMenuLabels.bind(this));
+
+ this._settings.connect('changed::embed-previews',
+ () => this._updateThumbnailVisibility());
+ this._updateThumbnailVisibility();
}
_onDestroy() {
@@ -485,12 +489,12 @@ let WorkspaceIndicator = GObject.registerClass({
super._onDestroy();
}
- _onWorkspaceOrientationChanged() {
- let vertical = global.workspace_manager.layout_rows == -1;
- this.reactive = vertical;
+ _updateThumbnailVisibility() {
+ const useMenu = !this._settings.get_boolean('embed-previews');
+ this.reactive = useMenu;
- this._statusLabel.visible = vertical;
- this._thumbnails.visible = !vertical;
+ this._statusLabel.visible = useMenu;
+ this._thumbnails.visible = !useMenu;
this._updateTopBarRedirect();
}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5cdb710f..eeb36fab 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -19,4 +19,5 @@ extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml
extensions/window-list/prefs.js
extensions/windowsNavigator/extension.js
extensions/workspace-indicator/prefs.js
+extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml
extensions/workspace-indicator/workspaceIndicator.js
--
2.50.0
From ecadaca214f2a7d2154d968bcdd7db927cfc8503 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 21 Mar 2024 17:27:09 +0100
Subject: [PATCH 25/43] window-list: Expose workspace preview option
Now that we have the option, the window-list should expose it
in its preference window like the workspace-indicator.
---
extensions/window-list/prefs.js | 6 ++++++
extensions/workspace-indicator/workspaceIndicator.js | 6 +++---
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js
index 17e97990..2c4f9e49 100644
--- a/extensions/window-list/prefs.js
+++ b/extensions/window-list/prefs.js
@@ -84,6 +84,12 @@ class WindowListPrefsWidget extends Gtk.Grid {
});
this._settings.bind('show-on-all-monitors', check, 'active', Gio.SettingsBindFlags.DEFAULT);
this.add(check);
+
+ check = new Gtk.CheckButton({
+ label: _('Show workspace previews'),
+ });
+ this._settings.bind('embed-previews', check, 'active', Gio.SettingsBindFlags.DEFAULT);
+ this.add(check);
}
});
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index fd497dc9..3c1d5724 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -463,8 +463,8 @@ let WorkspaceIndicator = GObject.registerClass({
this._updateMenu();
- this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' });
- this._settingsChangedId = this._settings.connect(
+ this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' });
+ this._settingsChangedId = this._desktopSettings.connect(
'changed::workspace-names',
this._updateMenuLabels.bind(this));
@@ -478,7 +478,7 @@ let WorkspaceIndicator = GObject.registerClass({
global.workspace_manager.disconnect(this._workspaceManagerSignals[i]);
if (this._settingsChangedId) {
- this._settings.disconnect(this._settingsChangedId);
+ this._desktopSettings.disconnect(this._settingsChangedId);
this._settingsChangedId = 0;
}
--
2.50.0
From 1748cb00834f7167d9e642a93240ec5f3518a344 Mon Sep 17 00:00:00 2001
From: Jakub Steiner <jimmac@gmail.com>
Date: Tue, 16 Jul 2024 09:40:53 +0200
Subject: [PATCH 26/43] window-list: Update styling
- Contemporary look. Fewer borders, thinner outlines for workspace indicators
- Lacks the designed unfocused window separators.
- Relies on https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/328
Fixes https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/421
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/330>
---
extensions/window-list/classic.css | 68 +++++++-----
extensions/window-list/stylesheet.css | 104 ++++++------------
.../workspace-indicator/stylesheet-dark.css | 4 +-
3 files changed, 76 insertions(+), 100 deletions(-)
diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css
index d7ceb062..1d9b82f0 100644
--- a/extensions/window-list/classic.css
+++ b/extensions/window-list/classic.css
@@ -1,22 +1,24 @@
+/*
+ * SPDX-FileCopyrightText: 2013 Florian Müllner <fmuellner@gnome.org>
+ * SPDX-FileCopyrightText: 2015 Jakub Steiner <jimmac@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
@import url("stylesheet.css");
@import url("stylesheet-workspace-switcher-light.css");
#panel.bottom-panel {
border-top-width: 1px;
border-bottom-width: 0px;
- height: 2.25em ;
- padding: 2px;
+ height: 2.5em;
}
- .bottom-panel .window-button > StWidget,
- .bottom-panel .window-picker-toggle > StWidget {
- color: #2e3436;
- background-color: #eee;
+ .bottom-panel .window-button > StWidget {
border-radius: 3px;
padding: 3px 6px 1px;
box-shadow: none;
text-shadow: none;
- border: 1px solid rgba(0,0,0,0.2);
}
.bottom-panel .window-button > StWidget {
@@ -24,27 +26,43 @@
max-width: 18.75em;
}
- .bottom-panel .window-button:hover > StWidget,
- .bottom-panel .window-picker-toggle:hover > StWidget {
- background-color: #f9f9f9;
- }
+ .window-button > StWidget {
+ color: #000;
+ background-color: transparent;
+}
- .bottom-panel .window-button:active > StWidget,
- .bottom-panel .window-button:focus > StWidget {
- box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
- }
+.window-button > StWidget {
+ -st-natural-width: 18.75em;
+ max-width: 18.75em;
+}
- .bottom-panel .window-button.focused > StWidget,
- .bottom-panel .window-picker-toggle:checked > StWidget {
- background-color: #ccc;
- box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
- }
+.window-button:hover > StWidget {
+ background-color: #e1e1e1;
+}
- .bottom-panel .window-button.focused:hover > StWidget {
- background-color: #e9e9e9;
+.window-button:active > StWidget,
+.window-button:focus > StWidget {
+ background-color: #d4d4d4;
+}
+
+.window-button.focused > StWidget {
+ background-color: #c7c7c7;
+}
+
+ .window-button.focused:hover > StWidget {
+ background-color: #bbb;
}
- .bottom-panel .window-button.minimized > StWidget {
- color: #888;
- box-shadow: none;
+ .window-button.focused:active > StWidget {
+ background-color: #aeaeae;
}
+
+.window-button.minimized > StWidget {
+ color: #aaa;
+ background-color: #f9f9f9;
+}
+
+.window-button.minimized:active > StWidget {
+ color: #aaa;
+ background-color: #f9f9f9;
+}
diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css
index 2aa35922..349404c5 100644
--- a/extensions/window-list/stylesheet.css
+++ b/extensions/window-list/stylesheet.css
@@ -1,3 +1,9 @@
+/*
+ * SPDX-FileCopyrightText: 2012 Florian Müllner <fmuellner@gnome.org>
+ * SPDX-FileCopyrightText: 2013 Giovanni Campagna <gcampagna@src.gnome.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
@import url("stylesheet-workspace-switcher-dark.css");
.bottom-panel {
@@ -12,8 +18,14 @@
font-size: 10pt;
}
+.bottom-panel {
+ background-color: #000000;
+ border-top-width: 0px;
+ height: 2.45em;
+}
+
.window-button {
- padding: 1px;
+ padding: 4px, 3px;
}
.window-button:first-child:ltr {
@@ -30,20 +42,11 @@
.window-button > StWidget,
.window-picker-toggle > StWidget {
- color: #bbb;
- background-color: black;
+ color: #fff;
+ background-color: transparent;
border-radius: 4px;
padding: 3px 6px 1px;
- box-shadow: inset 1px 1px 4px rgba(255,255,255,0.5);
- text-shadow: 1px 1px 4px rgba(0,0,0,0.8);
-}
-
-.window-picker-toggle {
- padding: 3px;
-}
-
-.window-picker-toggle > StWidet {
- border: 1px solid rgba(255,255,255,0.3);
+ transition: 100ms ease;
}
.window-button > StWidget {
@@ -51,35 +54,35 @@
max-width: 18.75em;
}
-.window-button:hover > StWidget,
-.window-picker-toggle:hover > StWidget {
- color: white;
- background-color: #1f1f1f;
+.window-button:hover > StWidget {
+ background-color: #303030;
}
.window-button:active > StWidget,
.window-button:focus > StWidget {
- box-shadow: inset 2px 2px 4px rgba(255,255,255,0.5);
+ background-color: #3c3c3c;
}
-.window-button.focused > StWidget,
-.window-picker-toggle:checked > StWidget {
- color: white;
- box-shadow: inset 1px 1px 4px rgba(255,255,255,0.7);
+.window-button.focused > StWidget {
+ background-color: #5b5b5b;
}
-.window-button.focused:active > StWidget,
-.window-picker-toggle:checked:active > StWidget {
- box-shadow: inset 2px 2px 4px rgba(255,255,255,0.7);
-}
+ .window-button.focused:hover > StWidget {
+ background-color: #676767;
+ }
+
+ .window-button.focused:active > StWidget {
+ background-color: #747474;
+ }
.window-button.minimized > StWidget {
color: #666;
- box-shadow: inset -1px -1px 4px rgba(255,255,255,0.5);
+ background-color: #161616;
}
.window-button.minimized:active > StWidget {
- box-shadow: inset -2px -2px 4px rgba(255,255,255,0.5);
+ color: #666;
+ background-color: #161616;
}
.window-button-icon {
@@ -87,51 +90,6 @@
height: 24px;
}
-.window-list-workspace-indicator .status-label-bin {
- background-color: rgba(200, 200, 200, .3);
- border: 1px solid #cccccc;
- padding: 0 3px;
- margin: 3px 0;
-}
-
-.window-list-workspace-indicator .workspaces-box {
- spacing: 3px;
- padding: 3px;
-}
-
-.window-list-workspace-indicator .workspace {
- border: 1px solid #cccccc;
- width: 52px;
-}
-
-.window-list-workspace-indicator .workspace:first-child:last-child:ltr,
-.window-list-workspace-indicator .workspace:first-child:last-child:rtl {
- border-radius: 4px;
-}
-
-.window-list-workspace-indicator .workspace:first-child:ltr,
-.window-list-workspace-indicator .workspace:last-child:rtl {
- border-radius: 4px 0 0 4px;
-}
-
-.window-list-workspace-indicator .workspace:first-child:rtl,
-.window-list-workspace-indicator .workspace:last-child:ltr {
- border-radius: 0 4px 4px 0;
-}
-
-.window-list-workspace-indicator .workspace.active {
- background-color: rgba(200, 200, 200, .3);
-}
-
-.window-list-workspace-indicator-window-preview {
- background-color: #bebebe;
- border: 1px solid #828282;
-}
-
-.window-list-workspace-indicator-window-preview.active {
- background-color: #d4d4d4;
-}
-
.notification {
font-weight: normal;
}
diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css
index 61d1e982..5663b422 100644
--- a/extensions/workspace-indicator/stylesheet-dark.css
+++ b/extensions/workspace-indicator/stylesheet-dark.css
@@ -13,13 +13,13 @@
.workspace-indicator .workspace {
width: 52px;
- border: 2px solid transparent;
+ border: 1px solid transparent;
border-radius: 4px;
background-color: #3f3f3f;
}
.workspace-indicator .workspace.active {
- border-color: #9f9f9f;
+ border-color: #fff;
}
.workspace-indicator-window-preview {
--
2.50.0
From c98e22e9b33a1a584eef04c25500e65d7423e676 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 25 Sep 2024 03:36:08 +0200
Subject: [PATCH 27/43] window-list: Small stylesheet cleanup
The light stylesheet duplicates some declarations, and the
last occurrence matches what we already inherit from the
dark stylesheet.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/337>
---
extensions/window-list/classic.css | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css
index 1d9b82f0..63e5e48c 100644
--- a/extensions/window-list/classic.css
+++ b/extensions/window-list/classic.css
@@ -21,21 +21,11 @@
text-shadow: none;
}
- .bottom-panel .window-button > StWidget {
- -st-natural-width: 18.7em;
- max-width: 18.75em;
- }
-
.window-button > StWidget {
color: #000;
background-color: transparent;
}
-.window-button > StWidget {
- -st-natural-width: 18.75em;
- max-width: 18.75em;
-}
-
.window-button:hover > StWidget {
background-color: #e1e1e1;
}
--
2.50.0
From f2e31221bbd114bedc1d95d3b49afb1af14d5735 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 11 Oct 2024 12:10:36 +0200
Subject: [PATCH 28/43] workspace-indicator: Split out workspaces prefs page
The window-list extension already uses the extension code for
its embedded workspace indicator, this will allow it to do the
same for the preference page.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/344>
---
extensions/workspace-indicator/meson.build | 2 +-
extensions/workspace-indicator/prefs.js | 244 +----------------
.../workspace-indicator/workspacePrefs.js | 245 ++++++++++++++++++
po/POTFILES.in | 2 +-
4 files changed, 250 insertions(+), 243 deletions(-)
create mode 100644 extensions/workspace-indicator/workspacePrefs.js
diff --git a/extensions/workspace-indicator/meson.build b/extensions/workspace-indicator/meson.build
index a88db78a..52ab5334 100644
--- a/extensions/workspace-indicator/meson.build
+++ b/extensions/workspace-indicator/meson.build
@@ -10,4 +10,4 @@ extension_data += files(
)
extension_schemas += files('schemas/' + metadata_conf.get('gschemaname') + '.gschema.xml')
-extension_sources += files('prefs.js', 'workspaceIndicator.js')
+extension_sources += files('prefs.js', 'workspaceIndicator.js', 'workspacePrefs.js')
diff --git a/extensions/workspace-indicator/prefs.js b/extensions/workspace-indicator/prefs.js
index d787f481..2d90e198 100644
--- a/extensions/workspace-indicator/prefs.js
+++ b/extensions/workspace-indicator/prefs.js
@@ -1,253 +1,15 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
/* exported init buildPrefsWidget */
-const { Gio, GObject, Gtk } = imports.gi;
-
-const Gettext = imports.gettext.domain('gnome-shell-extensions');
-const _ = Gettext.gettext;
-const N_ = e => e;
-
const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
-const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
-const WORKSPACE_KEY = 'workspace-names';
-
-const GeneralGroup = GObject.registerClass(
-class GeneralGroup extends Gtk.Box {
- _init() {
- super._init({
- orientation: Gtk.Orientation.VERTICAL,
- });
-
- const row = new Gtk.Box();
- this.add(row);
-
- row.add(new Gtk.Label({
- label: _('Show Previews In Top Bar'),
- }));
-
- const sw = new Gtk.Switch({
- hexpand: true,
- halign: Gtk.Align.END,
- });
- row.add(sw);
-
- const settings = ExtensionUtils.getSettings();
-
- settings.bind('embed-previews',
- sw, 'active',
- Gio.SettingsBindFlags.DEFAULT);
- }
-});
-
-const WorkspaceNameModel = GObject.registerClass(
-class WorkspaceNameModel extends Gtk.ListStore {
- _init(params) {
- super._init(params);
- this.set_column_types([GObject.TYPE_STRING]);
-
- this.Columns = {
- LABEL: 0,
- };
-
- this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA });
- //this._settings.connect('changed::workspace-names', this._reloadFromSettings.bind(this));
-
- this._reloadFromSettings();
-
- // overriding class closure doesn't work, because GtkTreeModel
- // plays tricks with marshallers and class closures
- this.connect('row-changed', this._onRowChanged.bind(this));
- this.connect('row-inserted', this._onRowInserted.bind(this));
- this.connect('row-deleted', this._onRowDeleted.bind(this));
- }
-
- _reloadFromSettings() {
- if (this._preventChanges)
- return;
- this._preventChanges = true;
-
- let newNames = this._settings.get_strv(WORKSPACE_KEY);
-
- let i = 0;
- let [ok, iter] = this.get_iter_first();
- while (ok && i < newNames.length) {
- this.set(iter, [this.Columns.LABEL], [newNames[i]]);
-
- ok = this.iter_next(iter);
- i++;
- }
-
- while (ok)
- ok = this.remove(iter);
-
- for ( ; i < newNames.length; i++) {
- iter = this.append();
- this.set(iter, [this.Columns.LABEL], [newNames[i]]);
- }
-
- this._preventChanges = false;
- }
-
- _onRowChanged(self, path, iter) {
- if (this._preventChanges)
- return;
- this._preventChanges = true;
-
- let index = path.get_indices()[0];
- let names = this._settings.get_strv(WORKSPACE_KEY);
-
- if (index >= names.length) {
- // fill with blanks
- for (let i = names.length; i <= index; i++)
- names[i] = '';
- }
-
- names[index] = this.get_value(iter, this.Columns.LABEL);
-
- this._settings.set_strv(WORKSPACE_KEY, names);
-
- this._preventChanges = false;
- }
-
- _onRowInserted(self, path, iter) {
- if (this._preventChanges)
- return;
- this._preventChanges = true;
-
- let index = path.get_indices()[0];
- let names = this._settings.get_strv(WORKSPACE_KEY);
- let label = this.get_value(iter, this.Columns.LABEL) || '';
- names.splice(index, 0, label);
-
- this._settings.set_strv(WORKSPACE_KEY, names);
-
- this._preventChanges = false;
- }
-
- _onRowDeleted(self, path) {
- if (this._preventChanges)
- return;
- this._preventChanges = true;
-
- let index = path.get_indices()[0];
- let names = this._settings.get_strv(WORKSPACE_KEY);
-
- if (index >= names.length)
- return;
-
- names.splice(index, 1);
-
- // compact the array
- for (let i = names.length - 1; i >= 0 && !names[i]; i++)
- names.pop();
-
- this._settings.set_strv(WORKSPACE_KEY, names);
-
- this._preventChanges = false;
- }
-});
-
-const WorkspaceSettingsWidget = GObject.registerClass(
-class WorkspaceSettingsWidget extends Gtk.Grid {
- _init(params) {
- super._init(params);
- this.margin = 12;
- this.orientation = Gtk.Orientation.VERTICAL;
-
- const box = new Gtk.Box({
- orientation: Gtk.Orientation.VERTICAL,
- halign: Gtk.Align.CENTER,
- spacing: 12,
- margin_top: 36,
- margin_bottom: 36,
- margin_start: 36,
- margin_end: 36,
- });
- this.add(box);
-
- box.add(new GeneralGroup());
-
- box.add(new Gtk.Label({
- label: '<b>%s</b>'.format(_('Workspace Names')),
- use_markup: true,
- margin_bottom: 6,
- hexpand: true,
- halign: Gtk.Align.START
- }));
-
- let scrolled = new Gtk.ScrolledWindow({ shadow_type: Gtk.ShadowType.IN });
- scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- this.add(scrolled);
-
- this._store = new WorkspaceNameModel();
- this._treeView = new Gtk.TreeView({
- model: this._store,
- headers_visible: false,
- reorderable: true,
- hexpand: true,
- vexpand: true
- });
-
- let column = new Gtk.TreeViewColumn({ title: _('Name') });
- let renderer = new Gtk.CellRendererText({ editable: true });
- renderer.connect('edited', this._cellEdited.bind(this));
- column.pack_start(renderer, true);
- column.add_attribute(renderer, 'text', this._store.Columns.LABEL);
- this._treeView.append_column(column);
-
- scrolled.add(this._treeView);
-
- let toolbar = new Gtk.Toolbar({ icon_size: Gtk.IconSize.SMALL_TOOLBAR });
- toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR);
-
- let newButton = new Gtk.ToolButton({ icon_name: 'list-add-symbolic' });
- newButton.connect('clicked', this._newClicked.bind(this));
- toolbar.add(newButton);
-
- let delButton = new Gtk.ToolButton({ icon_name: 'list-remove-symbolic' });
- delButton.connect('clicked', this._delClicked.bind(this));
- toolbar.add(delButton);
-
- let selection = this._treeView.get_selection();
- selection.connect('changed', () => {
- delButton.sensitive = selection.count_selected_rows() > 0;
- });
- delButton.sensitive = selection.count_selected_rows() > 0;
-
- this.add(toolbar);
- }
-
- _cellEdited(renderer, path, newText) {
- let [ok, iter] = this._store.get_iter_from_string(path);
-
- if (ok)
- this._store.set(iter, [this._store.Columns.LABEL], [newText]);
- }
-
- _newClicked() {
- let iter = this._store.append();
- let index = this._store.get_path(iter).get_indices()[0];
-
- let label = _('Workspace %d').format(index + 1);
- this._store.set(iter, [this._store.Columns.LABEL], [label]);
- }
-
- _delClicked() {
- let [any, model_, iter] = this._treeView.get_selection().get_selected();
-
- if (any)
- this._store.remove(iter);
- }
-});
+const { WorkspacesPage } = Me.imports.workspacePrefs;
function init() {
ExtensionUtils.initTranslations();
}
function buildPrefsWidget() {
- let widget = new WorkspaceSettingsWidget();
- widget.show_all();
-
- return widget;
+ return new WorkspacesPage();
}
diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js
new file mode 100644
index 00000000..1c65ff6b
--- /dev/null
+++ b/extensions/workspace-indicator/workspacePrefs.js
@@ -0,0 +1,245 @@
+// SPDX-FileCopyrightText: 2012 Giovanni Campagna <gcampagna@src.gnome.org>
+// SPDX-FileCopyrightText: 2014 Florian Müllner <fmuellner@gnome.org>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/* exported WorkspacesPage */
+const { Gio, GLib, GObject, Gtk, Pango } = imports.gi;
+
+const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
+
+const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']);
+const _ = Gettext.gettext;
+const N_ = e => e;
+
+const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
+const WORKSPACE_KEY = 'workspace-names';
+
+const GeneralGroup = GObject.registerClass(
+class GeneralGroup extends Gtk.Box {
+ _init() {
+ super._init({
+ orientation: Gtk.Orientation.VERTICAL,
+ });
+
+ const row = new Gtk.Box();
+ this.add(row);
+
+ row.add(new Gtk.Label({
+ label: _('Show Previews In Top Bar'),
+ }));
+
+ const sw = new Gtk.Switch({
+ hexpand: true,
+ halign: Gtk.Align.END,
+ });
+ row.add(sw);
+
+ const settings = ExtensionUtils.getSettings();
+
+ settings.bind('embed-previews',
+ sw, 'active',
+ Gio.SettingsBindFlags.DEFAULT);
+ }
+});
+
+const WorkspaceNameModel = GObject.registerClass(
+class WorkspaceNameModel extends Gtk.ListStore {
+ _init(params) {
+ super._init(params);
+ this.set_column_types([GObject.TYPE_STRING]);
+
+ this.Columns = {
+ LABEL: 0,
+ };
+
+ this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA });
+ //this._settings.connect('changed::workspace-names', this._reloadFromSettings.bind(this));
+
+ this._reloadFromSettings();
+
+ // overriding class closure doesn't work, because GtkTreeModel
+ // plays tricks with marshallers and class closures
+ this.connect('row-changed', this._onRowChanged.bind(this));
+ this.connect('row-inserted', this._onRowInserted.bind(this));
+ this.connect('row-deleted', this._onRowDeleted.bind(this));
+ }
+
+ _reloadFromSettings() {
+ if (this._preventChanges)
+ return;
+ this._preventChanges = true;
+
+ let newNames = this._settings.get_strv(WORKSPACE_KEY);
+
+ let i = 0;
+ let [ok, iter] = this.get_iter_first();
+ while (ok && i < newNames.length) {
+ this.set(iter, [this.Columns.LABEL], [newNames[i]]);
+
+ ok = this.iter_next(iter);
+ i++;
+ }
+
+ while (ok)
+ ok = this.remove(iter);
+
+ for ( ; i < newNames.length; i++) {
+ iter = this.append();
+ this.set(iter, [this.Columns.LABEL], [newNames[i]]);
+ }
+
+ this._preventChanges = false;
+ }
+
+ _onRowChanged(self, path, iter) {
+ if (this._preventChanges)
+ return;
+ this._preventChanges = true;
+
+ let index = path.get_indices()[0];
+ let names = this._settings.get_strv(WORKSPACE_KEY);
+
+ if (index >= names.length) {
+ // fill with blanks
+ for (let i = names.length; i <= index; i++)
+ names[i] = '';
+ }
+
+ names[index] = this.get_value(iter, this.Columns.LABEL);
+
+ this._settings.set_strv(WORKSPACE_KEY, names);
+
+ this._preventChanges = false;
+ }
+
+ _onRowInserted(self, path, iter) {
+ if (this._preventChanges)
+ return;
+ this._preventChanges = true;
+
+ let index = path.get_indices()[0];
+ let names = this._settings.get_strv(WORKSPACE_KEY);
+ let label = this.get_value(iter, this.Columns.LABEL) || '';
+ names.splice(index, 0, label);
+
+ this._settings.set_strv(WORKSPACE_KEY, names);
+
+ this._preventChanges = false;
+ }
+
+ _onRowDeleted(self, path) {
+ if (this._preventChanges)
+ return;
+ this._preventChanges = true;
+
+ let index = path.get_indices()[0];
+ let names = this._settings.get_strv(WORKSPACE_KEY);
+
+ if (index >= names.length)
+ return;
+
+ names.splice(index, 1);
+
+ // compact the array
+ for (let i = names.length - 1; i >= 0 && !names[i]; i++)
+ names.pop();
+
+ this._settings.set_strv(WORKSPACE_KEY, names);
+
+ this._preventChanges = false;
+ }
+});
+
+var WorkspacesPage = GObject.registerClass(
+class WorkspacesPage extends Gtk.ScrolledWindow {
+ _init() {
+ super._init({
+ hscrollbar_policy: Gtk.PolicyType.NEVER,
+ vexpand:true,
+ });
+
+ const box = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ halign: Gtk.Align.CENTER,
+ spacing: 12,
+ margin_top: 36,
+ margin_bottom: 36,
+ margin_start: 36,
+ margin_end: 36,
+ });
+ this.add(box);
+
+ box.add(new GeneralGroup());
+
+ box.add(new Gtk.Label({
+ label: '<b>%s</b>'.format(_('Workspace Names')),
+ use_markup: true,
+ margin_bottom: 6,
+ hexpand: true,
+ halign: Gtk.Align.START
+ }));
+
+ this._store = new WorkspaceNameModel();
+ this._treeView = new Gtk.TreeView({
+ model: this._store,
+ headers_visible: false,
+ reorderable: true,
+ hexpand: true,
+ vexpand: true
+ });
+
+ let column = new Gtk.TreeViewColumn({ title: _('Name') });
+ let renderer = new Gtk.CellRendererText({ editable: true });
+ renderer.connect('edited', this._cellEdited.bind(this));
+ column.pack_start(renderer, true);
+ column.add_attribute(renderer, 'text', this._store.Columns.LABEL);
+ this._treeView.append_column(column);
+
+ box.add(this._treeView);
+
+ let toolbar = new Gtk.Toolbar({ icon_size: Gtk.IconSize.SMALL_TOOLBAR });
+ toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR);
+
+ let newButton = new Gtk.ToolButton({ icon_name: 'list-add-symbolic' });
+ newButton.connect('clicked', this._newClicked.bind(this));
+ toolbar.add(newButton);
+
+ let delButton = new Gtk.ToolButton({ icon_name: 'list-remove-symbolic' });
+ delButton.connect('clicked', this._delClicked.bind(this));
+ toolbar.add(delButton);
+
+ let selection = this._treeView.get_selection();
+ selection.connect('changed', () => {
+ delButton.sensitive = selection.count_selected_rows() > 0;
+ });
+ delButton.sensitive = selection.count_selected_rows() > 0;
+
+ box.add(toolbar);
+
+ this.show_all();
+ }
+
+ _cellEdited(renderer, path, newText) {
+ let [ok, iter] = this._store.get_iter_from_string(path);
+
+ if (ok)
+ this._store.set(iter, [this._store.Columns.LABEL], [newText]);
+ }
+
+ _newClicked() {
+ let iter = this._store.append();
+ let index = this._store.get_path(iter).get_indices()[0];
+
+ let label = _('Workspace %d').format(index + 1);
+ this._store.set(iter, [this._store.Columns.LABEL], [label]);
+ }
+
+ _delClicked() {
+ let [any, model_, iter] = this._treeView.get_selection().get_selected();
+
+ if (any)
+ this._store.remove(iter);
+ }
+});
diff --git a/po/POTFILES.in b/po/POTFILES.in
index eeb36fab..ba4c5a46 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -18,6 +18,6 @@ extensions/window-list/extension.js
extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml
extensions/window-list/prefs.js
extensions/windowsNavigator/extension.js
-extensions/workspace-indicator/prefs.js
extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml
extensions/workspace-indicator/workspaceIndicator.js
+extensions/workspace-indicator/workspacePrefs.js
--
2.50.0
From 24d307c6cfa14b766f44e8bcba09b3b1dc741056 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 11 Oct 2024 12:13:05 +0200
Subject: [PATCH 29/43] workspace-indicator: Don't mention "top bar" in prefs
The preferences will be shared with the window-list extension,
so avoid mentioning a specific placement.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/344>
---
extensions/workspace-indicator/workspacePrefs.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js
index 1c65ff6b..0bd4a58b 100644
--- a/extensions/workspace-indicator/workspacePrefs.js
+++ b/extensions/workspace-indicator/workspacePrefs.js
@@ -27,7 +27,7 @@ class GeneralGroup extends Gtk.Box {
this.add(row);
row.add(new Gtk.Label({
- label: _('Show Previews In Top Bar'),
+ label: _('Show Previews'),
}));
const sw = new Gtk.Switch({
--
2.50.0
From 025580ecd9a522c3d68debbd9e7a9d0464db268e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 11 Oct 2024 12:45:54 +0200
Subject: [PATCH 30/43] window-list: Remove workspace-previews setting from
prefs
We are about to include the workspace prefs page from the
workspace-indicator extension, which already includes
the setting.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/344>
---
extensions/window-list/prefs.js | 6 ------
1 file changed, 6 deletions(-)
diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js
index 2c4f9e49..17e97990 100644
--- a/extensions/window-list/prefs.js
+++ b/extensions/window-list/prefs.js
@@ -84,12 +84,6 @@ class WindowListPrefsWidget extends Gtk.Grid {
});
this._settings.bind('show-on-all-monitors', check, 'active', Gio.SettingsBindFlags.DEFAULT);
this.add(check);
-
- check = new Gtk.CheckButton({
- label: _('Show workspace previews'),
- });
- this._settings.bind('embed-previews', check, 'active', Gio.SettingsBindFlags.DEFAULT);
- this.add(check);
}
});
--
2.50.0
From 232fa86f0ef5e833d1f7fb83812381afdaf3e1d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sun, 29 Jun 2025 23:49:15 +0200
Subject: [PATCH 31/43] window-list: Add workspaces page to prefs
This brings back the workspace-previews setting, and adds the
ability to change the workspace names.
Given that those names are used as tooltips or preview titles,
it makes sense to allow editing them from the extension prefs
rather than relying on external tools (like dconf-editor).
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/344>
---
extensions/window-list/meson.build | 1 +
extensions/window-list/prefs.js | 49 +++++++++++++++++++++++++-----
2 files changed, 42 insertions(+), 8 deletions(-)
diff --git a/extensions/window-list/meson.build b/extensions/window-list/meson.build
index 12d2b174..c4485965 100644
--- a/extensions/window-list/meson.build
+++ b/extensions/window-list/meson.build
@@ -30,6 +30,7 @@ workspaceIndicatorSources = [
command: transform_stylesheet,
capture: true,
),
+ files('../workspace-indicator/workspacePrefs.js'),
]
extension_sources += files('prefs.js', 'windowPicker.js') + workspaceIndicatorSources
diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js
index 17e97990..936767c8 100644
--- a/extensions/window-list/prefs.js
+++ b/extensions/window-list/prefs.js
@@ -7,20 +7,26 @@ const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
+const { WorkspacesPage } = Me.imports.workspacePrefs;
function init() {
ExtensionUtils.initTranslations();
}
-const WindowListPrefsWidget = GObject.registerClass(
-class WindowListPrefsWidget extends Gtk.Grid {
- _init(params) {
- super._init(params);
-
- this.margin = 24;
- this.row_spacing = 6;
- this.orientation = Gtk.Orientation.VERTICAL;
+const WindowListPage = GObject.registerClass(
+class WindowListPage extends Gtk.Box {
+ _init() {
+ super._init({
+ orientation: Gtk.Orientation.VERTICAL,
+ spacing: 6,
+ margin_top: 36,
+ margin_bottom: 36,
+ margin_start: 36,
+ margin_end: 36,
+ halign: Gtk.Align.CENTER,
+ });
let groupingLabel = '<b>%s</b>'.format(_('Window Grouping'));
this.add(new Gtk.Label({
@@ -84,6 +90,33 @@ class WindowListPrefsWidget extends Gtk.Grid {
});
this._settings.bind('show-on-all-monitors', check, 'active', Gio.SettingsBindFlags.DEFAULT);
this.add(check);
+
+ this.show_all();
+ }
+});
+
+const WindowListPrefsWidget = GObject.registerClass(
+class WindowListPrefsWidget extends Gtk.Box {
+ _init() {
+ super._init({
+ orientation: Gtk.Orientation.VERTICAL,
+ spacing: 6,
+ });
+
+ const stack = new Gtk.Stack();
+ const stackSwitcher = new Gtk.StackSwitcher({
+ stack,
+ margin_top: 12,
+ halign: Gtk.Align.CENTER,
+ });
+
+ this.add(stackSwitcher);
+ this.add(stack);
+
+ this.show_all();
+
+ stack.add_titled(new WindowListPage(), 'window-list', _('Window List'));
+ stack.add_titled(new WorkspacesPage(), 'workspaces', _('Workspaces'));
}
});
--
2.50.0
From 7722bfec6e5f388c2bf0330b603a9728643c0248 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 22 May 2025 16:31:57 +0200
Subject: [PATCH 32/43] workspace-indicator: Remove left-over variable
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/405>
---
extensions/workspace-indicator/workspaceIndicator.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 3c1d5724..3207e87c 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -440,8 +440,6 @@ let WorkspaceIndicator = GObject.registerClass({
this._thumbnails = new WorkspacePreviews();
container.add_child(this._thumbnails);
- this._workspacesItems = [];
-
this._workspaceManagerSignals = [
workspaceManager.connect_after('notify::n-workspaces',
this._nWorkspacesChanged.bind(this)),
--
2.50.0
From 3d5f527d2215f49670df7d078910a3144da0f95e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 22 May 2025 16:27:57 +0200
Subject: [PATCH 33/43] workspace-indicator: Split out WorkspacesMenu
The menu currently only contains the previews without any logic
on its own. This is about to change, so split the menu into a
separate class.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/405>
---
.../workspace-indicator/workspaceIndicator.js | 181 +++++++++++-------
1 file changed, 110 insertions(+), 71 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 3207e87c..9bb7cb60 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -1,6 +1,7 @@
-const { Clutter, Gio, GObject, Meta, St } = imports.gi;
+const { Clutter, Gio, GLib, GObject, Meta, St } = imports.gi;
const DND = imports.ui.dnd;
+const ExtensionUtils = imports.misc.extensionUtils;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
@@ -403,6 +404,110 @@ const WorkspacePreviews = GObject.registerClass({
}
});
+class WorkspacesMenu extends PopupMenu.PopupMenu {
+ constructor(sourceActor) {
+ super(sourceActor, 0.5, St.Side.TOP);
+
+ this.actor.add_style_class_name(`${baseStyleClassName}-menu`);
+ this.actor.connect('destroy', () => this._onDestroy());
+
+ this._workspacesSection = new PopupMenu.PopupMenuSection();
+ this.addMenuItem(this._workspacesSection);
+
+ this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+
+ this.addAction(_('Settings'), () => {
+ const extension = ExtensionUtils.getCurrentExtension();
+
+ Gio.DBus.session.call(
+ 'org.gnome.Shell',
+ '/org/gnome/Shell',
+ 'org.gnome.Shell.Extensions',
+ 'LaunchExtensionPrefs',
+ new GLib.Variant('(s)', [extension.uuid]),
+ null,
+ Gio.DBusCallFlags.NONE,
+ -1,
+ null);
+ });
+
+ this._desktopSettings =
+ new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'});
+ this._workspaceNamesChangedId =
+ this._desktopSettings.connect('changed::workspace-names', () => {
+ this._updateWorkspaceLabels();
+ this.emit('active-name-changed');
+ });
+
+ const {workspaceManager} = global;
+ this._workspaceManagerSignals = [
+ workspaceManager.connect('notify::n-workspaces',
+ () => this._updateWorkspaceItems()),
+ workspaceManager.connect('workspace-switched',
+ () => this._updateActiveIndicator()),
+ ];
+ this._updateWorkspaceItems();
+ }
+
+ get activeName() {
+ const {workspaceManager} = global;
+ const active = workspaceManager.get_active_workspace_index();
+ return Meta.prefs_get_workspace_name(active);
+ }
+
+ _updateWorkspaceItems() {
+ const {workspaceManager} = global;
+ const {nWorkspaces} = workspaceManager;
+
+ const section = this._workspacesSection.actor;
+ while (section.get_n_children() < nWorkspaces) {
+ const item = new PopupMenu.PopupMenuItem('');
+ item.connect('activate', (o, event) => {
+ const index = section.get_children().indexOf(item.actor);
+ const workspace = workspaceManager.get_workspace_by_index(index);
+ if (workspace)
+ workspace.activate(event.get_time());
+ });
+ this._workspacesSection.addMenuItem(item);
+ }
+
+ const items = section.get_children();
+ items.splice(nWorkspaces).forEach(item => item.destroy());
+
+ this._updateWorkspaceLabels();
+ this._updateActiveIndicator();
+ }
+
+ _updateWorkspaceLabels() {
+ const items =
+ this._workspacesSection.actor.get_children().map(c => c._delegate);
+ items.forEach(
+ (item, i) => (item.label.text = Meta.prefs_get_workspace_name(i)));
+ }
+
+ _updateActiveIndicator() {
+ const {workspaceManager} = global;
+ const active = workspaceManager.get_active_workspace_index();
+
+ const items =
+ this._workspacesSection.actor.get_children().map(c => c._delegate);
+ items.forEach((item, i) => {
+ item.setOrnament(i === active
+ ? PopupMenu.Ornament.CHECK
+ : PopupMenu.Ornament.NONE);
+ });
+ this.emit('active-name-changed');
+ }
+
+ _onDestroy() {
+ for (const id of this._workspaceManagerSignals)
+ global.workspace_manager.disconnect(id);
+
+ this._desktopSettings.disconnect(this._workspaceNamesChangedId);
+ this._desktopSettings = null;
+ }
+}
+
let WorkspaceIndicator = GObject.registerClass({
GTypeName: `${TypePrefix}WorkspaceIndicator`
}, class WorkspaceIndicator extends PanelMenu.Button {
@@ -441,8 +546,6 @@ let WorkspaceIndicator = GObject.registerClass({
container.add_child(this._thumbnails);
this._workspaceManagerSignals = [
- workspaceManager.connect_after('notify::n-workspaces',
- this._nWorkspacesChanged.bind(this)),
workspaceManager.connect_after('workspace-switched',
this._onWorkspaceSwitched.bind(this)),
];
@@ -459,13 +562,6 @@ let WorkspaceIndicator = GObject.registerClass({
this._updateTopBarRedirect();
});
- this._updateMenu();
-
- this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' });
- this._settingsChangedId = this._desktopSettings.connect(
- 'changed::workspace-names',
- this._updateMenuLabels.bind(this));
-
this._settings.connect('changed::embed-previews',
() => this._updateThumbnailVisibility());
this._updateThumbnailVisibility();
@@ -475,11 +571,6 @@ let WorkspaceIndicator = GObject.registerClass({
for (let i = 0; i < this._workspaceManagerSignals.length; i++)
global.workspace_manager.disconnect(this._workspaceManagerSignals[i]);
- if (this._settingsChangedId) {
- this._desktopSettings.disconnect(this._settingsChangedId);
- this._settingsChangedId = 0;
- }
-
if (this._inTopBar)
Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
this._inTopBar = false;
@@ -494,6 +585,10 @@ let WorkspaceIndicator = GObject.registerClass({
this._statusLabel.visible = useMenu;
this._thumbnails.visible = !useMenu;
+ this.setMenu(useMenu
+ ? new WorkspacesMenu(this)
+ : null);
+
this._updateTopBarRedirect();
}
@@ -510,67 +605,11 @@ let WorkspaceIndicator = GObject.registerClass({
_onWorkspaceSwitched() {
this._currentWorkspace = global.workspace_manager.get_active_workspace_index();
-
- this._updateMenuOrnament();
-
this._statusLabel.set_text(this._getStatusText());
}
- _nWorkspacesChanged() {
- this._updateMenu();
- }
-
- _updateMenuOrnament() {
- for (let i = 0; i < this._workspacesItems.length; i++) {
- this._workspacesItems[i].setOrnament(i == this._currentWorkspace
- ? PopupMenu.Ornament.DOT
- : PopupMenu.Ornament.NONE);
- }
- }
-
_getStatusText() {
const current = this._currentWorkspace + 1;
return `${current}`;
}
-
- _updateMenuLabels() {
- for (let i = 0; i < this._workspacesItems.length; i++) {
- const item = this._workspacesItems[i];
- item.label.text = Meta.prefs_get_workspace_name(i);
- }
- }
-
- _updateMenu() {
- let workspaceManager = global.workspace_manager;
-
- this.menu.removeAll();
- this._workspacesItems = [];
- this._currentWorkspace = workspaceManager.get_active_workspace_index();
-
- for (let i = 0; i < workspaceManager.n_workspaces; i++) {
- const name = Meta.prefs_get_workspace_name(i);
- const item = new PopupMenu.PopupMenuItem(name);
-
- item.connect('activate',
- () => this._activate(i));
-
- item.setOrnament(i === this._currentWorkspace
- ? PopupMenu.Ornament.DOT
- : PopupMenu.Ornament.NONE);
-
- this.menu.addMenuItem(item);
- this._workspacesItems[i] = item;
- }
-
- this._statusLabel.set_text(this._getStatusText());
- }
-
- _activate(index) {
- let workspaceManager = global.workspace_manager;
-
- if (index >= 0 && index < workspaceManager.n_workspaces) {
- let metaWorkspace = workspaceManager.get_workspace_by_index(index);
- metaWorkspace.activate(global.get_current_time());
- }
- }
});
--
2.50.0
From ce6bbf7ba28a0a24045e460b3eeb47aabbeeebe6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 28 May 2025 02:16:33 +0200
Subject: [PATCH 34/43] workspace-indicator: Include menu with previews
The menu is currently only used when previews are disabled. But
as we are going to use the menu for changing workspace names, it
should be always available. So add it unconditionally, and show
it on right-click when using previews.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/405>
---
.../workspace-indicator/stylesheet-dark.css | 5 ++++
.../workspace-indicator/workspaceIndicator.js | 25 +++++++++++++------
2 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css
index 5663b422..6719c05a 100644
--- a/extensions/workspace-indicator/stylesheet-dark.css
+++ b/extensions/workspace-indicator/stylesheet-dark.css
@@ -1,3 +1,8 @@
+.workspace-indicator.previews:active {
+ background-color: none !important;
+ box-shadow: none !important;
+}
+
.workspace-indicator .status-label {
padding: 0 8px;
}
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 9bb7cb60..8184efbb 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -524,6 +524,8 @@ let WorkspaceIndicator = GObject.registerClass({
baseStyleClassName = baseStyleClass;
this.add_style_class_name(baseStyleClassName);
+ this.setMenu(new WorkspacesMenu(this));
+
let container = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_expand: true,
@@ -545,6 +547,14 @@ let WorkspaceIndicator = GObject.registerClass({
this._thumbnails = new WorkspacePreviews();
container.add_child(this._thumbnails);
+ this._thumbnails.connect('button-press-event', (a, event) => {
+ if (event.get_button() !== Clutter.BUTTON_SECONDARY)
+ return Clutter.EVENT_PROPAGATE;
+
+ this.menu.toggle();
+ return Clutter.EVENT_STOP;
+ });
+
this._workspaceManagerSignals = [
workspaceManager.connect_after('workspace-switched',
this._onWorkspaceSwitched.bind(this)),
@@ -579,15 +589,16 @@ let WorkspaceIndicator = GObject.registerClass({
}
_updateThumbnailVisibility() {
- const useMenu = !this._settings.get_boolean('embed-previews');
- this.reactive = useMenu;
+ const usePreviews = this._settings.get_boolean('embed-previews');
+ this.reactive = !usePreviews;
- this._statusLabel.visible = useMenu;
- this._thumbnails.visible = !useMenu;
+ this._thumbnails.visible = usePreviews;
+ this._statusLabel.visible = !usePreviews;
- this.setMenu(useMenu
- ? new WorkspacesMenu(this)
- : null);
+ if (usePreviews)
+ this.add_style_class_name('previews');
+ else
+ this.remove_style_class_name('previews');
this._updateTopBarRedirect();
}
--
2.50.0
From d79cb50745803a7e6e7dc663580f1fb233b9130a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 22 May 2025 20:59:58 +0200
Subject: [PATCH 35/43] workspace-indicator: Show full name when using menu
With workspace names becoming a more prominent feature, it makes
sense to expose them without opening the menu.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/405>
---
.../workspace-indicator/stylesheet-dark.css | 8 +++++
.../workspace-indicator/workspaceIndicator.js | 32 +++++++------------
2 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css
index 6719c05a..cb0c6e62 100644
--- a/extensions/workspace-indicator/stylesheet-dark.css
+++ b/extensions/workspace-indicator/stylesheet-dark.css
@@ -4,8 +4,16 @@
}
.workspace-indicator .status-label {
+ width: 8em;
padding: 0 8px;
}
+.workspace-indicator .status-label:ltr { padding-right: 4px; }
+.workspace-indicator .status-label:rtl { padding-left: 4px; }
+
+.workspace-indicator .system-status-icon {
+ padding: 0 !important;
+ margin: 0 !important;
+}
.workspace-indicator .workspaces-view.hfade {
-st-hfade-offset: 20px;
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 8184efbb..2cd3de5f 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -533,16 +533,23 @@ let WorkspaceIndicator = GObject.registerClass({
});
this.add_actor(container);
- let workspaceManager = global.workspace_manager;
+ this._statusBox = new St.BoxLayout();
+ container.add_child(this._statusBox);
- this._currentWorkspace = workspaceManager.get_active_workspace_index();
this._statusLabel = new St.Label({
style_class: 'status-label',
+ x_expand: true,
y_align: Clutter.ActorAlign.CENTER,
- text: this._getStatusText(),
+ text: this.menu.activeName,
});
+ this._statusBox.add_child(this._statusLabel);
+ this._statusBox.add_child(new St.Icon({
+ icon_name: 'pan-down-symbolic',
+ style_class: 'system-status-icon',
+ }));
- container.add_actor(this._statusLabel);
+ this.menu.connect('active-name-changed',
+ () => this._statusLabel.set_text(this.menu.activeName));
this._thumbnails = new WorkspacePreviews();
container.add_child(this._thumbnails);
@@ -555,11 +562,6 @@ let WorkspaceIndicator = GObject.registerClass({
return Clutter.EVENT_STOP;
});
- this._workspaceManagerSignals = [
- workspaceManager.connect_after('workspace-switched',
- this._onWorkspaceSwitched.bind(this)),
- ];
-
this.connect('scroll-event',
(o, event) => this._thumbnails.handleScrollEvent(event));
@@ -593,7 +595,7 @@ let WorkspaceIndicator = GObject.registerClass({
this.reactive = !usePreviews;
this._thumbnails.visible = usePreviews;
- this._statusLabel.visible = !usePreviews;
+ this._statusBox.visible = !usePreviews;
if (usePreviews)
this.add_style_class_name('previews');
@@ -613,14 +615,4 @@ let WorkspaceIndicator = GObject.registerClass({
? Clutter.OffscreenRedirect.ALWAYS
: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY);
}
-
- _onWorkspaceSwitched() {
- this._currentWorkspace = global.workspace_manager.get_active_workspace_index();
- this._statusLabel.set_text(this._getStatusText());
- }
-
- _getStatusText() {
- const current = this._currentWorkspace + 1;
- return `${current}`;
- }
});
--
2.50.0
From bbcbd818726d387a5720686d483c2c79463d84b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 9 Jun 2025 18:10:14 +0200
Subject: [PATCH 36/43] workspace-indicator: Add background when using name
label
Panel buttons are flat, so the name+arrow are not immediately
recognizable as a single control. Address this by adding a
background to the button when using the name label.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/405>
---
extensions/workspace-indicator/stylesheet-dark.css | 14 ++++++++++++++
.../workspace-indicator/stylesheet-light.css | 14 ++++++++++++++
.../workspace-indicator/workspaceIndicator.js | 7 +++++--
3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css
index cb0c6e62..7a40664d 100644
--- a/extensions/workspace-indicator/stylesheet-dark.css
+++ b/extensions/workspace-indicator/stylesheet-dark.css
@@ -3,6 +3,20 @@
box-shadow: none !important;
}
+.workspace-indicator.name-label {
+ box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17) !important;
+}
+.workspace-indicator.name-label:hover,
+.workspace-indicator.name-label:focus {
+ box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28) !important;
+}
+.workspace-indicator.name-label:active {
+ box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32) !important;
+}
+.workspace-indicator.name-label:active:hover {
+ box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.36) !important;
+}
+
.workspace-indicator .status-label {
width: 8em;
padding: 0 8px;
diff --git a/extensions/workspace-indicator/stylesheet-light.css b/extensions/workspace-indicator/stylesheet-light.css
index 049b6a38..5191923c 100644
--- a/extensions/workspace-indicator/stylesheet-light.css
+++ b/extensions/workspace-indicator/stylesheet-light.css
@@ -7,6 +7,20 @@
@import url("stylesheet-dark.css");
+.workspace-indicator.name-label {
+ box-shadow: inset 0 0 0 100px rgba(34, 34, 38, 0.17) !important;
+}
+.workspace-indicator.name-label:hover,
+.workspace-indicator.name-label:focus {
+ box-shadow: inset 0 0 0 100px rgba(34, 34, 38, 0.28) !important;
+}
+.workspace-indicator.name-label:active {
+ box-shadow: inset 0 0 0 100px rgba(34, 34, 38, 0.32) !important;
+}
+.workspace-indicator.name-label:active:hover {
+ box-shadow: inset 0 0 0 100px rgba(34, 34, 38, 0.36) !important;
+}
+
.workspace-indicator .workspace {
background-color: #ccc;
}
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 2cd3de5f..0a4f33bf 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -597,10 +597,13 @@ let WorkspaceIndicator = GObject.registerClass({
this._thumbnails.visible = usePreviews;
this._statusBox.visible = !usePreviews;
- if (usePreviews)
+ if (usePreviews) {
this.add_style_class_name('previews');
- else
+ this.remove_style_class_name('name-label');
+ } else {
this.remove_style_class_name('previews');
+ this.add_style_class_name('name-label');
+ }
this._updateTopBarRedirect();
}
--
2.50.0
From 98db3fef2833ced71efe41de14ffd81780b304e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 22 May 2025 21:07:08 +0200
Subject: [PATCH 37/43] workspace-indicator: Reimplement some libadwaita prefs
widgets
Upstream now makes more use of libawaita, so reimplement the API we
need to make backporting a bit less painful.
---
.../workspace-indicator/workspacePrefs.js | 239 ++++++++++++++++++
1 file changed, 239 insertions(+)
diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js
index 0bd4a58b..11155f8a 100644
--- a/extensions/workspace-indicator/workspacePrefs.js
+++ b/extensions/workspace-indicator/workspacePrefs.js
@@ -16,6 +16,245 @@ const N_ = e => e;
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
const WORKSPACE_KEY = 'workspace-names';
+const PreferencesGroup = GObject.registerClass({
+ Properties: {
+ 'title': GObject.ParamSpec.string(
+ 'title', '', '',
+ GObject.ParamFlags.READWRITE,
+ null),
+ },
+}, class PreferencesGroup extends Gtk.Box {
+ _init(params) {
+ super._init({
+ ...params,
+ orientation: Gtk.Orientation.VERTICAL,
+ });
+
+ const titleLabel = new Gtk.Label({
+ halign: Gtk.Align.START,
+ });
+ titleLabel.get_style_context().add_class('heading');
+
+ this.bind_property('title',
+ titleLabel, 'label',
+ GObject.BindingFlags.SYNC_CREATE);
+ this.add(titleLabel);
+
+ this._list = new Gtk.ListBox({
+ selection_mode: Gtk.SelectionMode.NONE,
+ valign: Gtk.Align.START,
+ //show_separators: true,
+ });
+ this._list.get_style_context().add_class('boxed-list');
+ this.add(this._list);
+
+ this._list.connect('row-activated',
+ (l, row) => row.activate());
+ }
+
+ get title() {
+ return this._title || '';
+ }
+
+ set title(title) {
+ if (this._title === title)
+ return;
+
+ this._title = title;
+ this.notify('title');
+ }
+
+ append(child) {
+ this._list.add(child);
+ }
+
+ remove(child) {
+ this._list.remove(child);
+ }
+});
+
+const ActionRow = GObject.registerClass({
+ Properties: {
+ 'title': GObject.ParamSpec.string(
+ 'title', '', '',
+ GObject.ParamFlags.READWRITE,
+ null),
+ 'subtitle': GObject.ParamSpec.string(
+ 'subtitle', '', '',
+ GObject.ParamFlags.READWRITE,
+ null),
+ 'activatable-widget': GObject.ParamSpec.object(
+ 'activatable-widget', '', '',
+ GObject.ParamFlags.READWRITE,
+ Gtk.Widget),
+ },
+}, class ActionRow extends Gtk.ListBoxRow {
+ _init(params) {
+ super._init(params);
+
+ const provider = new Gtk.CssProvider();
+ provider.load_from_data(`* {
+ /*border-spacing: 6px 6px;*/
+ min-height: 40px;
+ margin-left: 12px;
+ margin-right: 12px;
+ }`);
+
+ const mainBox = new Gtk.Box({
+ valign: Gtk.Align.CENTER,
+ hexpand: false,
+ });
+ mainBox.get_style_context().add_provider(provider,
+ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+ this.add(mainBox);
+
+ this._prefixes = new Gtk.Box({
+ visible: false,
+ });
+ mainBox.add(this._prefixes);
+
+ const titleBox = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ valign: Gtk.Align.CENTER,
+ hexpand: true,
+ });
+ mainBox.add(titleBox);
+
+ this._suffixes = new Gtk.Box({
+ visible: false,
+ });
+ mainBox.add(this._suffixes);
+
+ const titleLabel = new Gtk.Label({
+ lines: 0,
+ wrap: true,
+ wrap_mode: Pango.WrapMode.WORD_CHAR,
+ xalign: 0,
+ });
+
+ this.bind_property('title',
+ titleLabel, 'label',
+ GObject.BindingFlags.SYNC_CREATE);
+ titleBox.add(titleLabel);
+
+ const subtitleLabel = new Gtk.Label({
+ ellipsize: Pango.EllipsizeMode.NONE,
+ lines: 0,
+ wrap: true,
+ wrap_mode: Pango.WrapMode.WORD_CHAR,
+ xalign: 0,
+ no_show_all: true,
+ visible: this.subtitle.length > 0,
+ });
+ subtitleLabel.get_style_context().add_class('dim-label');
+
+ this.bind_property('subtitle',
+ subtitleLabel, 'label',
+ GObject.BindingFlags.SYNC_CREATE);
+ titleBox.add(subtitleLabel);
+ }
+
+ get title() {
+ return this._title || '';
+ }
+
+ set title(title) {
+ if (this._title === title)
+ return;
+
+ this._title = title;
+ this.notify('title');
+ }
+
+ get subtitle() {
+ return this._subtitle || '';
+ }
+
+ set subtitle(subtitle) {
+ if (this._subtitle === subtitle)
+ return;
+
+ this._subtitle = subtitle;
+ this.notify('subtitle');
+ }
+
+ get activitable_widget() {
+ return this._activatableWidget;
+ }
+
+ set activatable_widget(widget) {
+ if (this._activatableWidget === widget)
+ return;
+
+ this._activatableWidget = widget;
+ this.notify('activatable-widget');
+ }
+
+ add_prefix(child) {
+ this._prefixes.add(child);
+ this._prefixes.set_visible(true);
+ }
+
+ add_suffix(child) {
+ this._suffixes.add(child);
+ this._suffixes.set_visible(true);
+ }
+
+ activate() {
+ if (this._activatableWidget)
+ this._activatableWidget.mnemonic_activate(false);
+ }
+});
+
+const SpinRow = GObject.registerClass({
+ Properties: {
+ 'adjustment': GObject.ParamSpec.object(
+ 'adjustment', '', '',
+ GObject.ParamFlags.READWRITE,
+ Gtk.Adjustment),
+ 'value': GObject.ParamSpec.double(
+ 'value', '', '',
+ GObject.ParamFlags.READWRITE,
+ -Infinity, Infinity, 0),
+ },
+}, class SpinRow extends ActionRow {
+ _init(params) {
+ this._spinButton = new Gtk.SpinButton({
+ valign: Gtk.Align.CENTER,
+ hexpand: true,
+ xalign: 1,
+ });
+ super._init(params);
+ this.add_suffix(this._spinButton);
+ }
+
+ get adjustment() {
+ return this._spinButton.get_adjustment();
+ }
+
+ set adjustment(adj) {
+ if (this.adjustment === adj)
+ return;
+
+ this._spinButton.set_adjustment(adj);
+ this.notify('adjustment');
+ }
+
+ get value() {
+ return this._spinButton.get_value();
+ }
+
+ set value(value) {
+ const EPSILON = 0.005;
+
+ if (Math.abs(this.value, value) < EPSILON)
+ return;
+
+ this._spinButton.set_value(value);
+ this.notify('value');
+ }
+});
+
const GeneralGroup = GObject.registerClass(
class GeneralGroup extends Gtk.Box {
_init() {
--
2.50.0
From c3d54e0e0c120ad09f15f9c95d215e14e8f0334d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sun, 29 Jun 2025 21:26:40 +0200
Subject: [PATCH 38/43] workspace-indicator: Refine preview settings
Add a group title, and change the single switch row to radio rows
to explicitly choose between "Previews" and "Workspace Name".
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/405>
---
.../workspace-indicator/workspacePrefs.js | 35 ++++++++++++-------
1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js
index 11155f8a..e33d4716 100644
--- a/extensions/workspace-indicator/workspacePrefs.js
+++ b/extensions/workspace-indicator/workspacePrefs.js
@@ -256,29 +256,38 @@ const SpinRow = GObject.registerClass({
});
const GeneralGroup = GObject.registerClass(
-class GeneralGroup extends Gtk.Box {
+class GeneralGroup extends PreferencesGroup {
_init() {
super._init({
- orientation: Gtk.Orientation.VERTICAL,
+ title: _('Indicator'),
});
- const row = new Gtk.Box();
- this.add(row);
-
- row.add(new Gtk.Label({
- label: _('Show Previews'),
- }));
+ const previewCheck = new Gtk.RadioButton();
+ const previewRow = new ActionRow({
+ title: _('Previews'),
+ activatable_widget: previewCheck,
+ });
+ previewRow.add_prefix(previewCheck);
+ this.append(previewRow);
- const sw = new Gtk.Switch({
- hexpand: true,
- halign: Gtk.Align.END,
+ const nameCheck = new Gtk.RadioButton({
+ group: previewCheck,
+ });
+ const nameRow = new ActionRow({
+ title: _('Workspace Name'),
+ activatable_widget: nameCheck,
});
- row.add(sw);
+ nameRow.add_prefix(nameCheck);
+ this.append(nameRow);
const settings = ExtensionUtils.getSettings();
+ if (settings.get_boolean('embed-previews'))
+ previewCheck.active = true;
+ else
+ nameCheck.active = true;
settings.bind('embed-previews',
- sw, 'active',
+ previewCheck, 'active',
Gio.SettingsBindFlags.DEFAULT);
}
});
--
2.50.0
From 2ce2e4439e13d1fa48502fdda7cff7dd41302482 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 22 May 2025 16:20:05 +0200
Subject: [PATCH 39/43] workspace-indicator: Include workspace settings
While the "Multitasking" panel in Settings already exposes workspace
settings, it makes sense to expose them in our prefs dialog as well
where they are more in context.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/405>
---
.../workspace-indicator/workspacePrefs.js | 67 +++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js
index e33d4716..316666ed 100644
--- a/extensions/workspace-indicator/workspacePrefs.js
+++ b/extensions/workspace-indicator/workspacePrefs.js
@@ -292,6 +292,72 @@ class GeneralGroup extends PreferencesGroup {
}
});
+const BehaviorGroup = GObject.registerClass(
+class BehaviorGroup extends PreferencesGroup {
+ _init() {
+ super._init({
+ title: _('Behavior'),
+ });
+
+ const dynamicCheck = new Gtk.RadioButton();
+ const dynamicRow = new ActionRow({
+ title: _('Dynamic'),
+ subtitle: _('Automatically removes empty workspaces.'),
+ activatable_widget: dynamicCheck,
+ });
+ dynamicRow.add_prefix(dynamicCheck);
+ this.append(dynamicRow);
+
+ const fixedCheck = new Gtk.RadioButton({
+ group: dynamicCheck,
+ });
+ const fixedRow = new ActionRow({
+ title: _('Fixed Number'),
+ subtitle: _('Specify a number of permanent workspaces.'),
+ activatable_widget: fixedCheck,
+ });
+ fixedRow.add_prefix(fixedCheck);
+ this.append(fixedRow);
+
+ const adjustment = new Gtk.Adjustment({
+ lower: 1,
+ step_increment: 1,
+ value: 4,
+ upper: 36, // hard limit in mutter
+ });
+ const numRow = new SpinRow({
+ title: _('Number of Workspaces'),
+ adjustment,
+ });
+ this.append(numRow);
+
+ const mutterSettings = new Gio.Settings({
+ schema_id: 'org.gnome.mutter',
+ });
+
+ if (mutterSettings.get_boolean('dynamic-workspaces'))
+ dynamicCheck.active = true;
+ else
+ fixedCheck.active = true;
+
+ mutterSettings.bind('dynamic-workspaces',
+ dynamicCheck, 'active',
+ Gio.SettingsBindFlags.DEFAULT);
+
+ const desktopSettings = new Gio.Settings({
+ schema_id: 'org.gnome.desktop.wm.preferences',
+ });
+
+ desktopSettings.bind('num-workspaces',
+ numRow, 'value',
+ Gio.SettingsBindFlags.DEFAULT);
+
+ fixedCheck.bind_property('active',
+ numRow, 'sensitive',
+ GObject.BindingFlags.SYNC_CREATE);
+ }
+});
+
const WorkspaceNameModel = GObject.registerClass(
class WorkspaceNameModel extends Gtk.ListStore {
_init(params) {
@@ -420,6 +486,7 @@ class WorkspacesPage extends Gtk.ScrolledWindow {
this.add(box);
box.add(new GeneralGroup());
+ box.add(new BehaviorGroup());
box.add(new Gtk.Label({
label: '<b>%s</b>'.format(_('Workspace Names')),
--
2.50.0
From 55746c9d3ef546feed2e473382c42f11245ea82f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 28 May 2025 21:01:08 +0200
Subject: [PATCH 40/43] workspace-indicator: Allow changing workspace names
from menu
Instead of requiring the user to open the prefs dialog to change
workspace names, make the menu items themselves editable.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/405>
---
.../workspace-indicator/stylesheet-dark.css | 48 +++++++
.../workspace-indicator/stylesheet-light.css | 16 +++
.../workspace-indicator/workspaceIndicator.js | 130 +++++++++++++++++-
3 files changed, 192 insertions(+), 2 deletions(-)
diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css
index 7a40664d..a74d25b5 100644
--- a/extensions/workspace-indicator/stylesheet-dark.css
+++ b/extensions/workspace-indicator/stylesheet-dark.css
@@ -58,3 +58,51 @@
.workspace-indicator-window-preview.active {
background-color: #d4d4d4;
}
+
+.workspace-indicator-menu {
+ min-width: 17em;
+}
+
+.workspace-indicator-menu .editable-menu-item.popup-menu-item {
+ padding: 3px 12px;
+}
+
+.workspace-indicator-menu .editable-menu-item .icon-button {
+ border-radius: 99px;
+ padding: 6px;
+}
+
+.workspace-indicator-menu .editable-menu-item .icon-button.flat {
+ background-color: transparent;
+}
+
+.workspace-indicator-menu .editable-menu-item .icon-button.flat:hover {
+ background-color: rgba(255, 255, 255, 0.1);
+}
+
+.workspace-indicator-menu .editable-menu-item .icon-button.flat:active {
+ background-color: rgba(255, 255, 255, 0.15);
+}
+
+.workspace-indicator-menu .editable-menu-item .icon-button.flat:checked {
+ color: white;
+ background-color: #3584e4;
+}
+
+.workspace-indicator-menu .editable-menu-item .icon-button.flat:checked:hover {
+ background-color: #629fea;
+}
+
+.workspace-indicator-menu .editable-menu-item .icon-button.flat:checked:active {
+ background-color: #78aded;
+}
+
+.workspace-indicator-menu .editable-menu-item .label {
+ padding: 0 11px;
+ width: 6.5em;
+}
+
+.workspace-indicator-menu .editable-menu-item .entry {
+ padding: 9px 9px;
+ width: 6.5em;
+}
diff --git a/extensions/workspace-indicator/stylesheet-light.css b/extensions/workspace-indicator/stylesheet-light.css
index 5191923c..e4f2b45a 100644
--- a/extensions/workspace-indicator/stylesheet-light.css
+++ b/extensions/workspace-indicator/stylesheet-light.css
@@ -37,3 +37,19 @@
.workspace-indicator-window-preview.active {
background-color: #f6f5f4;
}
+
+.workspace-indicator-menu .editable-menu-item .icon-button.flat:hover {
+ background-color: rgba(0, 0, 0, 0.1);
+}
+
+.workspace-indicator-menu .editable-menu-item .icon-button.flat:active {
+ background-color: rgba(0, 0, 0, 0.15);
+}
+
+.workspace-indicator-menu .editable-menu-item .icon-button.flat:checked:hover {
+ background-color: #1b6acb;
+}
+
+.workspace-indicator-menu .editable-menu-item .icon-button.flat:checked:active {
+ background-color: #185fb4;
+}
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 0a4f33bf..5a8a819c 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -1,4 +1,4 @@
-const { Clutter, Gio, GLib, GObject, Meta, St } = imports.gi;
+const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const DND = imports.ui.dnd;
const ExtensionUtils = imports.misc.extensionUtils;
@@ -7,6 +7,8 @@ const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Tweener = imports.ui.tweener;
+const Signals = imports.signals;
+
const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
@@ -404,6 +406,122 @@ const WorkspacePreviews = GObject.registerClass({
}
});
+class EditableMenuItem extends PopupMenu.PopupBaseMenuItem {
+ constructor() {
+ super({
+ style_class: 'editable-menu-item',
+ });
+ this.actor.get_accessible().set_description(0,
+ _('Press %s to edit').format('e'));
+
+ this._ornamentLabel.y_align = Clutter.ActorAlign.CENTER;
+
+ const stack = new Shell.Stack({
+ x_expand: true,
+ x_align: Clutter.ActorAlign.START,
+ });
+ this.actor.add_child(stack);
+
+ this.label = new St.Label({
+ style_class: 'label',
+ y_align: Clutter.ActorAlign.CENTER,
+ });
+ stack.add_child(this.label);
+ this.actor.label_actor = this.label;
+
+ this._entry = new St.Entry({
+ style_class: 'entry',
+ opacity: 0,
+ reactive: false,
+ });
+ stack.add_child(this._entry);
+
+ this.label.bind_property('text',
+ this._entry, 'text',
+ GObject.BindingFlags.DEFAULT);
+
+ this._entry.clutter_text.connect('activate',
+ () => this._stopEditing());
+
+ this._editButton = new St.Button({
+ style_class: 'icon-button flat',
+ child: new St.Icon({
+ icon_name: 'document-edit-symbolic',
+ icon_size: 16,
+ }),
+ button_mask: St.ButtonMask.ONE,
+ toggle_mode: true,
+ });
+ this._editButton.set_x_align(Clutter.ActorAlign.END);
+ this._editButton.set_y_align(Clutter.ActorAlign.CENTER);
+ this.actor.add_child(this._editButton);
+
+ this._editButton.connect('notify::checked', () => {
+ if (this._editButton.checked) {
+ this._editButton.child.icon_name = 'object-select-symbolic';
+ this._startEditing();
+ } else {
+ this._editButton.child.icon_name = 'document-edit-symbolic';
+ this._stopEditing();
+ }
+ });
+ this.actor.connect('key-release-event', (o, event) => {
+ if (event.get_key_symbol() === Clutter.KEY_e)
+ this._editButton.checked = true;
+ });
+
+ this._keyFocusId = global.stage.connect('notify::key-focus', () => {
+ const {keyFocus} = global.stage;
+ if (!keyFocus || !this.actor.contains(keyFocus))
+ this._stopEditing();
+ });
+
+ this.actor.connect('destroy', () => {
+ global.stage.disconnect(this._keyFocusId);
+ delete this._keyFocusId;
+ });
+ }
+
+ _switchActor(from, to) {
+ to.reactive = true;
+ Tweener.addTween(to, {
+ opacity: 255,
+ time: 0.3,
+ transition: 'easeOutQuad',
+ });
+
+ Tweener.addTween(from, {
+ opacity: 0,
+ time: 0.3,
+ transition: 'easeOutQuad',
+ onComplete: () => {
+ from.reactive = false;
+ },
+ });
+ }
+
+ _startEditing() {
+ this._switchActor(this.label, this._entry);
+
+ this._entry.clutter_text.set_selection(0, -1);
+ this._entry.clutter_text.grab_key_focus();
+ }
+
+ _stopEditing() {
+ if (this.label.text !== this._entry.text) {
+ this.label.text = this._entry.text;
+ this.emit('edited');
+ }
+
+ if (this._editButton.checked)
+ this._editButton.checked = false;
+
+ this._switchActor(this._entry, this.label);
+ this.actor.navigate_focus(this.actor, St.DirectionType.TAB_FORWARD, false);
+ }
+}
+Signals.addSignalMethods(EditableMenuItem.prototype);
+
class WorkspacesMenu extends PopupMenu.PopupMenu {
constructor(sourceActor) {
super(sourceActor, 0.5, St.Side.TOP);
@@ -461,13 +579,21 @@ class WorkspacesMenu extends PopupMenu.PopupMenu {
const section = this._workspacesSection.actor;
while (section.get_n_children() < nWorkspaces) {
- const item = new PopupMenu.PopupMenuItem('');
+ const item = new EditableMenuItem();
item.connect('activate', (o, event) => {
const index = section.get_children().indexOf(item.actor);
const workspace = workspaceManager.get_workspace_by_index(index);
if (workspace)
workspace.activate(event.get_time());
});
+ item.connect('edited', () => {
+ const nLabels = section.get_n_children();
+ const oldNames = this._desktopSettings.get_strv('workspace-names');
+ const newNames =
+ section.get_children().map(c => c._delegate.label.text);
+ this._desktopSettings.set_strv('workspace-names',
+ [...newNames, ...oldNames.slice(nLabels)]);
+ });
this._workspacesSection.addMenuItem(item);
}
--
2.50.0
From 9fd65412c1ebdb6c4c4f1026f95de72e985dcd1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 28 May 2025 21:04:36 +0200
Subject: [PATCH 41/43] workspace-indicator: Remove workspace names from prefs
Now that names can be changed from the extension itself, we no
longer need to expose them in the prefs dialog.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/405>
---
.../workspace-indicator/workspacePrefs.js | 181 +-----------------
1 file changed, 1 insertion(+), 180 deletions(-)
diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js
index 316666ed..bc4b3d01 100644
--- a/extensions/workspace-indicator/workspacePrefs.js
+++ b/extensions/workspace-indicator/workspacePrefs.js
@@ -4,17 +4,13 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* exported WorkspacesPage */
-const { Gio, GLib, GObject, Gtk, Pango } = imports.gi;
+const { Gio, GObject, Gtk, Pango } = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']);
const _ = Gettext.gettext;
-const N_ = e => e;
-
-const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
-const WORKSPACE_KEY = 'workspace-names';
const PreferencesGroup = GObject.registerClass({
Properties: {
@@ -358,114 +354,6 @@ class BehaviorGroup extends PreferencesGroup {
}
});
-const WorkspaceNameModel = GObject.registerClass(
-class WorkspaceNameModel extends Gtk.ListStore {
- _init(params) {
- super._init(params);
- this.set_column_types([GObject.TYPE_STRING]);
-
- this.Columns = {
- LABEL: 0,
- };
-
- this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA });
- //this._settings.connect('changed::workspace-names', this._reloadFromSettings.bind(this));
-
- this._reloadFromSettings();
-
- // overriding class closure doesn't work, because GtkTreeModel
- // plays tricks with marshallers and class closures
- this.connect('row-changed', this._onRowChanged.bind(this));
- this.connect('row-inserted', this._onRowInserted.bind(this));
- this.connect('row-deleted', this._onRowDeleted.bind(this));
- }
-
- _reloadFromSettings() {
- if (this._preventChanges)
- return;
- this._preventChanges = true;
-
- let newNames = this._settings.get_strv(WORKSPACE_KEY);
-
- let i = 0;
- let [ok, iter] = this.get_iter_first();
- while (ok && i < newNames.length) {
- this.set(iter, [this.Columns.LABEL], [newNames[i]]);
-
- ok = this.iter_next(iter);
- i++;
- }
-
- while (ok)
- ok = this.remove(iter);
-
- for ( ; i < newNames.length; i++) {
- iter = this.append();
- this.set(iter, [this.Columns.LABEL], [newNames[i]]);
- }
-
- this._preventChanges = false;
- }
-
- _onRowChanged(self, path, iter) {
- if (this._preventChanges)
- return;
- this._preventChanges = true;
-
- let index = path.get_indices()[0];
- let names = this._settings.get_strv(WORKSPACE_KEY);
-
- if (index >= names.length) {
- // fill with blanks
- for (let i = names.length; i <= index; i++)
- names[i] = '';
- }
-
- names[index] = this.get_value(iter, this.Columns.LABEL);
-
- this._settings.set_strv(WORKSPACE_KEY, names);
-
- this._preventChanges = false;
- }
-
- _onRowInserted(self, path, iter) {
- if (this._preventChanges)
- return;
- this._preventChanges = true;
-
- let index = path.get_indices()[0];
- let names = this._settings.get_strv(WORKSPACE_KEY);
- let label = this.get_value(iter, this.Columns.LABEL) || '';
- names.splice(index, 0, label);
-
- this._settings.set_strv(WORKSPACE_KEY, names);
-
- this._preventChanges = false;
- }
-
- _onRowDeleted(self, path) {
- if (this._preventChanges)
- return;
- this._preventChanges = true;
-
- let index = path.get_indices()[0];
- let names = this._settings.get_strv(WORKSPACE_KEY);
-
- if (index >= names.length)
- return;
-
- names.splice(index, 1);
-
- // compact the array
- for (let i = names.length - 1; i >= 0 && !names[i]; i++)
- names.pop();
-
- this._settings.set_strv(WORKSPACE_KEY, names);
-
- this._preventChanges = false;
- }
-});
-
var WorkspacesPage = GObject.registerClass(
class WorkspacesPage extends Gtk.ScrolledWindow {
_init() {
@@ -488,73 +376,6 @@ class WorkspacesPage extends Gtk.ScrolledWindow {
box.add(new GeneralGroup());
box.add(new BehaviorGroup());
- box.add(new Gtk.Label({
- label: '<b>%s</b>'.format(_('Workspace Names')),
- use_markup: true,
- margin_bottom: 6,
- hexpand: true,
- halign: Gtk.Align.START
- }));
-
- this._store = new WorkspaceNameModel();
- this._treeView = new Gtk.TreeView({
- model: this._store,
- headers_visible: false,
- reorderable: true,
- hexpand: true,
- vexpand: true
- });
-
- let column = new Gtk.TreeViewColumn({ title: _('Name') });
- let renderer = new Gtk.CellRendererText({ editable: true });
- renderer.connect('edited', this._cellEdited.bind(this));
- column.pack_start(renderer, true);
- column.add_attribute(renderer, 'text', this._store.Columns.LABEL);
- this._treeView.append_column(column);
-
- box.add(this._treeView);
-
- let toolbar = new Gtk.Toolbar({ icon_size: Gtk.IconSize.SMALL_TOOLBAR });
- toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR);
-
- let newButton = new Gtk.ToolButton({ icon_name: 'list-add-symbolic' });
- newButton.connect('clicked', this._newClicked.bind(this));
- toolbar.add(newButton);
-
- let delButton = new Gtk.ToolButton({ icon_name: 'list-remove-symbolic' });
- delButton.connect('clicked', this._delClicked.bind(this));
- toolbar.add(delButton);
-
- let selection = this._treeView.get_selection();
- selection.connect('changed', () => {
- delButton.sensitive = selection.count_selected_rows() > 0;
- });
- delButton.sensitive = selection.count_selected_rows() > 0;
-
- box.add(toolbar);
-
this.show_all();
}
-
- _cellEdited(renderer, path, newText) {
- let [ok, iter] = this._store.get_iter_from_string(path);
-
- if (ok)
- this._store.set(iter, [this._store.Columns.LABEL], [newText]);
- }
-
- _newClicked() {
- let iter = this._store.append();
- let index = this._store.get_path(iter).get_indices()[0];
-
- let label = _('Workspace %d').format(index + 1);
- this._store.set(iter, [this._store.Columns.LABEL], [label]);
- }
-
- _delClicked() {
- let [any, model_, iter] = this._treeView.get_selection().get_selected();
-
- if (any)
- this._store.remove(iter);
- }
});
--
2.50.0
From f6520c27519ae3bf7a9aa9c52eeaa2a908cbe44f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 30 May 2025 16:39:22 +0200
Subject: [PATCH 42/43] window-list: Adjust to workspace-indicator changes
Keep the `.panel-button` class to get the expected hover/focus/active
styling when using a regular menu button, but remove the horizontal
padding when using previews for fittsability.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/405>
---
extensions/window-list/extension.js | 6 ------
extensions/window-list/stylesheet.css | 5 +++++
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index b2357939..37b5ea09 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -1236,12 +1236,6 @@ class WindowList {
const BottomWorkspaceIndicator = GObject.registerClass(
class BottomWorkspaceIndicator extends WorkspaceIndicator {
- _init(params) {
- super._init(params);
-
- this.remove_style_class_name('panel-button');
- }
-
setMenu(menu) {
super.setMenu(menu);
diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css
index 349404c5..7da8ac7a 100644
--- a/extensions/window-list/stylesheet.css
+++ b/extensions/window-list/stylesheet.css
@@ -13,6 +13,11 @@
height: 2.25em;
}
+.window-list-workspace-indicator.previews {
+ -natural-hpadding: 0 !important;
+ -minimum-hpadding: 0 !important;
+}
+
.window-list {
spacing: 2px;
font-size: 10pt;
--
2.50.0
From cea785875ba9f155031ab94cbb3a61abba546252 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 2 Jul 2024 19:04:10 +0200
Subject: [PATCH 43/43] workspace-indicator: Re-fittsify workspace previews
For the window-list extension, it is important that the workspace
previews extend to the bottom edge for easier click targets.
That broke while merging the code with the workspace-indicator,
fix it again by moving the padding from the parent box into the
thumbnail children.
---
.../workspace-indicator/stylesheet-dark.css | 16 ++++++++++++-
.../workspace-indicator/workspaceIndicator.js | 23 +++++++++++++++----
2 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css
index a74d25b5..acf63524 100644
--- a/extensions/workspace-indicator/stylesheet-dark.css
+++ b/extensions/workspace-indicator/stylesheet-dark.css
@@ -34,10 +34,24 @@
}
.workspace-indicator .workspaces-box {
- padding: 5px;
spacing: 3px;
}
+.workspace-indicator .workspace-box {
+ padding-top: 5px;
+ padding-bottom: 5px;
+}
+
+.workspace-indicator StButton:first-child:ltr > .workspace-box,
+.workspace-indicator StButton:last-child:rtl > .workspace-box {
+ padding-left: 5px;
+}
+
+.workspace-indicator StButton:last-child:ltr > .workspace-box,
+.workspace-indicator StButton:first-child:rtl > .workspace-box {
+ padding-right: 5px;
+}
+
.workspace-indicator .workspace {
width: 52px;
border: 1px solid transparent;
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 5a8a819c..89099b31 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -120,14 +120,27 @@ let WorkspaceThumbnail = GObject.registerClass({
}, class WorkspaceThumbnail extends St.Button {
_init(index) {
super._init({
+ y_fill: true,
+ });
+
+ const box = new St.BoxLayout({
+ style_class: 'workspace-box',
+ y_expand: true,
+ vertical: true,
+ });
+ this.set_child(box);
+
+ this._preview = new St.Bin({
style_class: 'workspace',
child: new Clutter.Actor({
layout_manager: new WorkspaceLayout(),
clip_to_allocation: true
}),
x_fill: true,
- y_fill: true
+ y_fill: true,
+ y_expand: true,
});
+ box.add_child(this._preview);
this._tooltip = new St.Label({
style_class: 'dash-label',
@@ -184,7 +197,7 @@ let WorkspaceThumbnail = GObject.registerClass({
let preview = new WindowPreview(window);
preview.connect('clicked', (a, btn) => this.emit('clicked', btn));
this._windowPreviews.set(window, preview);
- this.child.add_child(preview);
+ this._preview.child.add_child(preview);
}
_removeWindow(window) {
@@ -204,7 +217,7 @@ let WorkspaceThumbnail = GObject.registerClass({
if (!preview)
continue;
- this.child.set_child_above_sibling(preview, lastPreview);
+ this._preview.child.set_child_above_sibling(preview, lastPreview);
lastPreview = preview;
}
}
@@ -348,9 +361,9 @@ const WorkspacePreviews = GObject.registerClass({
let thumbs = this._thumbnailsBox.get_children();
for (let i = 0; i < thumbs.length; i++) {
if (i == activeIndex)
- thumbs[i].add_style_class_name('active');
+ thumbs[i]._preview.add_style_class_name('active');
else
- thumbs[i].remove_style_class_name('active');
+ thumbs[i]._preview.remove_style_class_name('active');
}
}
--
2.50.0