gnome-shell-extensions/more-ws-previews.patch

4003 lines
139 KiB
Diff

From 2bc8aa48edae1465a5c51be9d864a159b1009bc7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 18 Apr 2024 18:09:40 +0200
Subject: [PATCH 01/29] prefs: Fix loading custom CSS
GTK changed the annotation of `gtk_css_provider_load_from_data()`,
and as a result the `length` parameter is no longer interpreted
as an implicit array length, but has to be specified explicitly.
---
extensions/auto-move-windows/prefs.js | 2 +-
extensions/classification-banner/prefs.js | 2 +-
extensions/heads-up-display/prefs.js | 2 +-
extensions/window-list/prefs.js | 2 +-
extensions/workspace-indicator/prefs.js | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/extensions/auto-move-windows/prefs.js b/extensions/auto-move-windows/prefs.js
index 2c529067..db09c28b 100644
--- a/extensions/auto-move-windows/prefs.js
+++ b/extensions/auto-move-windows/prefs.js
@@ -48,7 +48,7 @@ class AutoMoveSettingsWidget extends Gtk.ScrolledWindow {
const context = this._list.get_style_context();
const cssProvider = new Gtk.CssProvider();
cssProvider.load_from_data(
- 'list { min-width: 30em; }');
+ 'list { min-width: 30em; }', -1);
context.add_provider(cssProvider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
diff --git a/extensions/classification-banner/prefs.js b/extensions/classification-banner/prefs.js
index a5dd8af1..0a91a5da 100644
--- a/extensions/classification-banner/prefs.js
+++ b/extensions/classification-banner/prefs.js
@@ -137,7 +137,7 @@ class AppearancePrefs extends Adw.PreferencesGroup {
padding: 6px;
color: ${item.color};
background-color: ${item.background_color};
- }`);
+ }`, -1);
child.get_style_context().add_provider(provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
child.label = item.message;
diff --git a/extensions/heads-up-display/prefs.js b/extensions/heads-up-display/prefs.js
index a7106e07..9262c11a 100644
--- a/extensions/heads-up-display/prefs.js
+++ b/extensions/heads-up-display/prefs.js
@@ -55,7 +55,7 @@ var settings;
function init() {
settings = ExtensionUtils.getSettings("org.gnome.shell.extensions.heads-up-display");
const cssProvider = new Gtk.CssProvider();
- cssProvider.load_from_data(cssData);
+ cssProvider.load_from_data(cssData, -1);
const display = Gdk.Display.get_default();
Gtk.StyleContext.add_provider_for_display(display, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js
index aec8cc9d..e35990ff 100644
--- a/extensions/window-list/prefs.js
+++ b/extensions/window-list/prefs.js
@@ -43,7 +43,7 @@ class WindowListPrefsWidget extends Gtk.Box {
const context = box.get_style_context();
const cssProvider = new Gtk.CssProvider();
cssProvider.load_from_data(
- 'box { padding: 12px; }');
+ 'box { padding: 12px; }', -1);
context.add_provider(cssProvider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
diff --git a/extensions/workspace-indicator/prefs.js b/extensions/workspace-indicator/prefs.js
index 567f3e99..d307dcac 100644
--- a/extensions/workspace-indicator/prefs.js
+++ b/extensions/workspace-indicator/prefs.js
@@ -48,7 +48,7 @@ class WorkspaceSettingsWidget extends Gtk.ScrolledWindow {
const context = this._list.get_style_context();
const cssProvider = new Gtk.CssProvider();
cssProvider.load_from_data(
- 'list { min-width: 25em; }');
+ 'list { min-width: 25em; }', -1);
context.add_provider(cssProvider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
--
2.47.0
From d1380931b47adb23c36e5499cbd931fba4d63bd0 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 02/29] 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/stylesheet.css | 1 -
extensions/panel-favorites/meson.build | 1 +
extensions/places-menu/meson.build | 1 +
extensions/screenshot-window-sizer/meson.build | 1 +
extensions/systemMonitor/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 +
24 files changed, 16 insertions(+), 9 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/native-window-placement/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 b027381d..20406845 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('adwShim.js', '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 35ba2ecf..5f2ebe7e 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 8e691426..3961141c 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 ca00d01a..6f60b08d 100644
--- a/extensions/meson.build
+++ b/extensions/meson.build
@@ -15,7 +15,7 @@ foreach e : enabled_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/stylesheet.css b/extensions/native-window-placement/stylesheet.css
deleted file mode 100644
index 25134b65..00000000
--- a/extensions/native-window-placement/stylesheet.css
+++ /dev/null
@@ -1 +0,0 @@
-/* This extensions requires no special styling */
diff --git a/extensions/panel-favorites/meson.build b/extensions/panel-favorites/meson.build
index 48504f63..6b9bb19c 100644
--- a/extensions/panel-favorites/meson.build
+++ b/extensions/panel-favorites/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/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/systemMonitor/meson.build b/extensions/systemMonitor/meson.build
index b6548b14..bd3a8484 100644
--- a/extensions/systemMonitor/meson.build
+++ b/extensions/systemMonitor/meson.build
@@ -3,6 +3,7 @@ extension_data += configure_file(
output: metadata_name,
configuration: metadata_conf
)
+extension_data += files('stylesheet.css')
if classic_mode_enabled
extension_data += files('classic.css')
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.47.0
From c97c668cf178968d70a9f2de3308e37e0b931acb 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/29] 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 | 440 +----------------
extensions/workspace-indicator/meson.build | 2 +-
.../workspace-indicator/workspaceIndicator.js | 454 ++++++++++++++++++
po/POTFILES.in | 2 +-
4 files changed, 457 insertions(+), 441 deletions(-)
create mode 100644 extensions/workspace-indicator/workspaceIndicator.js
diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js
index 6974062b..5e1ed8e5 100644
--- a/extensions/workspace-indicator/extension.js
+++ b/extensions/workspace-indicator/extension.js
@@ -1,449 +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 Me = ExtensionUtils.getCurrentExtension();
-
-const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']);
-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;
-
-const MAX_THUMBNAILS = 6;
-
-let WindowPreview = GObject.registerClass(
-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._updateVisible();
- this.queue_relayout();
- });
- this._minimizedChangedId = this._window.connect('notify::minimized',
- this._updateVisible.bind(this));
-
- this._focusChangedId = global.display.connect('notify::focus-window',
- this._onFocusChanged.bind(this));
- this._onFocusChanged();
- }
-
- // needed for DND
- 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._focusChangedId);
- }
-
- _onFocusChanged() {
- if (global.display.focus_window === this._window)
- this.add_style_class_name('active');
- else
- this.remove_style_class_name('active');
- }
-
- _updateVisible() {
- const monitor = Main.layoutManager.findIndexForActor(this);
- const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
- this.visible = this._window.get_frame_rect().overlap(workArea) &&
- this._window.window_type !== Meta.WindowType.DESKTOP &&
- 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) {
- 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) {
- const childBox = new Clutter.ActorBox();
- const frameRect = child.metaWindow.get_frame_rect();
- childBox.set_size(
- Math.round(Math.min(frameRect.width, workArea.width) * hscale),
- Math.round(Math.min(frameRect.height, workArea.height) * vscale));
- childBox.set_origin(
- Math.round((frameRect.x - workArea.x) * hscale),
- Math.round((frameRect.y - workArea.y) * vscale));
- child.allocate(childBox);
- }
- }
-});
-
-let WorkspaceThumbnail = GObject.registerClass(
-class WorkspaceThumbnail extends St.Button {
- _init(index) {
- super._init({
- style_class: 'workspace',
- child: new Clutter.Actor({
- layout_manager: new WorkspaceLayout(),
- clip_to_allocation: 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.metaWindow)
- return false;
-
- this._moveWindow(source.metaWindow);
- return true;
- }
-
- handleDragOver(source) {
- if (source.metaWindow)
- 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);
- }
-
- 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.set({
- text: Meta.prefs_get_workspace_name(this._index),
- visible: true,
- opacity: 0,
- });
-
- 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.clamp(
- stageX + xOffset,
- monitor.x,
- monitor.x + monitor.width - tipWidth);
- const y = stageY + thumbHeight + TOOLTIP_OFFSET;
- this._tooltip.set_position(x, y);
- }
-
- this._tooltip.ease({
- opacity: this.hover ? 255 : 0,
- duration: TOOLTIP_ANIMATION_TIME,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- 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._updateThumbnailVisibility.bind(this)),
- ];
-
- this.connect('scroll-event', this._onScrollEvent.bind(this));
- this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
- this._createWorkspacesSection();
- this._updateThumbnails();
- this._updateThumbnailVisibility();
-
- 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();
- }
-
- _updateThumbnailVisibility() {
- const { workspaceManager } = global;
- const vertical = workspaceManager.layout_rows === -1;
- const useMenu =
- vertical || workspaceManager.n_workspaces > MAX_THUMBNAILS;
- this.reactive = useMenu;
-
- this._statusLabel.visible = useMenu;
- this._thumbnailsBox.visible = !useMenu;
-
- // Disable offscreen-redirect when showing the workspace switcher
- // so that clip-to-allocation works
- Main.panel.set_offscreen_redirect(useMenu
- ? 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();
- this._updateThumbnailVisibility();
- }
-
- _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 { 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..c88ffc9c
--- /dev/null
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -0,0 +1,454 @@
+// SPDX-FileCopyrightText: 2011 Erick Pérez Castellanos <erick.red@gmail.com>
+// SPDX-FileCopyrightText: 2011 Giovanni Campagna <gcampagna@src.gnome.org>
+// SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+const { Clutter, Gio, GObject, Meta, St } = imports.gi;
+
+const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
+
+const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']);
+const _ = Gettext.gettext;
+
+const DND = imports.ui.dnd;
+const Main = imports.ui.main;
+const PanelMenu = imports.ui.panelMenu;
+const PopupMenu = imports.ui.popupMenu;
+
+const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
+const WORKSPACE_KEY = 'workspace-names';
+
+const TOOLTIP_OFFSET = 6;
+const TOOLTIP_ANIMATION_TIME = 150;
+
+const MAX_THUMBNAILS = 6;
+
+const WindowPreview = GObject.registerClass(
+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._checkRelayout());
+ this._positionChangedId = this._window.connect('position-changed',
+ () => this._checkRelayout());
+ this._minimizedChangedId = this._window.connect('notify::minimized',
+ () => this._updateVisible());
+ this._typeChangedId = this._window.connect('notify::window-type',
+ () => this._updateVisible());
+ this._updateVisible();
+
+ this._focusChangedId = global.display.connect('notify::focus-window',
+ this._onFocusChanged.bind(this));
+ this._onFocusChanged();
+ }
+
+ // needed for DND
+ get metaWindow() {
+ return this._window;
+ }
+
+ _onDestroy() {
+ this._window.disconnect(this._sizeChangedId);
+ this._window.disconnect(this._positionChangedId);
+ this._window.disconnect(this._minimizedChangedId);
+ this._window.disconnect(this._typeChangedId);
+ 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');
+ }
+
+ _checkRelayout() {
+ const monitor = Main.layoutManager.findIndexForActor(this);
+ const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
+ if (this._window.get_frame_rect().overlap(workArea))
+ this.queue_relayout();
+ }
+
+ _updateVisible() {
+ this.visible = this._window.window_type !== Meta.WindowType.DESKTOP &&
+ this._window.showing_on_its_workspace();
+ }
+});
+
+const 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) {
+ 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) {
+ const childBox = new Clutter.ActorBox();
+ const frameRect = child.metaWindow.get_frame_rect();
+ childBox.set_size(
+ Math.round(Math.min(frameRect.width, workArea.width) * hscale),
+ Math.round(Math.min(frameRect.height, workArea.height) * vscale));
+ childBox.set_origin(
+ Math.round((frameRect.x - workArea.x) * hscale),
+ Math.round((frameRect.y - workArea.y) * vscale));
+ child.allocate(childBox);
+ }
+ }
+});
+
+const WorkspaceThumbnail = GObject.registerClass(
+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_expand: true,
+ y_expand: 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.metaWindow)
+ return false;
+
+ this._moveWindow(source.metaWindow);
+ return true;
+ }
+
+ handleDragOver(source) {
+ if (source.metaWindow)
+ 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);
+ }
+
+ 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.set({
+ text: Meta.prefs_get_workspace_name(this._index),
+ visible: true,
+ opacity: 0,
+ });
+
+ 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.clamp(
+ stageX + xOffset,
+ monitor.x,
+ monitor.x + monitor.width - tipWidth);
+ const y = stageY + thumbHeight + TOOLTIP_OFFSET;
+ this._tooltip.set_position(x, y);
+ }
+
+ this._tooltip.ease({
+ opacity: this.hover ? 255 : 0,
+ duration: TOOLTIP_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ 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(
+class WorkspaceIndicator extends PanelMenu.Button {
+ _init() {
+ super._init(0.5, _('Workspace Indicator'));
+
+ let container = new St.Widget({
+ layout_manager: new Clutter.BinLayout(),
+ x_expand: true,
+ y_expand: true,
+ });
+ this.add_child(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_child(this._statusLabel);
+
+ this._thumbnailsBox = new St.BoxLayout({
+ style_class: 'panel-workspace-indicator-box',
+ y_expand: true,
+ reactive: true,
+ });
+
+ container.add_child(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._updateThumbnailVisibility.bind(this)),
+ ];
+
+ this.connect('scroll-event', this._onScrollEvent.bind(this));
+ this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
+ this._createWorkspacesSection();
+ this._updateThumbnails();
+ this._updateThumbnailVisibility();
+
+ 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();
+ }
+
+ _updateThumbnailVisibility() {
+ const {workspaceManager} = global;
+ const vertical = workspaceManager.layout_rows === -1;
+ const useMenu =
+ vertical || workspaceManager.n_workspaces > MAX_THUMBNAILS;
+ this.reactive = useMenu;
+
+ this._statusLabel.visible = useMenu;
+ this._thumbnailsBox.visible = !useMenu;
+
+ // Disable offscreen-redirect when showing the workspace switcher
+ // so that clip-to-allocation works
+ Main.panel.set_offscreen_redirect(useMenu
+ ? 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();
+ this._updateThumbnailVisibility();
+ }
+
+ _updateMenuOrnament() {
+ for (let i = 0; i < this._workspacesItems.length; i++) {
+ this._workspacesItems[i].setOrnament(i === this._currentWorkspace
+ ? PopupMenu.Ornament.DOT
+ : PopupMenu.Ornament.NO_DOT);
+ }
+ }
+
+ _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);
+ });
+
+ this._workspacesItems[i].setOrnament(i === this._currentWorkspace
+ ? PopupMenu.Ornament.DOT
+ : PopupMenu.Ornament.NO_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_child(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 10b1d517..bd39ab61 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -17,5 +17,5 @@ extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml
extensions/window-list/prefs.js
extensions/window-list/workspaceIndicator.js
extensions/windowsNavigator/extension.js
-extensions/workspace-indicator/extension.js
extensions/workspace-indicator/prefs.js
+extensions/workspace-indicator/workspaceIndicator.js
--
2.47.0
From 34ba767aa622ac9122463f4649f7a8854a56f25d 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/29] 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 | 8 ++++----
extensions/workspace-indicator/workspaceIndicator.js | 6 ++++--
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/extensions/workspace-indicator/stylesheet.css b/extensions/workspace-indicator/stylesheet.css
index 84aaf454..4e12cce4 100644
--- a/extensions/workspace-indicator/stylesheet.css
+++ b/extensions/workspace-indicator/stylesheet.css
@@ -1,20 +1,20 @@
-.panel-workspace-indicator {
+.workspace-indicator .status-label {
padding: 0 8px;
}
-.panel-workspace-indicator-box {
+.workspace-indicator .workspaces-box {
padding: 4px 0;
spacing: 4px;
}
-.panel-workspace-indicator-box .workspace {
+.workspace-indicator .workspace {
width: 40px;
border: 2px solid #000;
border-radius: 2px;
background-color: #595959;
}
-.panel-workspace-indicator-box .workspace.active {
+.workspace-indicator .workspace.active {
border-color: #fff;
}
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index c88ffc9c..28fc3ea8 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -263,6 +263,8 @@ class WorkspaceIndicator extends PanelMenu.Button {
_init() {
super._init(0.5, _('Workspace Indicator'));
+ this.add_style_class_name('workspace-indicator');
+
let container = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_expand: true,
@@ -274,7 +276,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(),
});
@@ -282,7 +284,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
container.add_child(this._statusLabel);
this._thumbnailsBox = new St.BoxLayout({
- style_class: 'panel-workspace-indicator-box',
+ style_class: 'workspaces-box',
y_expand: true,
reactive: true,
});
--
2.47.0
From c5843b7870e0ce0cbf7b2f587193b93c63062105 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/29] 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 | 4 ++--
extensions/window-list/workspaceIndicator.js | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css
index 375a33e1..ab982b92 100644
--- a/extensions/window-list/classic.css
+++ b/extensions/window-list/classic.css
@@ -58,11 +58,11 @@
border-color: #888;
}
-.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;
}
diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css
index 87813a42..a13f72d8 100644
--- a/extensions/window-list/stylesheet.css
+++ b/extensions/window-list/stylesheet.css
@@ -101,12 +101,12 @@
border-color: #fff;
}
-.window-list-window-preview {
+.window-list-workspace-indicator-window-preview {
background-color: #bebebe;
border: 1px solid #828282;
}
-.window-list-window-preview.active {
+.window-list-workspace-indicator-window-preview.active {
background-color: #d4d4d4;
}
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
index cdfe5b61..c24f159f 100644
--- a/extensions/window-list/workspaceIndicator.js
+++ b/extensions/window-list/workspaceIndicator.js
@@ -21,7 +21,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.47.0
From a81dbea8250c85b950c83048f178c700635a8c38 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/29] 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 28fc3ea8..01604b91 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -25,11 +25,13 @@ const TOOLTIP_ANIMATION_TIME = 150;
const MAX_THUMBNAILS = 6;
+let baseStyleClassName = '';
+
const WindowPreview = GObject.registerClass(
class WindowPreview extends St.Button {
_init(window) {
super._init({
- style_class: 'workspace-indicator-window-preview',
+ style_class: `${baseStyleClassName}-window-preview`,
});
this._delegate = this;
@@ -260,10 +262,15 @@ class WorkspaceThumbnail extends St.Button {
var WorkspaceIndicator = GObject.registerClass(
class WorkspaceIndicator extends PanelMenu.Button {
- _init() {
+ _init(params = {}) {
super._init(0.5, _('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.47.0
From e1c5b589fca9021b960e19f043ca26735c8b02de 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 07/29] 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 | 5 ++++-
extensions/window-list/workspaceIndicator.js | 15 ++++++++++++---
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 0c28692d..41a0c143 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -774,7 +774,10 @@ class WindowList extends St.Widget {
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_child(this._workspaceIndicator.container);
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 c24f159f..1a1d15cd 100644
--- a/extensions/window-list/workspaceIndicator.js
+++ b/extensions/window-list/workspaceIndicator.js
@@ -17,11 +17,13 @@ const TOOLTIP_ANIMATION_TIME = 150;
const MAX_THUMBNAILS = 6;
+let baseStyleClassName = '';
+
let WindowPreview = GObject.registerClass(
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 @@ class WorkspaceThumbnail extends St.Button {
var WorkspaceIndicator = GObject.registerClass(
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.remove_style_class_name('panel-button');
this.menu.actor.remove_style_class_name('panel-menu');
--
2.47.0
From c673a9d7169cc1a2f6df9c3eeea4b11f8968dc19 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 08/29] 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 | 22 ++++++++++++++++++--
extensions/window-list/workspaceIndicator.js | 6 +-----
2 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 41a0c143..c58df434 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -774,10 +774,9 @@ class WindowList extends St.Widget {
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_child(this._workspaceIndicator.container);
this._mutterSettings = new Gio.Settings({ schema_id: 'org.gnome.mutter' });
@@ -1140,6 +1139,25 @@ class WindowList extends St.Widget {
}
});
+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() {
ExtensionUtils.initTranslations();
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
index 1a1d15cd..4290d58a 100644
--- a/extensions/window-list/workspaceIndicator.js
+++ b/extensions/window-list/workspaceIndicator.js
@@ -251,7 +251,7 @@ class WorkspaceThumbnail extends St.Button {
var WorkspaceIndicator = GObject.registerClass(
class WorkspaceIndicator extends PanelMenu.Button {
_init(params = {}) {
- super._init(0.0, _('Workspace Indicator'), true);
+ super._init(0.0, _('Workspace Indicator'));
const {
baseStyleClass = 'workspace-indicator',
@@ -260,10 +260,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
baseStyleClassName = baseStyleClass;
this.add_style_class_name(baseStyleClassName);
- this.setMenu(new PopupMenu.PopupMenu(this, 0.0, St.Side.BOTTOM));
- this.remove_style_class_name('panel-button');
- this.menu.actor.remove_style_class_name('panel-menu');
-
let container = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_expand: true,
--
2.47.0
From 3271e93695782d06ada9752144c650605ceed76a 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 09/29] 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 c58df434..a011bc90 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -789,7 +789,9 @@ class WindowList extends St.Widget {
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, {
affectsStruts: true,
@@ -884,6 +886,11 @@ class WindowList extends St.Widget {
children[newActive].activate();
}
+ _onWorkspaceMenuSet() {
+ if (this._workspaceIndicator.menu)
+ this._menuManager.addMenu(this._workspaceIndicator.menu);
+ }
+
_updatePosition() {
this.set_position(
this._monitor.x,
--
2.47.0
From 314072792bba618a85897dc085bb72debe3ec6b1 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 10/29] 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 01604b91..6e3ad7b5 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -17,9 +17,6 @@ const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
-const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
-const WORKSPACE_KEY = 'workspace-names';
-
const TOOLTIP_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150;
@@ -317,9 +314,9 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._updateThumbnails();
this._updateThumbnailVisibility();
- 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.47.0
From 002a0bb8036a997a70acda017e4016fd9fd51806 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 11/29] 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 6e3ad7b5..60356d74 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -454,7 +454,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
return;
- let newIndex = global.workspace_manager.get_active_workspace_index() + diff;
+ const newIndex = this._currentWorkspace + diff;
this._activate(newIndex);
}
});
--
2.47.0
From 4e2785910ceccc079305da1b9d0e2c810b1f982a 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 12/29] 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 60356d74..39d4e296 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -296,8 +296,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
container.add_child(this._thumbnailsBox);
this._workspacesItems = [];
- this._workspaceSection = new PopupMenu.PopupMenuSection();
- this.menu.addMenuItem(this._workspaceSection);
this._workspaceManagerSignals = [
workspaceManager.connect_after('notify::n-workspaces',
@@ -310,7 +308,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
this.connect('scroll-event', this._onScrollEvent.bind(this));
this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
- this._createWorkspacesSection();
+ this._updateMenu();
this._updateThumbnails();
this._updateThumbnailVisibility();
@@ -361,7 +359,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
}
_nWorkspacesChanged() {
- this._createWorkspacesSection();
+ this._updateMenu();
this._updateThumbnails();
this._updateThumbnailVisibility();
}
@@ -397,17 +395,17 @@ class WorkspaceIndicator extends PanelMenu.Button {
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.47.0
From 5f33bc574aee51700c92b940b23df0b7966450d6 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 13/29] 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 39d4e296..83713b6f 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -227,16 +227,17 @@ class WorkspaceThumbnail extends St.Button {
});
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.clamp(
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.47.0
From a65fd9e61cf3f3a83116815482843b1b20eef20f 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 14/29] 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 83713b6f..fa05a54c 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -309,6 +309,16 @@ class WorkspaceIndicator extends PanelMenu.Button {
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._updateThumbnailVisibility();
@@ -328,7 +338,9 @@ class WorkspaceIndicator extends PanelMenu.Button {
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();
}
@@ -343,9 +355,16 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._statusLabel.visible = useMenu;
this._thumbnailsBox.visible = !useMenu;
+ 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(useMenu
+ Main.panel.set_offscreen_redirect(this._thumbnailsBox.visible
? Clutter.OffscreenRedirect.ALWAYS
: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY);
}
--
2.47.0
From 521b224b17cb15df49a32d5c2dffe5ce65285df4 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 15/29] 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 | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index fa05a54c..bbb51c41 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -422,19 +422,18 @@ class WorkspaceIndicator extends PanelMenu.Button {
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));
- this._workspacesItems[i].setOrnament(i === this._currentWorkspace
+ item.connect('activate',
+ () => this._activate(i));
+
+ item.setOrnament(i === this._currentWorkspace
? PopupMenu.Ornament.DOT
: PopupMenu.Ornament.NO_DOT);
+
+ this.menu.addMenuItem(item);
+ this._workspacesItems[i] = item;
}
this._statusLabel.set_text(this._labelText());
--
2.47.0
From 3145e45a2d897b177e7395cec71a1293b6857a36 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 16/29] 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 bbb51c41..d401b6ab 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -283,7 +283,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._statusLabel = new St.Label({
style_class: 'status-label',
y_align: Clutter.ActorAlign.CENTER,
- text: this._labelText(),
+ text: this._getStatusText(),
});
container.add_child(this._statusLabel);
@@ -375,7 +375,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._updateMenuOrnament();
this._updateActiveThumbnail();
- this._statusLabel.set_text(this._labelText());
+ this._statusLabel.set_text(this._getStatusText());
}
_nWorkspacesChanged() {
@@ -402,17 +402,16 @@ class WorkspaceIndicator extends PanelMenu.Button {
}
}
- _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() {
@@ -423,7 +422,8 @@ class WorkspaceIndicator extends PanelMenu.Button {
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));
@@ -436,7 +436,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._workspacesItems[i] = item;
}
- this._statusLabel.set_text(this._labelText());
+ this._statusLabel.set_text(this._getStatusText());
}
_updateThumbnails() {
--
2.47.0
From 30adbc349b382c69c7592cd674d7837f6c9185c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 21 Feb 2024 16:35:09 +0100
Subject: [PATCH 17/29] workspace-indicator: Include n-workspaces in status
label
The two extensions currently use a slightly different label
in menu mode:
The workspace indicator uses the plain workspace number ("2"),
while the window list includes the number of workspaces ("2 / 4").
The additional information seem useful, as well as the slightly
bigger click/touch target, so copy the window-list behavior.
---
extensions/workspace-indicator/workspaceIndicator.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index d401b6ab..29b8a671 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -403,8 +403,9 @@ class WorkspaceIndicator extends PanelMenu.Button {
}
_getStatusText() {
+ const {nWorkspaces} = global.workspace_manager;
const current = this._currentWorkspace + 1;
- return `${current}`;
+ return `${current} / ${nWorkspaces}`;
}
_updateMenuLabels() {
--
2.47.0
From 675e91b7b521b4c8d7f53a9f3d028ab7300281dd 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 18/29] 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 | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/extensions/workspace-indicator/stylesheet.css b/extensions/workspace-indicator/stylesheet.css
index 4e12cce4..f74f7e88 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: #bebebe;
border: 1px solid #828282;
+ border-radius: 1px;
}
.workspace-indicator-window-preview.active {
--
2.47.0
From 011af97ab27a4e7be9dab937754470e890bc131c 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 19/29] 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 | 30 +------------------
4 files changed, 60 insertions(+), 30 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 f74f7e88..b0f7d171 100644
--- a/extensions/workspace-indicator/stylesheet.css
+++ b/extensions/workspace-indicator/stylesheet.css
@@ -1,29 +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.active {
- background-color: #d4d4d4;
-}
+@import url("stylesheet-dark.css");
--
2.47.0
From bcb34a3a91a5140b5ecc6f9582dd9f80272c7e32 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 20/29] 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 | 447 -------------------
4 files changed, 31 insertions(+), 467 deletions(-)
delete mode 100644 extensions/window-list/workspaceIndicator.js
diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css
index ab982b92..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 {
- border: 2px solid #f6f5f4;
- background-color: #ccc;
-}
-
-.window-list-workspace-indicator .workspace.active {
- border-color: #888;
-}
-
-.window-list-workspace-indicator-window-preview {
- background-color: #ededed;
- border: 1px solid #ccc;
-}
-
-.window-list-workspace-indicator-window-preview.active {
- background-color: #f6f5f4;
-}
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 a13f72d8..4ba47f07 100644
--- a/extensions/window-list/stylesheet.css
+++ b/extensions/window-list/stylesheet.css
@@ -1,3 +1,5 @@
+@import url("stylesheet-workspace-switcher-dark.css");
+
.window-list {
spacing: 2px;
font-size: 10pt;
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
deleted file mode 100644
index 4290d58a..00000000
--- a/extensions/window-list/workspaceIndicator.js
+++ /dev/null
@@ -1,447 +0,0 @@
-/* exported WorkspaceIndicator */
-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 Me = ExtensionUtils.getCurrentExtension();
-
-const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']);
-const _ = Gettext.gettext;
-
-const TOOLTIP_OFFSET = 6;
-const TOOLTIP_ANIMATION_TIME = 150;
-
-const MAX_THUMBNAILS = 6;
-
-let baseStyleClassName = '';
-
-let WindowPreview = GObject.registerClass(
-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.queue_relayout());
- this._positionChangedId = this._window.connect('position-changed',
- () => {
- this._updateVisible();
- this.queue_relayout();
- });
- this._minimizedChangedId = this._window.connect('notify::minimized',
- this._updateVisible.bind(this));
-
- this._focusChangedId = global.display.connect('notify::focus-window',
- this._onFocusChanged.bind(this));
- this._onFocusChanged();
- }
-
- // needed for DND
- 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._focusChangedId);
- }
-
- _onFocusChanged() {
- if (global.display.focus_window === this._window)
- this.add_style_class_name('active');
- else
- this.remove_style_class_name('active');
- }
-
- _updateVisible() {
- const monitor = Main.layoutManager.findIndexForActor(this);
- const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
- this.visible = this._window.get_frame_rect().overlap(workArea) &&
- this._window.window_type !== Meta.WindowType.DESKTOP &&
- 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) {
- 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) {
- const childBox = new Clutter.ActorBox();
- const frameRect = child.metaWindow.get_frame_rect();
- childBox.set_size(
- Math.round(Math.min(frameRect.width, workArea.width) * hscale),
- Math.round(Math.min(frameRect.height, workArea.height) * vscale));
- childBox.set_origin(
- Math.round((frameRect.x - workArea.x) * hscale),
- Math.round((frameRect.y - workArea.y) * vscale));
- child.allocate(childBox);
- }
- }
-});
-
-let WorkspaceThumbnail = GObject.registerClass(
-class WorkspaceThumbnail extends St.Button {
- _init(index) {
- super._init({
- style_class: 'workspace',
- child: new Clutter.Actor({
- layout_manager: new WorkspaceLayout(),
- clip_to_allocation: 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.metaWindow)
- return false;
-
- this._moveWindow(source.metaWindow);
- return true;
- }
-
- handleDragOver(source) {
- if (source.metaWindow)
- 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);
- }
-
- 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.set({
- text: Meta.prefs_get_workspace_name(this._index),
- visible: true,
- opacity: 0,
- });
-
- 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.clamp(
- stageX + xOffset,
- monitor.x,
- monitor.x + monitor.width - tipWidth);
- const y = stageY - tipHeight - TOOLTIP_OFFSET;
- this._tooltip.set_position(x, y);
- }
-
- this._tooltip.ease({
- opacity: this.hover ? 255 : 0,
- duration: TOOLTIP_ANIMATION_TIME,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- 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(
-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._updateThumbnailVisibility.bind(this)),
- ];
-
- this.connect('scroll-event', this._onScrollEvent.bind(this));
- this._updateMenu();
- this._updateThumbnails();
- this._updateThumbnailVisibility();
-
- 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();
- }
-
- _updateThumbnailVisibility() {
- const { workspaceManager } = global;
- const vertical = workspaceManager.layout_rows === -1;
- const useMenu =
- vertical || workspaceManager.n_workspaces > MAX_THUMBNAILS;
- this.reactive = useMenu;
-
- this._statusBin.visible = useMenu;
- this._thumbnailsBox.visible = !useMenu;
- }
-
- _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();
- this._updateThumbnailVisibility();
- }
-
- _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', () => {
- 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);
- }
-});
-
--
2.47.0
From 36e4714c31398b74eb1727197f40bbd81ccfd6f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 20 Feb 2024 17:39:49 +0100
Subject: [PATCH 21/29] workspace-indicator: Simplify scroll handling
gnome-shell already includes a method for switching workspaces
via scroll events. Use that instead of implementing our own.
---
.../workspace-indicator/workspaceIndicator.js | 21 ++++---------------
1 file changed, 4 insertions(+), 17 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 29b8a671..1dd3ed6b 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -307,8 +307,10 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._updateThumbnailVisibility.bind(this)),
];
- this.connect('scroll-event', this._onScrollEvent.bind(this));
- this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this));
+ this.connect('scroll-event',
+ (a, event) => Main.wm.handleWorkspaceScroll(event));
+ this._thumbnailsBox.connect('scroll-event',
+ (a, event) => Main.wm.handleWorkspaceScroll(event));
this._inTopBar = false;
this.connect('notify::realized', () => {
@@ -460,19 +462,4 @@ class WorkspaceIndicator extends PanelMenu.Button {
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.47.0
From f3154702594a814e5131252ab84b9daf0553ada3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 27 Feb 2024 21:20:45 +0100
Subject: [PATCH 22/29] workspace-indicator: Handle active indication in
thumbnail
Meta.Workspace has had an `active` property for a while now, so
we can use a property binding instead of tracking the active
workspace ourselves.
---
.../workspace-indicator/workspaceIndicator.js | 38 ++++++++++++-------
1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 1dd3ed6b..ae526929 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -116,8 +116,14 @@ class WorkspaceLayout extends Clutter.LayoutManager {
}
});
-const WorkspaceThumbnail = GObject.registerClass(
-class WorkspaceThumbnail extends St.Button {
+const WorkspaceThumbnail = GObject.registerClass({
+ Properties: {
+ 'active': GObject.ParamSpec.boolean(
+ 'active', '', '',
+ GObject.ParamFlags.READWRITE,
+ false),
+ },
+}, class WorkspaceThumbnail extends St.Button {
_init(index) {
super._init({
style_class: 'workspace',
@@ -146,6 +152,10 @@ class WorkspaceThumbnail extends St.Button {
let workspaceManager = global.workspace_manager;
this._workspace = workspaceManager.get_workspace_by_index(index);
+ this._workspace.bind_property('active',
+ this, 'active',
+ GObject.BindingFlags.SYNC_CREATE);
+
this._windowAddedId = this._workspace.connect('window-added',
(ws, window) => this._addWindow(window));
this._windowRemovedId = this._workspace.connect('window-removed',
@@ -158,6 +168,18 @@ class WorkspaceThumbnail extends St.Button {
this._onRestacked();
}
+ get active() {
+ return this.has_style_class_name('active');
+ }
+
+ set active(active) {
+ if (active)
+ this.add_style_class_name('active');
+ else
+ this.remove_style_class_name('active');
+ this.notify('active');
+ }
+
acceptDrop(source) {
if (!source.metaWindow)
return false;
@@ -375,7 +397,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._currentWorkspace = global.workspace_manager.get_active_workspace_index();
this._updateMenuOrnament();
- this._updateActiveThumbnail();
this._statusLabel.set_text(this._getStatusText());
}
@@ -394,16 +415,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
}
}
- _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 {nWorkspaces} = global.workspace_manager;
const current = this._currentWorkspace + 1;
@@ -451,7 +462,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
let thumb = new WorkspaceThumbnail(i);
this._thumbnailsBox.add_child(thumb);
}
- this._updateActiveThumbnail();
}
_activate(index) {
--
2.47.0
From e854ad2e483489952691d5fbede37e3fec63737c 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 23/29] 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 | 74 ++++++++++++-------
1 file changed, 49 insertions(+), 25 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index ae526929..e5be8081 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -280,6 +280,51 @@ const WorkspaceThumbnail = GObject.registerClass({
}
});
+const WorkspacePreviews = GObject.registerClass(
+class WorkspacePreviews extends Clutter.Actor {
+ _init(params) {
+ super._init({
+ ...params,
+ layout_manager: new Clutter.BinLayout(),
+ reactive: true,
+ y_expand: true,
+ });
+
+ this.connect('scroll-event',
+ (a, event) => Main.wm.handleWorkspaceScroll(event));
+ this.connect('destroy', () => this._onDestroy());
+
+ const {workspaceManager} = global;
+
+ this._nWorkspacesChanged =
+ workspaceManager.connect_after('notify::n-workspaces',
+ () => this._updateThumbnails());
+
+ this._thumbnailsBox = new St.BoxLayout({
+ style_class: 'workspaces-box',
+ y_expand: true,
+ });
+ this.add_child(this._thumbnailsBox);
+
+ this._updateThumbnails();
+ }
+
+ _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);
+ }
+ }
+
+ _onDestroy() {
+ global.workspace_manager.disconnect(this._nWorkspacesChanged);
+ }
+});
+
var WorkspaceIndicator = GObject.registerClass(
class WorkspaceIndicator extends PanelMenu.Button {
_init(params = {}) {
@@ -307,16 +352,10 @@ class WorkspaceIndicator extends PanelMenu.Button {
y_align: Clutter.ActorAlign.CENTER,
text: this._getStatusText(),
});
-
container.add_child(this._statusLabel);
- this._thumbnailsBox = new St.BoxLayout({
- style_class: 'workspaces-box',
- y_expand: true,
- reactive: true,
- });
-
- container.add_child(this._thumbnailsBox);
+ this._thumbnails = new WorkspacePreviews();
+ container.add_child(this._thumbnails);
this._workspacesItems = [];
@@ -331,8 +370,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
this.connect('scroll-event',
(a, event) => Main.wm.handleWorkspaceScroll(event));
- this._thumbnailsBox.connect('scroll-event',
- (a, event) => Main.wm.handleWorkspaceScroll(event));
this._inTopBar = false;
this.connect('notify::realized', () => {
@@ -344,7 +381,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
});
this._updateMenu();
- this._updateThumbnails();
this._updateThumbnailVisibility();
this._settings = new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'});
@@ -377,7 +413,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
this.reactive = useMenu;
this._statusLabel.visible = useMenu;
- this._thumbnailsBox.visible = !useMenu;
+ this._thumbnails.visible = !useMenu;
this._updateTopBarRedirect();
}
@@ -388,7 +424,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
// 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);
}
@@ -403,7 +439,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
_nWorkspacesChanged() {
this._updateMenu();
- this._updateThumbnails();
this._updateThumbnailVisibility();
}
@@ -453,17 +488,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
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_child(thumb);
- }
- }
-
_activate(index) {
let workspaceManager = global.workspace_manager;
--
2.47.0
From 18b40e7f586d4546bd64745a0b2d617655b87af3 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 24/29] 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 | 66 ++++++++++++++++++-
2 files changed, 69 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 e5be8081..d496d22d 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -20,6 +20,8 @@ const PopupMenu = imports.ui.popupMenu;
const TOOLTIP_OFFSET = 6;
const TOOLTIP_ANIMATION_TIME = 150;
+const SCROLL_TIME = 100;
+
const MAX_THUMBNAILS = 6;
let baseStyleClassName = '';
@@ -299,12 +301,30 @@ class WorkspacePreviews extends Clutter.Actor {
this._nWorkspacesChanged =
workspaceManager.connect_after('notify::n-workspaces',
() => this._updateThumbnails());
+ this._workspaceSwitchedId =
+ 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();
}
@@ -318,6 +338,50 @@ class WorkspacePreviews extends Clutter.Actor {
const thumb = new WorkspaceThumbnail(i);
this._thumbnailsBox.add_child(thumb);
}
+
+ if (this.mapped)
+ this._updateScrollPosition();
+ }
+
+ _updateScrollPosition() {
+ const adjustment = this._scrollView.hscroll.adjustment;
+ const {upper, pageSize} = adjustment;
+ let {value} = adjustment;
+
+ const activeWorkspace =
+ [...this._thumbnailsBox].find(a => a.active);
+
+ if (!activeWorkspace)
+ return;
+
+ let offset = 0;
+ const hfade = this._scrollView.get_effect('fade');
+ if (hfade)
+ offset = hfade.fade_margins.left;
+
+ 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;
+
+ adjustment.ease(value, {
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ duration: SCROLL_TIME,
+ });
}
_onDestroy() {
--
2.47.0
From 422a5e6f67b23c3b9b0764ec313ad0ad864249db Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sun, 3 Mar 2024 15:05:23 +0100
Subject: [PATCH 25/29] workspace-indicator: Support labels in previews
The space in the top bar is too limited to include the workspace
names. However we'll soon replace the textual menu with a preview
popover. We can use bigger previews there, so we can include the
names to not lose functionality with regards to the current menu.
---
.../workspace-indicator/workspaceIndicator.js | 63 ++++++++++++++++---
1 file changed, 55 insertions(+), 8 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index d496d22d..f5ffdbb7 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -124,10 +124,23 @@ const WorkspaceThumbnail = GObject.registerClass({
'active', '', '',
GObject.ParamFlags.READWRITE,
false),
+ 'show-label': GObject.ParamSpec.boolean(
+ 'show-label', '', '',
+ GObject.ParamFlags.READWRITE,
+ false),
},
}, class WorkspaceThumbnail extends St.Button {
_init(index) {
- super._init({
+ super._init();
+
+ 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(),
@@ -135,7 +148,15 @@ const WorkspaceThumbnail = GObject.registerClass({
x_expand: true,
y_expand: true,
}),
+ y_expand: true,
});
+ box.add_child(this._preview);
+
+ this._label = new St.Label({
+ x_align: Clutter.ActorAlign.CENTER,
+ text: Meta.prefs_get_workspace_name(index),
+ });
+ box.add_child(this._label);
this._tooltip = new St.Label({
style_class: 'dash-label',
@@ -143,9 +164,20 @@ const WorkspaceThumbnail = GObject.registerClass({
});
Main.uiGroup.add_child(this._tooltip);
+ this.bind_property('show-label',
+ this._label, 'visible',
+ GObject.BindingFlags.SYNC_CREATE);
+
this.connect('destroy', this._onDestroy.bind(this));
this.connect('notify::hover', this._syncTooltip.bind(this));
+ this._desktopSettings =
+ new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'});
+ this._namesChangedId =
+ this._desktopSettings.connect('changed::workspace-names', () => {
+ this._label.text = Meta.prefs_get_workspace_name(index);
+ });
+
this._index = index;
this._delegate = this; // needed for DND
@@ -171,14 +203,14 @@ const WorkspaceThumbnail = GObject.registerClass({
}
get active() {
- return this.has_style_class_name('active');
+ return this._preview.has_style_class_name('active');
}
set active(active) {
if (active)
- this.add_style_class_name('active');
+ this._preview.add_style_class_name('active');
else
- this.remove_style_class_name('active');
+ this._preview.remove_style_class_name('active');
this.notify('active');
}
@@ -204,7 +236,7 @@ const 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) {
@@ -224,7 +256,7 @@ const 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;
}
}
@@ -243,6 +275,9 @@ const WorkspaceThumbnail = GObject.registerClass({
}
_syncTooltip() {
+ if (this.showLabel)
+ return;
+
if (this.hover) {
this._tooltip.set({
text: Meta.prefs_get_workspace_name(this._index),
@@ -279,11 +314,20 @@ const WorkspaceThumbnail = GObject.registerClass({
this._workspace.disconnect(this._windowAddedId);
this._workspace.disconnect(this._windowRemovedId);
global.display.disconnect(this._restackedId);
+
+ this._desktopSettings.disconnect(this._namesChangedId);
+ this._desktopSettings = null;
}
});
-const WorkspacePreviews = GObject.registerClass(
-class WorkspacePreviews extends Clutter.Actor {
+const WorkspacePreviews = GObject.registerClass({
+ Properties: {
+ 'show-labels': GObject.ParamSpec.boolean(
+ 'show-labels', '', '',
+ GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
+ false),
+ },
+}, class WorkspacePreviews extends Clutter.Actor {
_init(params) {
super._init({
...params,
@@ -336,6 +380,9 @@ class WorkspacePreviews extends Clutter.Actor {
for (let i = 0; i < nWorkspaces; i++) {
const thumb = new WorkspaceThumbnail(i);
+ this.bind_property('show-labels',
+ thumb, 'show-label',
+ GObject.BindingFlags.SYNC_CREATE);
this._thumbnailsBox.add_child(thumb);
}
--
2.47.0
From a0985eb24eafee329b6af6c2c2f7db4de7b103e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 20 Feb 2024 21:43:55 +0100
Subject: [PATCH 26/29] workspace-indicator: Stop handling vertical layouts
Both the regular session and GNOME classic use a horizontal layout
nowadays, so it doesn't seem worth to specifically handle vertical
layouts anymore.
The extension will still work when the layout is changed (by some
other extension), there will simply be a mismatch between horizontal
previews and the actual layout.
---
extensions/workspace-indicator/workspaceIndicator.js | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index f5ffdbb7..362c6372 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -475,8 +475,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._nWorkspacesChanged.bind(this)),
workspaceManager.connect_after('workspace-switched',
this._onWorkspaceSwitched.bind(this)),
- workspaceManager.connect('notify::layout-rows',
- this._updateThumbnailVisibility.bind(this)),
];
this.connect('scroll-event',
@@ -518,9 +516,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
_updateThumbnailVisibility() {
const {workspaceManager} = global;
- const vertical = workspaceManager.layout_rows === -1;
- const useMenu =
- vertical || workspaceManager.n_workspaces > MAX_THUMBNAILS;
+ const useMenu = workspaceManager.n_workspaces > MAX_THUMBNAILS;
this.reactive = useMenu;
this._statusLabel.visible = useMenu;
--
2.47.0
From 74b64e860757d56f0d500165ba2e49024ead48d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sun, 3 Mar 2024 15:05:23 +0100
Subject: [PATCH 27/29] workspace-indicator: Also show previews in menu
Since the regular session also switched to horizontal workspaces,
using a vertical menu has been a bit awkward.
Now that our previews have become more flexible, we can use them
in the collapsed state as well as when embedded into the top bar.
---
.../workspace-indicator/stylesheet-dark.css | 25 +++++-
.../workspace-indicator/workspaceIndicator.js | 79 +++----------------
2 files changed, 36 insertions(+), 68 deletions(-)
diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css
index 61d1e982..fb0e8b1a 100644
--- a/extensions/workspace-indicator/stylesheet-dark.css
+++ b/extensions/workspace-indicator/stylesheet-dark.css
@@ -6,18 +6,41 @@
-st-hfade-offset: 20px;
}
+.workspace-indicator-menu .workspaces-view {
+ max-width: 480px;
+}
+
.workspace-indicator .workspaces-box {
padding: 5px;
spacing: 3px;
}
+.workspace-indicator-menu .workspaces-box {
+ padding: 5px;
+ spacing: 6px;
+}
+
+.workspace-indicator-menu .workspace-box {
+ spacing: 6px;
+}
+
+.workspace-indicator-menu .workspace,
.workspace-indicator .workspace {
- width: 52px;
border: 2px solid transparent;
border-radius: 4px;
background-color: #3f3f3f;
}
+.workspace-indicator .workspace {
+ width: 52px;
+}
+
+.workspace-indicator-menu .workspace {
+ height: 80px;
+ width: 160px;
+}
+
+.workspace-indicator-menu .workspace.active,
.workspace-indicator .workspace.active {
border-color: #9f9f9f;
}
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index 362c6372..ed5645db 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -439,7 +439,7 @@ const WorkspacePreviews = GObject.registerClass({
var WorkspaceIndicator = GObject.registerClass(
class WorkspaceIndicator extends PanelMenu.Button {
_init(params = {}) {
- super._init(0.5, _('Workspace Indicator'));
+ super(0.5, _('Workspace Indicator'), true);
const {
baseStyleClass = 'workspace-indicator',
@@ -472,7 +472,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._workspaceManagerSignals = [
workspaceManager.connect_after('notify::n-workspaces',
- this._nWorkspacesChanged.bind(this)),
+ this._updateThumbnailVisibility.bind(this)),
workspaceManager.connect_after('workspace-switched',
this._onWorkspaceSwitched.bind(this)),
];
@@ -489,24 +489,13 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._updateTopBarRedirect();
});
- this._updateMenu();
this._updateThumbnailVisibility();
-
- 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;
- }
-
if (this._inTopBar)
Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
this._inTopBar = false;
@@ -522,6 +511,10 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._statusLabel.visible = useMenu;
this._thumbnails.visible = !useMenu;
+ this.setMenu(useMenu
+ ? this._createPreviewMenu()
+ : null);
+
this._updateTopBarRedirect();
}
@@ -538,69 +531,21 @@ class WorkspaceIndicator extends PanelMenu.Button {
_onWorkspaceSwitched() {
this._currentWorkspace = global.workspace_manager.get_active_workspace_index();
-
- this._updateMenuOrnament();
-
this._statusLabel.set_text(this._getStatusText());
}
- _nWorkspacesChanged() {
- this._updateMenu();
- this._updateThumbnailVisibility();
- }
-
- _updateMenuOrnament() {
- for (let i = 0; i < this._workspacesItems.length; i++) {
- this._workspacesItems[i].setOrnament(i === this._currentWorkspace
- ? PopupMenu.Ornament.DOT
- : PopupMenu.Ornament.NO_DOT);
- }
- }
-
_getStatusText() {
const {nWorkspaces} = global.workspace_manager;
const current = this._currentWorkspace + 1;
return `${current} / ${nWorkspaces}`;
}
- _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();
+ _createPreviewMenu() {
+ const menu = new PopupMenu.PopupMenu(this, 0.5, St.Side.TOP);
- 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.NO_DOT);
-
- 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());
- }
+ const previews = new WorkspacePreviews({show_labels: true});
+ menu.box.add_child(previews);
+ menu.actor.add_style_class_name(`${baseStyleClassName}-menu`);
+ return menu;
}
});
--
2.47.0
From f810340e1e7ffd7c1964ec950be8b0585afe9e7f 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 28/29] 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
---
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 | 30 +++++++++++++++++++
...extensions.workspace-indicator.gschema.xml | 15 ++++++++++
.../workspace-indicator/workspaceIndicator.js | 14 ++++-----
po/POTFILES.in | 1 +
8 files changed, 62 insertions(+), 8 deletions(-)
create mode 100644 extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index a011bc90..688ca761 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -776,6 +776,7 @@ class WindowList extends St.Widget {
this._workspaceIndicator = new BottomWorkspaceIndicator({
baseStyleClass: 'window-list-workspace-indicator',
+ settings: ExtensionUtils.getSettings(),
});
indicatorsBox.add_child(this._workspaceIndicator.container);
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 299864cf..c5ab9fb1 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
@@ -30,5 +30,9 @@
only on the primary one.
</description>
</key>
+ <key name="embed-previews" type="b">
+ <default>true</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 5e1ed8e5..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 d307dcac..9809b46a 100644
--- a/extensions/workspace-indicator/prefs.js
+++ b/extensions/workspace-indicator/prefs.js
@@ -13,6 +13,34 @@ 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.append(row);
+
+ row.append(new Gtk.Label({
+ label: _('Show Previews In Top Bar'),
+ }));
+
+ const sw = new Gtk.Switch({
+ hexpand: true,
+ halign: Gtk.Align.END,
+ });
+ row.append(sw);
+
+ const settings = ExtensionUtils.getSettings();
+
+ settings.bind('embed-previews',
+ sw, 'active',
+ Gio.SettingsBindFlags.DEFAULT);
+ }
+});
+
const WorkspaceSettingsWidget = GObject.registerClass(
class WorkspaceSettingsWidget extends Gtk.ScrolledWindow {
_init() {
@@ -31,6 +59,8 @@ class WorkspaceSettingsWidget extends Gtk.ScrolledWindow {
});
this.set_child(box);
+ box.append(new GeneralGroup());
+
box.append(new Gtk.Label({
label: '<b>%s</b>'.format(_('Workspace Names')),
use_markup: true,
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..c7c634ca
--- /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>true</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 ed5645db..14359a0e 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -22,8 +22,6 @@ const TOOLTIP_ANIMATION_TIME = 150;
const SCROLL_TIME = 100;
-const MAX_THUMBNAILS = 6;
-
let baseStyleClassName = '';
const WindowPreview = GObject.registerClass(
@@ -439,12 +437,15 @@ const WorkspacePreviews = GObject.registerClass({
var WorkspaceIndicator = GObject.registerClass(
class WorkspaceIndicator extends PanelMenu.Button {
_init(params = {}) {
- super(0.5, _('Workspace Indicator'), true);
+ super._init(0.5, _('Workspace Indicator'), true);
const {
baseStyleClass = 'workspace-indicator',
+ settings,
} = params;
+ this._settings = settings;
+
baseStyleClassName = baseStyleClass;
this.add_style_class_name(baseStyleClassName);
@@ -471,8 +472,6 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._workspacesItems = [];
this._workspaceManagerSignals = [
- workspaceManager.connect_after('notify::n-workspaces',
- this._updateThumbnailVisibility.bind(this)),
workspaceManager.connect_after('workspace-switched',
this._onWorkspaceSwitched.bind(this)),
];
@@ -489,6 +488,8 @@ class WorkspaceIndicator extends PanelMenu.Button {
this._updateTopBarRedirect();
});
+ this._settings.connect('changed::embed-previews',
+ () => this._updateThumbnailVisibility());
this._updateThumbnailVisibility();
}
@@ -504,8 +505,7 @@ class WorkspaceIndicator extends PanelMenu.Button {
}
_updateThumbnailVisibility() {
- const {workspaceManager} = global;
- const useMenu = workspaceManager.n_workspaces > MAX_THUMBNAILS;
+ const useMenu = !this._settings.get_boolean('embed-previews');
this.reactive = useMenu;
this._statusLabel.visible = useMenu;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bd39ab61..4d551780 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -18,4 +18,5 @@ extensions/window-list/prefs.js
extensions/window-list/workspaceIndicator.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.47.0
From 952d2ca4e3e5b35b3a25336506b06ef0dca734a9 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 29/29] 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 ++++++
1 file changed, 6 insertions(+)
diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js
index e35990ff..79cd1355 100644
--- a/extensions/window-list/prefs.js
+++ b/extensions/window-list/prefs.js
@@ -102,6 +102,12 @@ class WindowListPrefsWidget extends Gtk.Box {
});
this._settings.bind('display-all-workspaces', check, 'active', Gio.SettingsBindFlags.DEFAULT);
this.append(check);
+
+ check = new Gtk.CheckButton({
+ label: _('Show workspace previews'),
+ });
+ this._settings.bind('embed-previews', check, 'active', Gio.SettingsBindFlags.DEFAULT);
+ this.append(check);
}
});
--
2.47.0