Compare commits

...

No commits in common. 'cs10' and 'c9' have entirely different histories.
cs10 ... c9

2
.gitignore vendored

@ -1 +1 @@
SOURCES/gnome-shell-extensions-47.2.tar.xz
SOURCES/gnome-shell-extensions-40.7.tar.xz

@ -1 +1 @@
f6a5582475e6b2e2b7982594f8d646891e7771d6 SOURCES/gnome-shell-extensions-47.2.tar.xz
a905a152407590d18e8dc14bb4133fbde0e03abb SOURCES/gnome-shell-extensions-40.7.tar.xz

@ -0,0 +1,438 @@
From cca3ca69a5b5a5551a9130ab4b9ea6909666108a Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Thu, 28 Jan 2021 00:06:12 +0100
Subject: [PATCH 1/5] Add gesture-inhibitor extension
This extension may disable default GNOME Shell gestures.
---
extensions/gesture-inhibitor/extension.js | 75 +++++++++++++++++++
extensions/gesture-inhibitor/meson.build | 8 ++
extensions/gesture-inhibitor/metadata.json.in | 12 +++
...l.extensions.gesture-inhibitor.gschema.xml | 25 +++++++
extensions/gesture-inhibitor/stylesheet.css | 1 +
meson.build | 1 +
6 files changed, 122 insertions(+)
create mode 100644 extensions/gesture-inhibitor/extension.js
create mode 100644 extensions/gesture-inhibitor/meson.build
create mode 100644 extensions/gesture-inhibitor/metadata.json.in
create mode 100644 extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
create mode 100644 extensions/gesture-inhibitor/stylesheet.css
diff --git a/extensions/gesture-inhibitor/extension.js b/extensions/gesture-inhibitor/extension.js
new file mode 100644
index 00000000..e74ede2f
--- /dev/null
+++ b/extensions/gesture-inhibitor/extension.js
@@ -0,0 +1,75 @@
+/* extension.js
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/* exported init */
+
+const Clutter = imports.gi.Clutter;
+const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
+const ViewSelector = imports.ui.viewSelector;
+const EdgeDragAction = imports.ui.edgeDragAction;
+const WindowManager = imports.ui.windowManager;
+const St = imports.gi.St;
+const Gio = imports.gi.Gio;
+
+class Extension {
+ constructor() {
+ this._settings = ExtensionUtils.getSettings();
+ let actions = global.stage.get_actions();
+
+ actions.forEach(a => {
+ if (a instanceof ViewSelector.ShowOverviewAction)
+ this._showOverview = a;
+ else if (a instanceof WindowManager.AppSwitchAction)
+ this._appSwitch = a;
+ else if (a instanceof EdgeDragAction.EdgeDragAction &&
+ a._side == St.Side.BOTTOM)
+ this._showOsk = a;
+ else if (a instanceof EdgeDragAction.EdgeDragAction &&
+ a._side == St.Side.TOP)
+ this._unfullscreen = a;
+ else if (a instanceof EdgeDragAction.EdgeDragAction)
+ this._showAppGrid = a;
+ });
+
+ this._map = [
+ { setting: 'overview', action: this._showOverview },
+ { setting: 'app-switch', action: this._appSwitch },
+ { setting: 'show-osk', action: this._showOsk },
+ { setting: 'unfullscreen', action: this._unfullscreen },
+ { setting: 'show-app-grid', action: this._showAppGrid }
+ ];
+ }
+
+ enable() {
+ this._map.forEach(m => {
+ this._settings.bind(m.setting, m.action, 'enabled',
+ Gio.SettingsBindFlags.DEFAULT);
+ });
+ }
+
+ disable() {
+ this._map.forEach(m => {
+ m.action.enabled = true;
+ });
+ }
+}
+
+function init() {
+ return new Extension();
+}
diff --git a/extensions/gesture-inhibitor/meson.build b/extensions/gesture-inhibitor/meson.build
new file mode 100644
index 00000000..fdad5cc8
--- /dev/null
+++ b/extensions/gesture-inhibitor/meson.build
@@ -0,0 +1,8 @@
+extension_data += configure_file(
+ input: metadata_name + '.in',
+ output: metadata_name,
+ configuration: metadata_conf
+)
+
+# extension_sources += files('prefs.js')
+extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
diff --git a/extensions/gesture-inhibitor/metadata.json.in b/extensions/gesture-inhibitor/metadata.json.in
new file mode 100644
index 00000000..37d6a117
--- /dev/null
+++ b/extensions/gesture-inhibitor/metadata.json.in
@@ -0,0 +1,12 @@
+{
+ "uuid": "@uuid@",
+ "extension-id": "@extension_id@",
+ "settings-schema": "@gschemaname@",
+ "gettext-domain": "@gettext_domain@",
+ "name": "Gesture Inhibitor",
+ "description": "Makes touchscreen gestures optional.",
+ "shell-version": [ "@shell_current@" ],
+ "original-authors": [ "cgarnach@redhat.com" ],
+ "url": "@url@"
+}
+
diff --git a/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
new file mode 100644
index 00000000..1d67dcc0
--- /dev/null
+++ b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
@@ -0,0 +1,25 @@
+<schemalist>
+ <schema id="org.gnome.shell.extensions.gesture-inhibitor" path="/org/gnome/shell/extensions/gesture-inhibitor/">
+ <key name="show-app-grid" type="b">
+ <default>true</default>
+ <summary>Show app grid gesture</summary>
+ </key>
+ <key name="show-osk" type="b">
+ <default>true</default>
+ <summary>Show OSK gesture</summary>
+ </key>
+ <key name="overview" type="b">
+ <default>true</default>
+ <summary>Show Overview gesture</summary>
+ </key>
+ <key name="app-switch" type="b">
+ <default>true</default>
+ <summary>Application switch gesture</summary>
+ </key>
+ <key name="unfullscreen" type="b">
+ <default>true</default>
+ <summary>Unfullscreen gesture</summary>
+ </key>
+ </schema>
+</schemalist>
+
diff --git a/extensions/gesture-inhibitor/stylesheet.css b/extensions/gesture-inhibitor/stylesheet.css
new file mode 100644
index 00000000..37b93f21
--- /dev/null
+++ b/extensions/gesture-inhibitor/stylesheet.css
@@ -0,0 +1 @@
+/* Add your custom extension styling here */
diff --git a/meson.build b/meson.build
index ec600041..615dc5b0 100644
--- a/meson.build
+++ b/meson.build
@@ -50,6 +50,7 @@ all_extensions += [
'custom-menu',
'dash-to-dock',
'dash-to-panel',
+ 'gesture-inhibitor',
'native-window-placement',
'panel-favorites',
'systemMonitor',
--
2.41.0
From 45e88e7b5bb9537c44384a23af7d00f023d55793 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 20 Oct 2021 19:48:46 +0200
Subject: [PATCH 2/5] gesture-inhibitor: Fix up indentation
---
extensions/gesture-inhibitor/extension.js | 59 +++++++++++------------
1 file changed, 29 insertions(+), 30 deletions(-)
diff --git a/extensions/gesture-inhibitor/extension.js b/extensions/gesture-inhibitor/extension.js
index e74ede2f..734d61cc 100644
--- a/extensions/gesture-inhibitor/extension.js
+++ b/extensions/gesture-inhibitor/extension.js
@@ -29,44 +29,43 @@ const Gio = imports.gi.Gio;
class Extension {
constructor() {
- this._settings = ExtensionUtils.getSettings();
- let actions = global.stage.get_actions();
+ this._settings = ExtensionUtils.getSettings();
+ let actions = global.stage.get_actions();
- actions.forEach(a => {
- if (a instanceof ViewSelector.ShowOverviewAction)
- this._showOverview = a;
- else if (a instanceof WindowManager.AppSwitchAction)
- this._appSwitch = a;
- else if (a instanceof EdgeDragAction.EdgeDragAction &&
- a._side == St.Side.BOTTOM)
- this._showOsk = a;
- else if (a instanceof EdgeDragAction.EdgeDragAction &&
- a._side == St.Side.TOP)
- this._unfullscreen = a;
- else if (a instanceof EdgeDragAction.EdgeDragAction)
- this._showAppGrid = a;
- });
+ actions.forEach(a => {
+ if (a instanceof ViewSelector.ShowOverviewAction)
+ this._showOverview = a;
+ else if (a instanceof WindowManager.AppSwitchAction)
+ this._appSwitch = a;
+ else if (a instanceof EdgeDragAction.EdgeDragAction &&
+ a._side == St.Side.BOTTOM)
+ this._showOsk = a;
+ else if (a instanceof EdgeDragAction.EdgeDragAction &&
+ a._side == St.Side.TOP)
+ this._unfullscreen = a;
+ else if (a instanceof EdgeDragAction.EdgeDragAction)
+ this._showAppGrid = a;
+ });
- this._map = [
- { setting: 'overview', action: this._showOverview },
- { setting: 'app-switch', action: this._appSwitch },
- { setting: 'show-osk', action: this._showOsk },
- { setting: 'unfullscreen', action: this._unfullscreen },
- { setting: 'show-app-grid', action: this._showAppGrid }
- ];
+ this._map = [
+ { setting: 'overview', action: this._showOverview },
+ { setting: 'app-switch', action: this._appSwitch },
+ { setting: 'show-osk', action: this._showOsk },
+ { setting: 'unfullscreen', action: this._unfullscreen },
+ { setting: 'show-app-grid', action: this._showAppGrid }
+ ];
}
enable() {
- this._map.forEach(m => {
- this._settings.bind(m.setting, m.action, 'enabled',
- Gio.SettingsBindFlags.DEFAULT);
- });
+ this._map.forEach(m => {
+ this._settings.bind(m.setting, m.action, 'enabled',
+ Gio.SettingsBindFlags.DEFAULT);
+ });
}
disable() {
- this._map.forEach(m => {
- m.action.enabled = true;
- });
+ this._map.forEach(
+ m => (m.action.enabled = true));
}
}
--
2.41.0
From fe0dd05f0c8c5cfeb5edbc6b9bb73417d42f6ee8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 20 Oct 2021 19:47:05 +0200
Subject: [PATCH 3/5] gesture-inhibitor: Adjust for GNOME 40 changes
---
extensions/gesture-inhibitor/extension.js | 11 +++--------
...ome.shell.extensions.gesture-inhibitor.gschema.xml | 4 ----
2 files changed, 3 insertions(+), 12 deletions(-)
diff --git a/extensions/gesture-inhibitor/extension.js b/extensions/gesture-inhibitor/extension.js
index 734d61cc..13586108 100644
--- a/extensions/gesture-inhibitor/extension.js
+++ b/extensions/gesture-inhibitor/extension.js
@@ -21,8 +21,8 @@
const Clutter = imports.gi.Clutter;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
-const ViewSelector = imports.ui.viewSelector;
const EdgeDragAction = imports.ui.edgeDragAction;
+const Main = imports.ui.main;
const WindowManager = imports.ui.windowManager;
const St = imports.gi.St;
const Gio = imports.gi.Gio;
@@ -33,9 +33,7 @@ class Extension {
let actions = global.stage.get_actions();
actions.forEach(a => {
- if (a instanceof ViewSelector.ShowOverviewAction)
- this._showOverview = a;
- else if (a instanceof WindowManager.AppSwitchAction)
+ if (a instanceof WindowManager.AppSwitchAction)
this._appSwitch = a;
else if (a instanceof EdgeDragAction.EdgeDragAction &&
a._side == St.Side.BOTTOM)
@@ -43,16 +41,13 @@ class Extension {
else if (a instanceof EdgeDragAction.EdgeDragAction &&
a._side == St.Side.TOP)
this._unfullscreen = a;
- else if (a instanceof EdgeDragAction.EdgeDragAction)
- this._showAppGrid = a;
});
this._map = [
- { setting: 'overview', action: this._showOverview },
+ { setting: 'overview', action: Main.overview._swipeTracker },
{ setting: 'app-switch', action: this._appSwitch },
{ setting: 'show-osk', action: this._showOsk },
{ setting: 'unfullscreen', action: this._unfullscreen },
- { setting: 'show-app-grid', action: this._showAppGrid }
];
}
diff --git a/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
index 1d67dcc0..4bdf9260 100644
--- a/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
+++ b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
@@ -1,9 +1,5 @@
<schemalist>
<schema id="org.gnome.shell.extensions.gesture-inhibitor" path="/org/gnome/shell/extensions/gesture-inhibitor/">
- <key name="show-app-grid" type="b">
- <default>true</default>
- <summary>Show app grid gesture</summary>
- </key>
<key name="show-osk" type="b">
<default>true</default>
<summary>Show OSK gesture</summary>
--
2.41.0
From 952fa19311faecf50b02ab0f8807c2bc890848be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 18 Nov 2021 15:54:23 +0100
Subject: [PATCH 4/5] gesture-inhibitor: Unbind setting on disable
---
extensions/gesture-inhibitor/extension.js | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/extensions/gesture-inhibitor/extension.js b/extensions/gesture-inhibitor/extension.js
index 13586108..02b34ec4 100644
--- a/extensions/gesture-inhibitor/extension.js
+++ b/extensions/gesture-inhibitor/extension.js
@@ -59,8 +59,10 @@ class Extension {
}
disable() {
- this._map.forEach(
- m => (m.action.enabled = true));
+ this._map.forEach(m => {
+ Gio.Settings.unbind(m.action, 'enabled');
+ m.action.enabled = true;
+ });
}
}
--
2.41.0
From ef7a6cb1eac7b3d6d4d047174502d88f4e78959e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 18 Nov 2021 16:06:09 +0100
Subject: [PATCH 5/5] gesture-inhibitor: Override :enabled property
Otherwise gnome-shell can re-enable an inhibited gesture behind our
back.
---
extensions/gesture-inhibitor/extension.js | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/extensions/gesture-inhibitor/extension.js b/extensions/gesture-inhibitor/extension.js
index 02b34ec4..fb8a6dc0 100644
--- a/extensions/gesture-inhibitor/extension.js
+++ b/extensions/gesture-inhibitor/extension.js
@@ -49,18 +49,39 @@ class Extension {
{ setting: 'show-osk', action: this._showOsk },
{ setting: 'unfullscreen', action: this._unfullscreen },
];
+
+ this._enabledDesc = Object.getOwnPropertyDescriptor(
+ Clutter.ActorMeta.prototype, 'enabled');
+ }
+
+ _overrideEnabledSetter(obj, set) {
+ if (!(obj instanceof Clutter.ActorMeta))
+ return;
+
+ const desc = set
+ ? { ...this._enabledDesc, set }
+ : { ...this._enabledDesc };
+ Object.defineProperty(obj, 'enabled', desc);
}
enable() {
+ const settings = this._settings;
+
this._map.forEach(m => {
- this._settings.bind(m.setting, m.action, 'enabled',
+ settings.bind(m.setting, m.action, 'enabled',
Gio.SettingsBindFlags.DEFAULT);
+
+ this._overrideEnabledSetter(m.action, function (value) {
+ if (settings.get_boolean(m.setting))
+ this.set_enabled(value);
+ });
});
}
disable() {
this._map.forEach(m => {
Gio.Settings.unbind(m.action, 'enabled');
+ this._overrideEnabledSetter(m.action);
m.action.enabled = true;
});
}
--
2.41.0

@ -1,32 +0,0 @@
From b373d600104d6a5c4984521d934c5d02af3a2b99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 23 Feb 2018 16:56:46 +0100
Subject: [PATCH] Include status-icons in classic session
---
meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index d092830f..14143501 100644
--- a/meson.build
+++ b/meson.build
@@ -35,6 +35,7 @@ classic_extensions = [
'apps-menu',
'places-menu',
'launch-new-instance',
+ 'status-icons',
'window-list',
]
@@ -45,7 +46,6 @@ default_extensions += [
'heads-up-display',
'light-style',
'screenshot-window-sizer',
- 'status-icons',
'system-monitor',
'windowsNavigator',
'workspace-indicator',
--
2.47.1

@ -0,0 +1,32 @@
From 1982ab4218fa3a7ff622fff5af7c15c2e11351f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 23 Feb 2018 16:56:46 +0100
Subject: [PATCH] Include top-icons in classic session
---
meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index afc0133..78dee5b 100644
--- a/meson.build
+++ b/meson.build
@@ -31,6 +31,7 @@ classic_extensions = [
'desktop-icons',
'places-menu',
'launch-new-instance',
+ 'top-icons',
'window-list'
]
@@ -49,7 +50,6 @@ all_extensions += [
'native-window-placement',
'panel-favorites',
'systemMonitor',
- 'top-icons',
'updates-dialog',
'user-theme'
]
--
2.32.0

@ -0,0 +1,43 @@
From 9ca03a744552c43251523fd23292b243130e1f89 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 24 May 2021 15:36:04 +0200
Subject: [PATCH] Update style
---
data/gnome-shell-sass | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Submodule data/gnome-shell-sass 9d66f7d..60230f4:
diff --git a/data/gnome-shell-sass/widgets/_panel.scss b/data/gnome-shell-sass/widgets/_panel.scss
index 1f46507..ad638b2 100644
--- a/data/gnome-shell-sass/widgets/_panel.scss
+++ b/data/gnome-shell-sass/widgets/_panel.scss
@@ -67,6 +67,11 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
}
}
+ .panel-logo-icon {
+ padding-right: .4em;
+ icon-size: 1em;
+ }
+
// status area icons
.system-status-icon {
icon-size: $base_icon_size;
diff --git a/data/gnome-classic.css b/data/gnome-classic.css
index 52e5367..3be81e9 100644
--- a/data/gnome-classic.css
+++ b/data/gnome-classic.css
@@ -1234,6 +1234,9 @@ StScrollBar {
box-shadow: none; }
#panel .panel-button.clock-display:hover .clock, #panel .panel-button.clock-display:active .clock, #panel .panel-button.clock-display:overview .clock, #panel .panel-button.clock-display:focus .clock, #panel .panel-button.clock-display:checked .clock {
box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.2); }
+ #panel .panel-button .panel-logo-icon {
+ padding-right: .4em;
+ icon-size: 1em; }
#panel .panel-button .system-status-icon {
icon-size: 1.09em;
padding: 5px;
--
2.28.0

@ -0,0 +1,29 @@
From fe13aa54e7c104f63689fcd15957ab16ffc0c3ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 17 Mar 2016 17:15:38 +0100
Subject: [PATCH] apps-menu: Explicitly set label_actor
For some reason orca fails to pick up the label of category items,
so set the label_actor explicitly as workaround.
---
extensions/apps-menu/extension.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index 983a4e7..f8cef41 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -113,7 +113,9 @@ class CategoryMenuItem extends PopupMenu.PopupBaseMenuItem {
else
name = _('Favorites');
- this.add_child(new St.Label({ text: name }));
+ const label = new St.Label({ text: name });
+ this.add_child(label);
+ this.actor.label_actor = label;
this.connect('motion-event', this._onMotionEvent.bind(this));
this.connect('notify::active', this._onActiveChanged.bind(this));
}
--
2.32.0

@ -0,0 +1,66 @@
From 08e720c793baa0cb12ed99c4333c75df46e3a9ed Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 21 Jan 2014 16:48:17 -0500
Subject: [PATCH] apps-menu: add logo icon to Applications menu
Brand requested it.
---
extensions/apps-menu/extension.js | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index e36b0fe..983a4e7 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -364,13 +364,24 @@ class ApplicationsButton extends PanelMenu.Button {
// role ATK_ROLE_MENU like other elements of the panel.
this.accessible_role = Atk.Role.LABEL;
+ const hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
+
+ const iconFile = Gio.File.new_for_path(
+ '/usr/share/icons/hicolor/scalable/apps/start-here.svg');
+ this._icon = new St.Icon({
+ gicon: new Gio.FileIcon({ file: iconFile }),
+ style_class: 'panel-logo-icon',
+ });
+ hbox.add_actor(this._icon);
+
this._label = new St.Label({
text: _('Applications'),
y_expand: true,
y_align: Clutter.ActorAlign.CENTER,
});
+ hbox.add_actor(this._label);
- this.add_actor(this._label);
+ this.add_actor(hbox);
this.name = 'panelApplications';
this.label_actor = this._label;
@@ -404,6 +415,14 @@ class ApplicationsButton extends PanelMenu.Button {
this._display();
this._installedChangedId = appSys.connect('installed-changed',
this._onTreeChanged.bind(this));
+ this._sessionUpdatedId = Main.sessionMode.connect('updated',
+ this._sessionUpdated.bind(this));
+ this._sessionUpdated();
+ }
+
+ _sessionUpdated() {
+ this._icon.visible =
+ !Main.sessionMode.panel.left.includes('activities');
}
_onTreeChanged() {
@@ -429,6 +448,7 @@ class ApplicationsButton extends PanelMenu.Button {
Main.overview.disconnect(this._showingId);
Main.overview.disconnect(this._hidingId);
+ Main.sessionMode.disconnect(this._sessionUpdatedId);
appSys.disconnect(this._installedChangedId);
this._tree.disconnect(this._treeChangedId);
this._tree = null;
--
2.32.0

@ -0,0 +1,68 @@
From ffba821e1142c3cb96b9ced24dd1f161f0609d2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 14 Dec 2022 16:55:51 +0100
Subject: [PATCH] classification-banner: Handle fullscreen monitors
When a monitor is in fullscreen, we don't want its classification
banner to be offset by an imaginary panel, but at the top of the
screen.
---
extensions/classification-banner/extension.js | 22 +++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/extensions/classification-banner/extension.js b/extensions/classification-banner/extension.js
index cc046e01..ea788022 100644
--- a/extensions/classification-banner/extension.js
+++ b/extensions/classification-banner/extension.js
@@ -27,16 +27,19 @@ const Main = imports.ui.main;
const ClassificationBanner = GObject.registerClass(
class ClassificationBanner extends Clutter.Actor {
_init(index) {
+ const constraint = new Layout.MonitorConstraint({index});
super._init({
layout_manager: new Clutter.BinLayout(),
- constraints: new Layout.MonitorConstraint({
- work_area: true,
- index,
- }),
+ constraints: constraint,
});
+ this._monitorConstraint = constraint;
this._settings = ExtensionUtils.getSettings();
this.connect('destroy', () => {
+ if (this._fullscreenChangedId)
+ global.display.disconnect(this._fullscreenChangedId);
+ delete this._fullscreenChangedId;
+
this._settings?.run_dispose();
this._settings = null;
});
@@ -94,6 +97,11 @@ class ClassificationBanner extends Clutter.Actor {
userLabel, 'visible',
Gio.SettingsBindFlags.GET);
+ this._fullscreenChangedId =
+ global.display.connect('in-fullscreen-changed',
+ () => this._updateMonitorConstraint());
+ this._updateMonitorConstraint();
+
this._settings.connect('changed::color',
() => this._updateStyles());
this._settings.connect('changed::background-color',
@@ -110,6 +118,12 @@ class ClassificationBanner extends Clutter.Actor {
return `${key}: rgba(${red},${green},${blue},${alpha / 255});`;
}
+ _updateMonitorConstraint() {
+ const {index} = this._monitorConstraint;
+ this._monitorConstraint.work_area =
+ !global.display.get_monitor_in_fullscreen(index);
+ }
+
_updateStyles() {
const bgStyle = this._getColorSetting('background-color');
const fgStyle = this._getColorSetting('color');
--
2.38.1

@ -0,0 +1,39 @@
From b9ba6b8708c18fb14033150fdb02a508457e0a17 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 2 Feb 2024 15:39:32 +0100
Subject: [PATCH] classification-banner: Hide from picks
Banners are laid out via a fullscreen actor. While the actor is
not reactive, it can still interfere with picks (for example
during drag-and-drop operations).
Avoid that by explicitly hiding the actor from picks.
---
extensions/classification-banner/extension.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/extensions/classification-banner/extension.js b/extensions/classification-banner/extension.js
index ea788022..2bde741e 100644
--- a/extensions/classification-banner/extension.js
+++ b/extensions/classification-banner/extension.js
@@ -18,7 +18,7 @@
/* exported init */
-const { Clutter, Gio, GLib, GObject, St } = imports.gi;
+const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
const Layout = imports.ui.layout;
@@ -34,6 +34,8 @@ class ClassificationBanner extends Clutter.Actor {
});
this._monitorConstraint = constraint;
+ Shell.util_set_hidden_from_pick(this, true);
+
this._settings = ExtensionUtils.getSettings();
this.connect('destroy', () => {
if (this._fullscreenChangedId)
--
2.43.0

@ -0,0 +1,33 @@
From 8bea7c892c24694efda753ad1d76ab470032c6fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 15 Dec 2022 17:09:45 +0100
Subject: [PATCH] desktop-icons: Don't grab focus on click
We will move keyboard focus away immediately, either when opening
the context menu or when starting the rubberband.
In theory the grab is still useful, because it will move keyboard
focus to the grid when restoring focus after ending the rubberband
or closing the menu, however as keyboard navigation support is
lacking, all it does is preventing the focus to return to the
focus window after the operation.
---
extensions/desktop-icons/desktopGrid.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js
index 002803c7..9a89d5a3 100644
--- a/extensions/desktop-icons/desktopGrid.js
+++ b/extensions/desktop-icons/desktopGrid.js
@@ -559,8 +559,6 @@ var DesktopGrid = GObject.registerClass({
let button = event.get_button();
let [x, y] = event.get_coords();
- this._grid.grab_key_focus();
-
if (button == 1) {
let shiftPressed = !!(event.get_state() & Clutter.ModifierType.SHIFT_MASK);
let controlPressed = !!(event.get_state() & Clutter.ModifierType.CONTROL_MASK);
--
2.38.1

@ -0,0 +1,33 @@
From b48dae39341a3ba24eb3d142f99eb37d6b14ab41 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 2 Nov 2023 20:51:45 +0100
Subject: [PATCH] desktop-icons: Don't try spawn with non-existent workdir
g_spawn_async() will fail if the specified workdir doesn't exist.
That means that opening a terminal from the context menu will fail
when the desktop directory doesn't exist.
The extension doesn't really make sense in that case, but when we
show an "Open in Terminal" menu item even then, users expect it
to work.
---
extensions/desktop-icons/desktopIconsUtil.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/extensions/desktop-icons/desktopIconsUtil.js b/extensions/desktop-icons/desktopIconsUtil.js
index 57bedc13..c3fe5977 100644
--- a/extensions/desktop-icons/desktopIconsUtil.js
+++ b/extensions/desktop-icons/desktopIconsUtil.js
@@ -50,6 +50,9 @@ function launchTerminal(workdir) {
* https://gitlab.gnome.org/GNOME/gnome-shell/blob/gnome-3-30/js/misc/util.js
*/
+ if (!GLib.file_test(workdir, GLib.FileTest.EXISTS))
+ workdir = null;
+
var success, pid;
try {
[success, pid] = GLib.spawn_async(workdir, argv, null,
--
2.41.0

@ -0,0 +1,108 @@
From 2a1dd773a529c89b5f9577b53ae3c88aea2efc48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 17 Jan 2023 20:31:21 +0100
Subject: [PATCH] desktop-icons: Don't use blocking IO
---
extensions/desktop-icons/desktopManager.js | 45 +++++++++++++++-------
1 file changed, 32 insertions(+), 13 deletions(-)
diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js
index 74d0e6bd..75b2a22a 100644
--- a/extensions/desktop-icons/desktopManager.js
+++ b/extensions/desktop-icons/desktopManager.js
@@ -54,6 +54,21 @@ function findMonitorIndexForPos(x, y) {
return getDpy().get_monitor_index_for_rect(new Meta.Rectangle({x, y}));
}
+async function queryInfo(file, attributes = DesktopIconsUtil.DEFAULT_ATTRIBUTES, cancellable = null) {
+ const flags = Gio.FileQueryInfoFlags.NONE;
+ const priority = GLib.PRIORITY_DEFAULT;
+ return new Promise((resolve, reject) => {
+ file.query_info_async(attributes, flags, priority, cancellable, (o, res) => {
+ try {
+ const info = file.query_info_finish(res);
+ resolve(info);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+}
+
var DesktopManager = GObject.registerClass({
Properties: {
@@ -272,9 +287,7 @@ var DesktopManager = GObject.registerClass({
if (!this._unixMode) {
let desktopDir = DesktopIconsUtil.getDesktopDir();
- let fileInfo = desktopDir.query_info(Gio.FILE_ATTRIBUTE_UNIX_MODE,
- Gio.FileQueryInfoFlags.NONE,
- null);
+ let fileInfo = await queryInfo(desktopDir, Gio.FILE_ATTRIBUTE_UNIX_MODE);
this._unixMode = fileInfo.get_attribute_uint32(Gio.FILE_ATTRIBUTE_UNIX_MODE);
this._setWritableByOthers((this._unixMode & S_IWOTH) != 0);
}
@@ -283,7 +296,7 @@ var DesktopManager = GObject.registerClass({
let items = [];
for (let item of await this._enumerateDesktop())
items.push(item);
- for (let item of this._getMounts())
+ for (let item of await this._getMounts())
items.push(item);
let tmpFileItems = new Map();
@@ -328,14 +341,22 @@ var DesktopManager = GObject.registerClass({
Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_DEFAULT,
this._desktopEnumerateCancellable,
- (source, result) => {
+ async (source, result) => {
try {
let fileEnum = source.enumerate_children_finish(result);
+ let extraFolders = await Promise.all(DesktopIconsUtil.getExtraFolders()
+ .map(async ([folder, extras]) => {
+ const info = await queryInfo(folder,
+ DesktopIconsUtil.DEFAULT_ATTRIBUTES,
+ this._desktopEnumerateCancellable);
+ return [folder, info, extras];
+ }));
+
let resultGenerator = function *() {
+ for (let [newFolder, info, extras] of extraFolders)
+ yield [newFolder, info, extras];
+
let info;
- for (let [newFolder, extras] of DesktopIconsUtil.getExtraFolders()) {
- yield [newFolder, newFolder.query_info(DesktopIconsUtil.DEFAULT_ATTRIBUTES, Gio.FileQueryInfoFlags.NONE, this._desktopEnumerateCancellable), extras];
- }
while ((info = fileEnum.next_file(null)))
yield [fileEnum.get_child(info), info, Prefs.FileType.NONE];
}.bind(this);
@@ -359,19 +380,17 @@ var DesktopManager = GObject.registerClass({
this._monitorDesktopDir.connect('changed', (obj, file, otherFile, eventType) => this._updateDesktopIfChanged(file, otherFile, eventType));
}
- _getMounts() {
+ async _getMounts() {
let files = [];
if (!Prefs.settings.get_boolean('show-mount'))
return files;
- this._mountMonitor.get_mounts().forEach( mount => {
+ this._mountMonitor.get_mounts().forEach(async mount => {
if (this._isNetworkMount(mount))
return;
let file = mount.get_root();
- let info = file.query_info(DesktopIconsUtil.DEFAULT_ATTRIBUTES,
- Gio.FileQueryInfoFlags.NONE,
- null);
+ let info = await queryInfo(file);
files.push([file, info, Prefs.FileType.MOUNT_DISK]);
});
--
2.38.1

@ -0,0 +1,209 @@
From 73000f25e578b3ce6654fdf0d3da2ec3d9b95dd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@redhat.com>
Date: Tue, 2 Nov 2021 09:20:11 +0100
Subject: [PATCH] desktop-icons: Fix stuck grab issue with rubber banding
The desktop icons extension can get into a state where the desktop no longer
takes mouse input.
This happens if a user starts a rubber banding operation and then drags
the mouse to somewhere on screen that has a pop up menu, and then pops
the menu up.
This commit addresses the bug by limiting the grab actor to the
backgrounds, and by explicitly ending the rubber banding operation
when one of the icons own menus is shown.
One side effect of limiting the grab actor to the backgrounds, is the
rubber banding code never gets to see motion outside of the backgrounds
anymore. In order to keep drag operations feeling fluid when the user moves
toward the edge of the screen, this commit also overrides the
grab helpers captured-event handler so those motion events keep coming.
We also start to end the rubber band if for any reason the grab it had
was released.
---
extensions/desktop-icons/desktopGrid.js | 1 +
extensions/desktop-icons/desktopManager.js | 109 ++++++++++++---------
extensions/desktop-icons/fileItem.js | 1 +
3 files changed, 67 insertions(+), 44 deletions(-)
diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js
index 002803c..c7846bf 100644
--- a/extensions/desktop-icons/desktopGrid.js
+++ b/extensions/desktop-icons/desktopGrid.js
@@ -388,6 +388,7 @@ var DesktopGrid = GObject.registerClass({
}
_openMenu(x, y) {
+ Extension.desktopManager.endRubberBand();
Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
this._submenu.menu.removeAll();
let templates = Extension.templateManager.getTemplates();
diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js
index 10e3ce0..08bc82b 100644
--- a/extensions/desktop-icons/desktopManager.js
+++ b/extensions/desktop-icons/desktopManager.js
@@ -81,6 +81,7 @@ var DesktopManager = GObject.registerClass({
this._unixMode = null;
this._writableByOthers = null;
this._discreteGpuAvailable = false;
+ this._rubberBandActive = false;
this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._recreateDesktopIcons());
this._rubberBand = new St.Widget({ style_class: 'rubber-band' });
@@ -94,6 +95,20 @@ var DesktopManager = GObject.registerClass({
this._mountRemovedId = this._mountMonitor.connect('mount-removed', (monitor, mount) => {
this._recreateDesktopIcons(); });
+ let origCapturedEvent = this._grabHelper.onCapturedEvent;
+ this._grabHelper.onCapturedEvent = (event) => {
+ if (event.type() === Clutter.EventType.MOTION) {
+ /* We handle motion events from a captured event handler so we
+ * we can see motion over actors that are on other parts of the
+ * stage.
+ */
+ this._handleMotion(event);
+ return Clutter.EVENT_STOP;
+ }
+
+ return origCapturedEvent.bind(this._grabHelper)(event);
+ };
+
this._addDesktopIcons();
this._monitorDesktopFolder();
@@ -133,57 +148,67 @@ var DesktopManager = GObject.registerClass({
this._rubberBandInitialY = y;
this._updateRubberBand(x, y);
this._rubberBand.show();
- this._grabHelper.grab({ actor: global.stage });
+ this._rubberBandActive = true;
+ this._grabHelper.grab({
+ actor: Main.layoutManager._backgroundGroup,
+ onUngrab: () => this.endRubberBand(false),
+ });
Extension.lockActivitiesButton = true;
this._stageReleaseEventId = global.stage.connect('button-release-event', (actor, event) => {
this.endRubberBand();
});
this._rubberBandId = global.stage.connect('motion-event', (actor, event) => {
- /* In some cases, when the user starts a rubberband selection and ends it
- * (by releasing the left button) over a window instead of doing it over
- * the desktop, the stage doesn't receive the "button-release" event.
- * This happens currently with, at least, Dash to Dock extension, but
- * it probably also happens with other applications or extensions.
- * To fix this, we also end the rubberband selection if we detect mouse
- * motion in the stage without the left button pressed during a
- * rubberband selection.
- * */
- let button = event.get_state();
- if (!(button & Clutter.ModifierType.BUTTON1_MASK)) {
- this.endRubberBand();
- return;
- }
- [x, y] = event.get_coords();
- this._updateRubberBand(x, y);
- let x0, y0, x1, y1;
- if (x >= this._rubberBandInitialX) {
- x0 = this._rubberBandInitialX;
- x1 = x;
- } else {
- x1 = this._rubberBandInitialX;
- x0 = x;
- }
- if (y >= this._rubberBandInitialY) {
- y0 = this._rubberBandInitialY;
- y1 = y;
- } else {
- y1 = this._rubberBandInitialY;
- y0 = y;
- }
- for (let [fileUri, fileItem] of this._fileItems) {
- fileItem.emit('selected', true, true,
- fileItem.intersectsWith(x0, y0, x1 - x0, y1 - y0));
- }
});
}
- endRubberBand() {
+ _handleMotion(event) {
+ /* In some cases, when the user starts a rubberband selection and ends it
+ * (by releasing the left button) over a window instead of doing it over
+ * the desktop, the stage doesn't receive the "button-release" event.
+ * This happens currently with, at least, Dash to Dock extension, but
+ * it probably also happens with other applications or extensions.
+ * To fix this, we also end the rubberband selection if we detect mouse
+ * motion in the stage without the left button pressed during a
+ * rubberband selection.
+ * */
+ let button = event.get_state();
+ if (!(button & Clutter.ModifierType.BUTTON1_MASK)) {
+ this.endRubberBand();
+ return;
+ }
+ let [x, y] = event.get_coords();
+ this._updateRubberBand(x, y);
+ let x0, y0, x1, y1;
+ if (x >= this._rubberBandInitialX) {
+ x0 = this._rubberBandInitialX;
+ x1 = x;
+ } else {
+ x1 = this._rubberBandInitialX;
+ x0 = x;
+ }
+ if (y >= this._rubberBandInitialY) {
+ y0 = this._rubberBandInitialY;
+ y1 = y;
+ } else {
+ y1 = this._rubberBandInitialY;
+ y0 = y;
+ }
+ for (let [fileUri, fileItem] of this._fileItems) {
+ fileItem.emit('selected', true, true,
+ fileItem.intersectsWith(x0, y0, x1 - x0, y1 - y0));
+ }
+ }
+
+ endRubberBand(ungrab=true) {
+ if (!this._rubberBandActive)
+ return;
+
+ this._rubberBandActive = false;
this._rubberBand.hide();
Extension.lockActivitiesButton = false;
- this._grabHelper.ungrab();
- global.stage.disconnect(this._rubberBandId);
+ if (ungrab)
+ this._grabHelper.ungrab();
global.stage.disconnect(this._stageReleaseEventId);
- this._rubberBandId = 0;
this._stageReleaseEventId = 0;
this._selection = new Set([...this._selection, ...this._currentSelection]);
@@ -825,10 +850,6 @@ var DesktopManager = GObject.registerClass({
global.stage.disconnect(this._stageReleaseEventId);
this._stageReleaseEventId = 0;
- if (this._rubberBandId)
- global.stage.disconnect(this._rubberBandId);
- this._rubberBandId = 0;
-
this._rubberBand.destroy();
if (this._queryFileInfoCancellable)
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
index 1e8ea89..37ee54d 100644
--- a/extensions/desktop-icons/fileItem.js
+++ b/extensions/desktop-icons/fileItem.js
@@ -747,6 +747,7 @@ var FileItem = GObject.registerClass({
}
_onPressButton(actor, event) {
+ Extension.desktopManager.endRubberBand();
this._updateClickState(event);
let button = event.get_button();
if (button == 3) {
--
2.31.1

@ -0,0 +1,29 @@
From ba4208c00504439bad19de4680fac68210767798 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 27 Jan 2021 11:51:28 +0100
Subject: [PATCH] desktop-icons: Update Japanese translation
---
po/ja.po | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/po/ja.po b/po/ja.po
index 8eb7725..ddf1eb7 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -897,11 +897,7 @@ msgstr "押し込み量 (ピクセル)"
#: desktopGrid.js:359
#, fuzzy
msgid "Display Settings"
-msgstr ""
-"#-#-#-#-# ja.po (gnome-shell-extensions master) #-#-#-#-#\n"
-"ディスプレイ設定\n"
-"#-#-#-#-# ja.po (desktop-icons master) #-#-#-#-#\n"
-"ディスプレイの設定"
+msgstr "ディスプレイ設定"
#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
#, fuzzy
--
2.32.0

@ -0,0 +1,60 @@
From 62289dff5cb2e615a277b72f034fa42f45aad639 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 15 Dec 2022 15:14:08 +0100
Subject: [PATCH] desktopManager: Hook into LayoutManager to create grids
Right now we track the `monitors-changed` signal to recreate the
per-monitor grids. Usually that's enough, but if something else
causes backgrounds to update, we'll end up without desktop icons
until some other change (settings, mounts, monitor/resolution
changes, ...) results in a reload of the grid.
To address this, hook into LayoutManager to always create the grid
when backgrounds are updated.
---
extensions/desktop-icons/desktopManager.js | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js
index 08bc82b7..74d0e6bd 100644
--- a/extensions/desktop-icons/desktopManager.js
+++ b/extensions/desktop-icons/desktopManager.js
@@ -83,7 +83,6 @@ var DesktopManager = GObject.registerClass({
this._discreteGpuAvailable = false;
this._rubberBandActive = false;
- this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._recreateDesktopIcons());
this._rubberBand = new St.Widget({ style_class: 'rubber-band' });
this._rubberBand.hide();
Main.layoutManager._backgroundGroup.add_child(this._rubberBand);
@@ -109,6 +108,13 @@ var DesktopManager = GObject.registerClass({
return origCapturedEvent.bind(this._grabHelper)(event);
};
+ this._origUpdateBackgrounds =
+ Main.layoutManager._updateBackgrounds;
+ Main.layoutManager._updateBackgrounds = () => {
+ this._origUpdateBackgrounds.call(Main.layoutManager);
+ this._recreateDesktopIcons();
+ };
+
this._addDesktopIcons();
this._monitorDesktopFolder();
@@ -843,9 +849,10 @@ var DesktopManager = GObject.registerClass({
GLib.source_remove(this._deleteChildrenId);
this._deleteChildrenId = 0;
- if (this._monitorsChangedId)
- Main.layoutManager.disconnect(this._monitorsChangedId);
- this._monitorsChangedId = 0;
+ if (this._origUpdateBackgrounds)
+ Main.layoutManager._updateBackgrounds = this._origUpdateBackgrounds;
+ delete this._origUpdateBackgrounds;
+
if (this._stageReleaseEventId)
global.stage.disconnect(this._stageReleaseEventId);
this._stageReleaseEventId = 0;
--
2.38.1

@ -0,0 +1,29 @@
From 3edf3c0be7638bf9161c0d192dd3c2de1e3b9845 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 14 Dec 2023 14:41:04 +0100
Subject: [PATCH] docking: Only remove spacer if necessary
There may not be a main dock at the time when restoring the dash.
Handle that case by not removing a non-existent spacer, instead of
triggering an error.
---
extensions/dash-to-dock/docking.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/dash-to-dock/docking.js b/extensions/dash-to-dock/docking.js
index daa9de59..14e2ced6 100644
--- a/extensions/dash-to-dock/docking.js
+++ b/extensions/dash-to-dock/docking.js
@@ -1796,7 +1796,7 @@ var DockManager = class DashToDock_DockManager {
let overviewControls = Main.overview._overview._controls;
Main.overview._overview._controls.layout_manager._dash = this._oldDash;
- if (this.mainDock._dashSpacer) {
+ if (this.mainDock?._dashSpacer) {
Main.overview._overview._controls.remove_child(this.mainDock._dashSpacer);
}
--
2.43.0

@ -0,0 +1,40 @@
From c70a1fa37f68687b8c0a013d2328e6262f8419d0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 9 Dec 2022 15:31:08 +0100
Subject: [PATCH] gesture-inhibitor: Allow inhibiting workspace switch gesture
---
extensions/gesture-inhibitor/extension.js | 1 +
.../org.gnome.shell.extensions.gesture-inhibitor.gschema.xml | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/extensions/gesture-inhibitor/extension.js b/extensions/gesture-inhibitor/extension.js
index fb8a6dc0..d103d5b8 100644
--- a/extensions/gesture-inhibitor/extension.js
+++ b/extensions/gesture-inhibitor/extension.js
@@ -48,6 +48,7 @@ class Extension {
{ setting: 'app-switch', action: this._appSwitch },
{ setting: 'show-osk', action: this._showOsk },
{ setting: 'unfullscreen', action: this._unfullscreen },
+ { setting: 'workspace-switch', action: Main.wm._workspaceAnimation._swipeTracker },
];
this._enabledDesc = Object.getOwnPropertyDescriptor(
diff --git a/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
index 4bdf9260..b06d027a 100644
--- a/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
+++ b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
@@ -12,6 +12,10 @@
<default>true</default>
<summary>Application switch gesture</summary>
</key>
+ <key name="workspace-switch" type="b">
+ <default>true</default>
+ <summary>Workspace switch gesture</summary>
+ </key>
<key name="unfullscreen" type="b">
<default>true</default>
<summary>Unfullscreen gesture</summary>
--
2.38.1

@ -1,19 +1,19 @@
From 7b2627e3110daa4cb98a67a94f7ffa7361569003 Mon Sep 17 00:00:00 2001
From 8beb3b27486fd50f74c15d2cf9ed8ca22fb546c2 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 24 Aug 2021 15:03:57 -0400
Subject: [PATCH 3/5] Add heads-up-display
Subject: [PATCH] heads-up-display: Add extension for showing persistent heads
up display message
---
extensions/heads-up-display/extension.js | 404 ++++++++++++++++++
extensions/heads-up-display/headsUpMessage.js | 166 +++++++
extensions/heads-up-display/meson.build | 13 +
extensions/heads-up-display/metadata.json.in | 12 +
...ll.extensions.heads-up-display.gschema.xml | 60 +++
extensions/heads-up-display/prefs.js | 92 ++++
extensions/heads-up-display/stylesheet.css | 38 ++
extensions/heads-up-display/extension.js | 436 ++++++++++++++++++
extensions/heads-up-display/headsUpMessage.js | 170 +++++++
extensions/heads-up-display/meson.build | 8 +
extensions/heads-up-display/metadata.json.in | 11 +
...ll.extensions.heads-up-display.gschema.xml | 54 +++
extensions/heads-up-display/prefs.js | 194 ++++++++
extensions/heads-up-display/stylesheet.css | 32 ++
meson.build | 1 +
po/POTFILES.in | 1 +
9 files changed, 787 insertions(+)
8 files changed, 906 insertions(+)
create mode 100644 extensions/heads-up-display/extension.js
create mode 100644 extensions/heads-up-display/headsUpMessage.js
create mode 100644 extensions/heads-up-display/meson.build
@ -24,39 +24,41 @@ Subject: [PATCH 3/5] Add heads-up-display
diff --git a/extensions/heads-up-display/extension.js b/extensions/heads-up-display/extension.js
new file mode 100644
index 00000000..a71b5925
index 00000000..7cebfa99
--- /dev/null
+++ b/extensions/heads-up-display/extension.js
@@ -0,0 +1,404 @@
+// SPDX-FileCopyrightText: 2021 Ray Strode <rstrode@redhat.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
@@ -0,0 +1,436 @@
+/* exported init enable disable */
+
+import GObject from 'gi://GObject';
+import Meta from 'gi://Meta';
+import Mtk from 'gi://Mtk';
+const Signals = imports.signals;
+
+import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
+const {
+ Atk, Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St,
+} = imports.gi;
+
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+import {MonitorConstraint} from 'resource:///org/gnome/shell/ui/layout.js';
+const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
+
+import {HeadsUpMessage} from './headsUpMessage.js';
+const Main = imports.ui.main;
+const Layout = imports.ui.layout;
+const HeadsUpMessage = Me.imports.headsUpMessage;
+
+const _ = ExtensionUtils.gettext;
+
+var HeadsUpConstraint = GObject.registerClass({
+ Properties: {
+ 'offset': GObject.ParamSpec.int(
+ 'offset', 'Offset', 'offset',
+ GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
+ -1, 0, -1),
+ 'active': GObject.ParamSpec.boolean(
+ 'active', 'Active', 'active',
+ GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
+ true),
+ 'offset': GObject.ParamSpec.int('offset',
+ 'Offset', 'offset',
+ GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
+ -1, 0, -1),
+ 'active': GObject.ParamSpec.boolean('active',
+ 'Active', 'active',
+ GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
+ true),
+ },
+}, class HeadsUpConstraint extends MonitorConstraint {
+ constructor(props) {
+ super(props);
+}, class HeadsUpConstraint extends Layout.MonitorConstraint {
+ _init(props) {
+ super._init(props);
+ this._offset = 0;
+ this._active = true;
+ }
@ -66,7 +68,7 @@ index 00000000..a71b5925
+ }
+
+ set offset(o) {
+ this._offset = o;
+ this._offset = o
+ }
+
+ get active() {
@ -92,21 +94,25 @@ index 00000000..a71b5925
+ }
+});
+
+export default class HeadsUpDisplayExtension extends Extension {
+class Extension {
+ constructor() {
+ ExtensionUtils.initTranslations();
+ }
+
+ enable() {
+ this._settings = this.getSettings('org.gnome.shell.extensions.heads-up-display');
+ this._settings.connectObject('changed',
+ () => this._updateMessage(), this);
+ this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.heads-up-display');
+ this._settingsChangedId = this._settings.connect('changed', this._updateMessage.bind(this));
+
+ this._idleMonitor = global.backend.get_core_idle_monitor();
+ this._idleMonitor = Meta.IdleMonitor.get_core();
+ this._messageInhibitedUntilIdle = false;
+ global.window_manager.connectObject('map',
+ this._onWindowMap.bind(this), this);
+ this._oldMapWindow = Main.wm._mapWindow;
+ Main.wm._mapWindow = this._mapWindow;
+ this._windowManagerMapId = global.window_manager.connect('map', this._onWindowMap.bind(this));
+
+ if (Main.layoutManager._startingUp)
+ Main.layoutManager.connectObject('startup-complete', () => this._onStartupComplete(), this);
+ this._startupCompleteId = Main.layoutManager.connect('startup-complete', this._onStartupComplete.bind(this));
+ else
+ this._onStartupComplete();
+ this._onStartupComplete(this);
+ }
+
+ disable() {
@ -114,69 +120,93 @@ index 00000000..a71b5925
+
+ this._stopWatchingForIdle();
+
+ Main.sessionMode.disconnectObject(this);
+ Main.overview.disconnectObject(this);
+ Main.layoutManager.panelBox.disconnectObject(this);
+ Main.layoutManager.disconnectObject(this);
+ global.window_manager.disconnectObject(this);
+ if (this._sessionModeUpdatedId) {
+ Main.sessionMode.disconnect(this._sessionModeUpdatedId);
+ this._sessionModeUpdatedId = 0;
+ }
+
+ if (this._overviewShowingId) {
+ Main.overview.disconnect(this._overviewShowingId);
+ this._overviewShowingId = 0;
+ }
+
+ if (this._overviewHiddenId) {
+ Main.overview.disconnect(this._overviewHiddenId);
+ this._overviewHiddenId = 0;
+ }
+
+ if (this._screenShieldVisibleId) {
+ Main.screenShield._dialog._clock.disconnect(this._screenShieldVisibleId);
+ this._screenShieldVisibleId = 0;
+ }
+
+ this._settings.disconnectObject(this);
+ delete this._settings;
+ if (this._panelConnectionId) {
+ Main.layoutManager.panelBox.disconnect(this._panelConnectionId);
+ this._panelConnectionId = 0;
+ }
+
+ if (this._oldMapWindow) {
+ Main.wm._mapWindow = this._oldMapWindow;
+ this._oldMapWindow = null;
+ }
+
+ if (this._windowManagerMapId) {
+ global.window_manager.disconnect(this._windowManagerMapId);
+ this._windowManagerMapId = 0;
+ }
+
+ if (this._startupCompleteId) {
+ Main.layoutManager.disconnect(this._startupCompleteId);
+ this._startupCompleteId = 0;
+ }
+
+ if (this._settingsChangedId) {
+ this._settings.disconnect(this._settingsChangedId);
+ this._settingsChangedId = 0;
+ }
+ }
+
+ _onWindowMap(shellwm, actor) {
+ const windowObject = actor.meta_window;
+ const windowType = windowObject.get_window_type();
+
+ if (windowType !== Meta.WindowType.NORMAL)
+ if (windowType != Meta.WindowType.NORMAL)
+ return;
+
+ if (!this._message || !this._message.visible)
+ return;
+
+ const messageRect = new Mtk.Rectangle({
+ x: this._message.x,
+ y: this._message.y,
+ width: this._message.width,
+ height: this._message.height,
+ });
+ const messageRect = new Meta.Rectangle({ x: this._message.x, y: this._message.y, width: this._message.width, height: this._message.height });
+ const windowRect = windowObject.get_frame_rect();
+
+ if (windowRect.intersect(messageRect))
+ if (windowRect.intersect(messageRect)) {
+ windowObject.move_frame(false, windowRect.x, this._message.y + this._message.height);
+ }
+ }
+
+ _onStartupComplete() {
+ Main.overview.connectObject(
+ 'showing', () => this._updateMessage(),
+ 'hidden', () => this._updateMessage(),
+ this);
+ Main.layoutManager.panelBox.connectObject('notify::visible',
+ () => this._updateMessage(), this);
+ Main.sessionMode.connectObject('updated',
+ () => this._onSessionModeUpdated(), this);
+ this._overviewShowingId = Main.overview.connect('showing', this._updateMessage.bind(this));
+ this._overviewHiddenId = Main.overview.connect('hidden', this._updateMessage.bind(this));
+ this._panelConnectionId = Main.layoutManager.panelBox.connect('notify::visible', this._updateMessage.bind(this));
+ this._sessionModeUpdatedId = Main.sessionMode.connect('updated', this._onSessionModeUpdated.bind(this));
+
+ this._updateMessage();
+ }
+
+ _onSessionModeUpdated() {
+ if (!Main.sessionMode.hasWindows)
+ this._messageInhibitedUntilIdle = false;
+ if (!Main.sessionMode.hasWindows)
+ this._messageInhibitedUntilIdle = false;
+
+ const dialog = Main.screenShield._dialog;
+ if (!Main.sessionMode.isGreeter && dialog && !this._screenShieldVisibleId) {
+ this._screenShieldVisibleId = dialog._clock.connect('notify::visible', this._updateMessage.bind(this));
+ this._screenShieldVisibleId = dialog._clock.connect('notify::visible',
+ this._updateMessage.bind(this));
+ this._screenShieldDestroyId = dialog._clock.connect('destroy', () => {
+ this._screenShieldVisibleId = 0;
+ this._screenShieldDestroyId = 0;
+ });
+ }
+ this._updateMessage();
+ this._updateMessage();
+ }
+
+ _stopWatchingForIdle() {
@ -206,11 +236,8 @@ index 00000000..a71b5925
+
+ const idleTimeout = this._settings.get_uint('idle-timeout');
+
+ this._idleTimeoutChangedId =
+ this._settings.connect('changed::idle-timeout',
+ this._onIdleTimeoutChanged.bind(this));
+ this._idleWatchId = this._idleMonitor.add_idle_watch(idleTimeout * 1000,
+ this._onUserIdle.bind(this));
+ this._idleTimeoutChangedId = this._settings.connect('changed::idle-timeout', this._onIdleTimeoutChanged.bind(this));
+ this._idleWatchId = this._idleMonitor.add_idle_watch(idleTimeout * 1000, this._onUserIdle.bind(this));
+ }
+
+ _updateMessage() {
@ -276,7 +303,7 @@ index 00000000..a71b5925
+ }
+
+ if (!this._message) {
+ this._message = new HeadsUpMessage(heading, body);
+ this._message = new HeadsUpMessage.HeadsUpMessage(heading, body);
+
+ this._message.connect('notify::allocation', this._adaptSessionForMessage.bind(this));
+ this._message.connect('clicked', this._onMessageClicked.bind(this));
@ -296,7 +323,7 @@ index 00000000..a71b5925
+
+ _onMessageClicked() {
+ if (!Main.sessionMode.hasWindows)
+ return;
+ return;
+
+ this._watchForIdle();
+ this._messageInhibitedUntilIdle = true;
@ -304,8 +331,9 @@ index 00000000..a71b5925
+ }
+
+ _dismissMessage() {
+ if (!this._message)
+ if (!this._message) {
+ return;
+ }
+
+ this._message.visible = false;
+ this._message.destroy();
@ -334,7 +362,7 @@ index 00000000..a71b5925
+ return;
+
+ if (!this._message || !this._message.visible) {
+ this._resetMessageTray();
+ this._resetMessageTray()
+ return;
+ }
+
@ -343,7 +371,7 @@ index 00000000..a71b5925
+
+ this._updateMessageTrayId = global.stage.connect('before-update', () => {
+ if (!this._messageTrayConstraint) {
+ this._messageTrayConstraint = new HeadsUpConstraint({primary: true});
+ this._messageTrayConstraint = new HeadsUpConstraint({ primary: true });
+
+ Main.layoutManager.panelBox.bind_property('visible',
+ this._messageTrayConstraint, 'active',
@ -394,7 +422,7 @@ index 00000000..a71b5925
+ return;
+
+ if (!this._message || !this._message.visible) {
+ this._resetLoginDialog();
+ this._resetLoginDialog()
+ return;
+ }
+
@ -404,12 +432,12 @@ index 00000000..a71b5925
+ return;
+
+ this._updateLoginDialogId = global.stage.connect('before-update', () => {
+ let messageHeight = this._message.y + this._message.height;
+ let messageHeight = this._message.y + this._message.height;
+ if (dialog._logoBin.visible)
+ messageHeight -= dialog._logoBin.height;
+
+ if (!this._logindDialogConstraint) {
+ this._loginDialogConstraint = new HeadsUpConstraint({primary: true});
+ this._loginDialogConstraint = new HeadsUpConstraint({ primary: true });
+ dialog.add_constraint(this._loginDialogConstraint);
+ }
+
@ -432,33 +460,30 @@ index 00000000..a71b5925
+ }
+ }
+}
+
+function init() {
+ return new Extension();
+}
diff --git a/extensions/heads-up-display/headsUpMessage.js b/extensions/heads-up-display/headsUpMessage.js
new file mode 100644
index 00000000..30298847
index 00000000..87a8c8ba
--- /dev/null
+++ b/extensions/heads-up-display/headsUpMessage.js
@@ -0,0 +1,166 @@
+// SPDX-FileCopyrightText: 2021 Ray Strode <rstrode@redhat.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+import Atk from 'gi://Atk';
+import Clutter from 'gi://Clutter';
+import GObject from 'gi://GObject';
+import St from 'gi://St';
@@ -0,0 +1,170 @@
+const { Atk, Clutter, GLib, GObject, Pango, St } = imports.gi;
+const Layout = imports.ui.layout;
+const Main = imports.ui.main;
+const Signals = imports.signals;
+
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+
+const HeadsUpMessageBodyLabel = GObject.registerClass({
+var HeadsUpMessageBodyLabel = GObject.registerClass({
+}, class HeadsUpMessageBodyLabel extends St.Label {
+ constructor(params) {
+ super(params);
+ _init(params) {
+ super._init(params);
+
+ this._widthCoverage = 0.75;
+ this._heightCoverage = 0.25;
+
+ global.display.connectObject('workareas-changed',
+ () => this._getWorkAreaAndMeasureLineHeight());
+ this._workAreasChangedId = global.display.connect('workareas-changed', this._getWorkAreaAndMeasureLineHeight.bind(this));
+ }
+
+ _getWorkAreaAndMeasureLineHeight() {
@ -476,12 +501,12 @@ index 00000000..30298847
+ this.clutter_text.line_wrap = true;
+ }
+
+ vfunc_parent_set() {
+ vfunc_parent_set(oldParent) {
+ this._getWorkAreaAndMeasureLineHeight();
+ }
+
+ vfunc_get_preferred_width(forHeight) {
+ const maxWidth = this._widthCoverage * this._workArea.width;
+ const maxWidth = this._widthCoverage * this._workArea.width
+
+ let [labelMinimumWidth, labelNaturalWidth] = super.vfunc_get_preferred_width(forHeight);
+
@ -505,134 +530,139 @@ index 00000000..30298847
+
+ return [labelMinimumHeight, labelNaturalHeight];
+ }
+
+ destroy() {
+ if (this._workAreasChangedId) {
+ global.display.disconnect(this._workAreasChangedId);
+ this._workAreasChangedId = 0;
+ }
+
+ super.destroy();
+ }
+});
+
+export const HeadsUpMessage = GObject.registerClass({
+var HeadsUpMessage = GObject.registerClass({
+}, class HeadsUpMessage extends St.Button {
+ constructor(heading, body) {
+ super({
+ _init(heading, body) {
+ super._init({
+ style_class: 'message',
+ accessible_role: Atk.Role.NOTIFICATION,
+ can_focus: false,
+ opacity: 0,
+ });
+
+ Main.layoutManager.addChrome(this, {affectsInputRegion: true});
+ Main.layoutManager.addChrome(this, { affectsInputRegion: true });
+
+ this.add_style_class_name('heads-up-display-message');
+
+ this.connect('destroy', () => this._onDestroy());
+ this._panelAllocationId = Main.layoutManager.panelBox.connect('notify::allocation', this._alignWithPanel.bind(this));
+ this.connect('notify::allocation', this._alignWithPanel.bind(this));
+
+ Main.layoutManager.panelBox.connectObject('notify::allocation',
+ () => this._alignWithPanel());
+ this.connect('notify::allocation',
+ () => this._alignWithPanel());
+
+ const contentsBox = new St.BoxLayout({
+ style_class: 'heads-up-message-content',
+ vertical: true,
+ x_align: Clutter.ActorAlign.CENTER,
+ });
+ this.add_child(contentsBox);
+
+ this._headingLabel = new St.Label({
+ style_class: 'heads-up-message-heading',
+ x_expand: true,
+ x_align: Clutter.ActorAlign.CENTER,
+ });
+ const contentsBox = new St.BoxLayout({ style_class: 'heads-up-message-content',
+ vertical: true,
+ x_align: Clutter.ActorAlign.CENTER });
+ this.add_actor(contentsBox);
+
+ this.headingLabel = new St.Label({ style_class: 'heads-up-message-heading',
+ x_expand: true,
+ x_align: Clutter.ActorAlign.CENTER });
+ this.setHeading(heading);
+ contentsBox.add_child(this._headingLabel);
+ contentsBox.add_actor(this.headingLabel);
+ this.contentsBox = contentsBox;
+
+ this._bodyLabel = new HeadsUpMessageBodyLabel({
+ style_class: 'heads-up-message-body',
+ x_expand: true,
+ y_expand: true,
+ });
+ contentsBox.add_child(this._bodyLabel);
+ this.bodyLabel = new HeadsUpMessageBodyLabel({ style_class: 'heads-up-message-body',
+ x_expand: true,
+ y_expand: true });
+ contentsBox.add_actor(this.bodyLabel);
+
+ this.setBody(body);
+ }
+
+ vfunc_parent_set() {
+ vfunc_parent_set(oldParent) {
+ this._alignWithPanel();
+ }
+
+ _alignWithPanel() {
+ if (this._beforeUpdateId)
+ if (this._afterUpdateId)
+ return;
+
+ this._beforeUpdateId = global.stage.connect('before-update', () => {
+ this._afterUpdateId = global.stage.connect('before-update', () => {
+ let x = Main.panel.x;
+ let y = Main.panel.y + Main.panel.height;
+
+ x += Main.panel.width / 2;
+ x -= this.width / 2;
+ x = Math.floor(x);
+ this.set_position(x, y);
+ this.set_position(x,y);
+ this.opacity = 255;
+
+ global.stage.disconnect(this._beforeUpdateId);
+ this._beforeUpdateId = 0;
+ global.stage.disconnect(this._afterUpdateId);
+ this._afterUpdateId = 0;
+ });
+ }
+
+ setHeading(text) {
+ if (text) {
+ const heading = text ? text.replace(/\n/g, ' ') : '';
+ this._headingLabel.text = heading;
+ this._headingLabel.visible = true;
+ this.headingLabel.text = heading;
+ this.headingLabel.visible = true;
+ } else {
+ this._headingLabel.text = text;
+ this._headingLabel.visible = false;
+ this.headingLabel.text = text;
+ this.headingLabel.visible = false;
+ }
+ }
+
+ setBody(text) {
+ this._bodyLabel.text = text;
+
+ if (text)
+ this._bodyLabel.visible = true;
+ else
+ this._bodyLabel.visible = false;
+ this.bodyLabel.text = text;
+ if (text) {
+ this.bodyLabel.visible = true;
+ } else {
+ this.bodyLabel.visible = false;
+ }
+ }
+
+ _onDestroy() {
+ if (this._beforeUpdateId) {
+ global.stage.disconnect(this._beforeUpdateId);
+ this._beforeUpdateId = 0;
+ destroy() {
+ if (this._panelAllocationId) {
+ Main.layoutManager.panelBox.disconnect(this._panelAllocationId);
+ this._panelAllocationId = 0;
+ }
+
+ if (this._afterUpdateId) {
+ global.stage.disconnect(this._afterUpdateId);
+ this._afterUpdateId = 0;
+ }
+
+ if (this.bodyLabel) {
+ this.bodyLabel.destroy();
+ this.bodyLabel = null;
+ }
+
+ super.destroy();
+ }
+});
diff --git a/extensions/heads-up-display/meson.build b/extensions/heads-up-display/meson.build
new file mode 100644
index 00000000..42ce222c
index 00000000..40c3de0a
--- /dev/null
+++ b/extensions/heads-up-display/meson.build
@@ -0,0 +1,13 @@
+# SPDX-FileCopyrightText: 2021 Ray Strode <rstrode@redhat.com>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
@@ -0,0 +1,8 @@
+extension_data += configure_file(
+ input: metadata_name + '.in',
+ 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/heads-up-display/metadata.json.in b/extensions/heads-up-display/metadata.json.in
new file mode 100644
index 00000000..01bcd4df
index 00000000..e7ab71aa
--- /dev/null
+++ b/extensions/heads-up-display/metadata.json.in
@@ -0,0 +1,12 @@
@@ -0,0 +1,11 @@
+{
+"extension-id": "@extension_id@",
+"uuid": "@uuid@",
+"settings-schema": "@gschemaname@",
+"gettext-domain": "@gettext_domain@",
+"name": "Heads-up Display Message",
+"description": "Add a message to be displayed on screen always above all windows and chrome.",
@ -643,16 +673,10 @@ index 00000000..01bcd4df
+}
diff --git a/extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml b/extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml
new file mode 100644
index 00000000..1e2119c8
index 00000000..ea1f3774
--- /dev/null
+++ b/extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml
@@ -0,0 +1,60 @@
+<!--
+SPDX-FileCopyrightText: 2021 Ray Strode <rstrode@redhat.com>
+
+SPDX-License-Identifier: GPL-2.0-or-later
+-->
+
@@ -0,0 +1,54 @@
+<schemalist gettext-domain="gnome-shell-extensions">
+ <schema id="org.gnome.shell.extensions.heads-up-display"
+ path="/org/gnome/shell/extensions/heads-up-display/">
@ -709,114 +733,210 @@ index 00000000..1e2119c8
+</schemalist>
diff --git a/extensions/heads-up-display/prefs.js b/extensions/heads-up-display/prefs.js
new file mode 100644
index 00000000..304c8813
index 00000000..a7106e07
--- /dev/null
+++ b/extensions/heads-up-display/prefs.js
@@ -0,0 +1,92 @@
+// SPDX-FileCopyrightText: 2021 Ray Strode <rstrode@redhat.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+import Adw from 'gi://Adw';
+import Gio from 'gi://Gio';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+
+import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
+
+class GeneralGroup extends Adw.PreferencesGroup {
+ static {
+ GObject.registerClass(this);
+ }
+
+ constructor(settings) {
+ super();
+
+ const actionGroup = new Gio.SimpleActionGroup();
+ this.insert_action_group('options', actionGroup);
+
+ actionGroup.add_action(settings.create_action('show-when-locked'));
+ actionGroup.add_action(settings.create_action('show-when-unlocking'));
+ actionGroup.add_action(settings.create_action('show-when-unlocked'));
+
+ this.add(new Adw.SwitchRow({
+ title: _('Show message when screen is locked'),
+ action_name: 'options.show-when-locked',
+ }));
+ this.add(new Adw.SwitchRow({
+ title: _('Show message on unlock screen'),
+ action_name: 'options.show-when-unlocking',
+ }));
+ this.add(new Adw.SwitchRow({
+ title: _('Show message when screen is unlocked'),
+ action_name: 'options.show-when-unlocked',
+ }));
+
+ const spinRow = new Adw.SpinRow({
+ title: _('Seconds after user goes idle before reshowing message'),
+ adjustment: new Gtk.Adjustment({
+ lower: 0,
+ upper: 2147483647,
+ step_increment: 1,
+ page_increment: 60,
+ page_size: 60,
+ }),
+ });
+ settings.bind('idle-timeout',
+ spinRow, 'value',
+ Gio.SettingsBindFlags.DEFAULT);
+ this.add(spinRow);
+ }
+}
@@ -0,0 +1,194 @@
+
+class MessageGroup extends Adw.PreferencesGroup {
+ static {
+ GObject.registerClass(this);
+ }
+/* Desktop Icons GNOME Shell extension
+ *
+ * Copyright (C) 2017 Carlos Soriano <csoriano@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ constructor(settings) {
+ super({
+ title: _('Message'),
+ });
+const { Gio, GObject, Gdk, Gtk } = imports.gi;
+const ExtensionUtils = imports.misc.extensionUtils;
+const Gettext = imports.gettext.domain('gnome-shell-extensions');
+const _ = Gettext.gettext;
+const N_ = e => e;
+const cssData = `
+ .no-border {
+ border: none;
+ }
+
+ .border {
+ border: 1px solid;
+ border-radius: 3px;
+ border-color: #b6b6b3;
+ box-shadow: inset 0 0 0 1px rgba(74, 144, 217, 0);
+ background-color: white;
+ }
+
+ .margins {
+ padding-left: 8px;
+ padding-right: 8px;
+ padding-bottom: 8px;
+ }
+
+ .contents {
+ padding: 20px;
+ }
+
+ .message-label {
+ font-weight: bold;
+ }
+`;
+
+var settings;
+
+function init() {
+ settings = ExtensionUtils.getSettings("org.gnome.shell.extensions.heads-up-display");
+ const cssProvider = new Gtk.CssProvider();
+ cssProvider.load_from_data(cssData);
+
+ const display = Gdk.Display.get_default();
+ Gtk.StyleContext.add_provider_for_display(display, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+}
+
+ const textView = new Gtk.TextView({
+ accepts_tab: false,
+ wrap_mode: Gtk.WrapMode.WORD,
+ top_margin: 6,
+ bottom_margin: 6,
+ left_margin: 6,
+ right_margin: 6,
+ vexpand: true,
+ });
+ textView.add_css_class('card');
+function buildPrefsWidget() {
+ ExtensionUtils.initTranslations();
+
+ const contents = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ spacing: 10,
+ visible: true,
+ });
+
+ contents.append(buildSwitch('show-when-locked', _("Show message when screen is locked")));
+ contents.append(buildSwitch('show-when-unlocking', _("Show message on unlock screen")));
+ contents.append(buildSwitch('show-when-unlocked', _("Show message when screen is unlocked")));
+ contents.append(buildSpinButton('idle-timeout', _("Seconds after user goes idle before reshowing message")));
+ contents.get_style_context().add_class("contents");
+
+ const outerMessageBox = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ spacing: 5,
+ visible: true,
+ });
+ contents.append(outerMessageBox);
+
+ const messageLabel = new Gtk.Label({
+ label: 'Message',
+ halign: Gtk.Align.START,
+ visible: true,
+ });
+ messageLabel.get_style_context().add_class("message-label");
+ outerMessageBox.append(messageLabel);
+
+ const innerMessageBox = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ spacing: 0,
+ visible: true,
+ });
+ innerMessageBox.get_style_context().add_class("border");
+ outerMessageBox.append(innerMessageBox);
+
+ innerMessageBox.append(buildEntry('message-heading', _("Message Heading")));
+ innerMessageBox.append(buildTextView('message-body', _("Message Body")));
+ return contents;
+}
+
+ settings.bind('message-body',
+ textView.get_buffer(), 'text',
+ Gio.SettingsBindFlags.DEFAULT);
+ this.add(textView);
+ }
+function buildTextView(key, labelText) {
+ const textView = new Gtk.TextView({
+ accepts_tab: false,
+ visible: true,
+ wrap_mode: Gtk.WrapMode.WORD,
+ });
+
+ settings.bind(key, textView.get_buffer(), 'text', Gio.SettingsBindFlags.DEFAULT);
+
+ const scrolledWindow = new Gtk.ScrolledWindow({
+ hexpand: true,
+ vexpand: true,
+ visible: true,
+ });
+ const styleContext = scrolledWindow.get_style_context();
+ styleContext.add_class("margins");
+
+ scrolledWindow.set_child(textView);
+ return scrolledWindow;
+}
+function buildEntry(key, labelText) {
+ const entry = new Gtk.Entry({
+ placeholder_text: labelText,
+ visible: true,
+ });
+ const styleContext = entry.get_style_context();
+ styleContext.add_class("no-border");
+ settings.bind(key, entry, 'text', Gio.SettingsBindFlags.DEFAULT);
+
+ entry.get_settings()['gtk-entry-select-on-focus'] = false;
+
+ return entry;
+}
+
+export default class HeadsUpDisplayPrefs extends ExtensionPreferences {
+ getPreferencesWidget() {
+ const page = new Adw.PreferencesPage();
+ page.add(new GeneralGroup(this.getSettings()));
+ page.add(new MessageGroup(this.getSettings()));
+ return page;
+ }
+function buildSpinButton(key, labelText) {
+ const hbox = new Gtk.Box({
+ orientation: Gtk.Orientation.HORIZONTAL,
+ spacing: 10,
+ visible: true,
+ });
+ const label = new Gtk.Label({
+ hexpand: true,
+ label: labelText,
+ visible: true,
+ xalign: 0,
+ });
+ const adjustment = new Gtk.Adjustment({
+ value: 0,
+ lower: 0,
+ upper: 2147483647,
+ step_increment: 1,
+ page_increment: 60,
+ page_size: 60,
+ });
+ const spinButton = new Gtk.SpinButton({
+ adjustment: adjustment,
+ climb_rate: 1.0,
+ digits: 0,
+ max_width_chars: 3,
+ visible: true,
+ width_chars: 3,
+ });
+ settings.bind(key, spinButton, 'value', Gio.SettingsBindFlags.DEFAULT);
+ hbox.append(label);
+ hbox.append(spinButton);
+ return hbox;
+}
+
+function buildSwitch(key, labelText) {
+ const hbox = new Gtk.Box({
+ orientation: Gtk.Orientation.HORIZONTAL,
+ spacing: 10,
+ visible: true,
+ });
+ const label = new Gtk.Label({
+ hexpand: true,
+ label: labelText,
+ visible: true,
+ xalign: 0,
+ });
+ const switcher = new Gtk.Switch({
+ active: settings.get_boolean(key),
+ });
+ settings.bind(key, switcher, 'active', Gio.SettingsBindFlags.DEFAULT);
+ hbox.append(label);
+ hbox.append(switcher);
+ return hbox;
+}
diff --git a/extensions/heads-up-display/stylesheet.css b/extensions/heads-up-display/stylesheet.css
new file mode 100644
index 00000000..a1a34e3f
index 00000000..93034469
--- /dev/null
+++ b/extensions/heads-up-display/stylesheet.css
@@ -0,0 +1,38 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Ray Strode <rstrode@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
@@ -0,0 +1,32 @@
+.heads-up-display-message {
+ background-color: rgba(0.24, 0.24, 0.24, 0.80);
+ border: 1px solid black;
@ -850,29 +970,17 @@ index 00000000..a1a34e3f
+ text-align: center;
+}
diff --git a/meson.build b/meson.build
index 0f12b451..da36032b 100644
index 582535c4..ecc86fc8 100644
--- a/meson.build
+++ b/meson.build
@@ -41,6 +41,7 @@ classic_extensions = [
@@ -39,6 +39,7 @@ classic_extensions = [
default_extensions = classic_extensions
default_extensions += [
'drive-menu',
+ 'heads-up-display',
'light-style',
'screenshot-window-sizer',
'status-icons',
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 447465a1..b7cb8a7c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,6 +6,7 @@ extensions/auto-move-windows/extension.js
extensions/auto-move-windows/org.gnome.shell.extensions.auto-move-windows.gschema.xml
extensions/auto-move-windows/prefs.js
extensions/drive-menu/extension.js
+extensions/heads-up-display/prefs.js
extensions/native-window-placement/extension.js
extensions/native-window-placement/org.gnome.shell.extensions.native-window-placement.gschema.xml
extensions/places-menu/extension.js
'windowsNavigator',
'workspace-indicator'
--
2.47.1
2.33.1

@ -0,0 +1,27 @@
From f0e4618bf0752aaf094d78b4c810ebda817ccaad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 2 Jun 2021 17:32:21 +0200
Subject: [PATCH] top-icons: Don't use wm_class as role
This prevents adding icons for multiple instances of the same app,
which may be desirable in some circumstances.
---
extensions/top-icons/extension.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/top-icons/extension.js b/extensions/top-icons/extension.js
index 79e2f42..3dfba46 100644
--- a/extensions/top-icons/extension.js
+++ b/extensions/top-icons/extension.js
@@ -63,7 +63,7 @@ class SysTray {
button.destroy();
});
- let role = wmClass || `${icon}`;
+ const role = `${icon}`;
Main.panel.addToStatusArea(role, button);
}
--
2.32.0

@ -0,0 +1,46 @@
From a31f4b6ca703faab25c306dc33056763642a83cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 30 Sep 2022 18:16:16 +0200
Subject: [PATCH] window-list: Explicitly dispose settings on destroy
This will not only disconnect the signal handler, but also remove
any bindings. This works around a crash that happens if a setting
that triggers the binding changes at the same time as a setting
that rebuilds the window list; in that case, the binding handler
runs after gjs has dropped its wrapper object, but before the
binding is removed automaticalled when the object is finalized.
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/416
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/243>
---
extensions/window-list/extension.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 89413818..91ee3e6b 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -842,8 +842,8 @@ class WindowList extends St.Widget {
this._dndWindow = null;
this._settings = ExtensionUtils.getSettings();
- this._groupingModeChangedId = this._settings.connect(
- 'changed::grouping-mode', this._groupingModeChanged.bind(this));
+ this._settings.connect('changed::grouping-mode',
+ () => this._groupingModeChanged());
this._grouped = undefined;
this._groupingModeChanged();
}
@@ -1112,7 +1112,7 @@ class WindowList extends St.Widget {
Main.xdndHandler.disconnect(this._dragBeginId);
Main.xdndHandler.disconnect(this._dragEndId);
- this._settings.disconnect(this._groupingModeChangedId);
+ this._settings.run_dispose();
let windows = global.get_window_actors();
for (let i = 0; i < windows.length; i++)
--
2.39.1

File diff suppressed because it is too large Load Diff

@ -0,0 +1,231 @@
From afa394114c57197e96f18e7942729634ece5d3c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 19 May 2021 16:46:59 +0200
Subject: [PATCH 1/2] desktop-icons: Revert "Use GTK-Theme CSS for selected
file-item and rubberband"
GtkStyleContext requires a (X11) display connection, which may not
be available with xwayland-on-demand. Better use some hardcoded
colors than crashing the session.
This reverts commit 8dc524aa4efd6a3fbad67480bd6c904b0c0c99d6.
---
extensions/desktop-icons/desktopIconsUtil.js | 11 ----------
extensions/desktop-icons/desktopManager.js | 12 -----------
extensions/desktop-icons/fileItem.js | 22 ++++----------------
extensions/desktop-icons/stylesheet.css | 9 ++++++++
4 files changed, 13 insertions(+), 41 deletions(-)
diff --git a/extensions/desktop-icons/desktopIconsUtil.js b/extensions/desktop-icons/desktopIconsUtil.js
index 696c945..57bedc1 100644
--- a/extensions/desktop-icons/desktopIconsUtil.js
+++ b/extensions/desktop-icons/desktopIconsUtil.js
@@ -16,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-const Gtk = imports.gi.Gtk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const ExtensionUtils = imports.misc.extensionUtils;
@@ -114,16 +113,6 @@ function getFileExtensionOffset(filename, isDirectory) {
return offset;
}
-function getGtkClassBackgroundColor(classname, state) {
- let widget = new Gtk.WidgetPath();
- widget.append_type(Gtk.Widget);
-
- let context = new Gtk.StyleContext();
- context.set_path(widget);
- context.add_class(classname);
- return context.get_background_color(state);
-}
-
// Reference the extension org.gnome.shell.extensions.drive-menu
function eject(mount) {
let unmountArgs = [
diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js
index 1aad8c6..10e3ce0 100644
--- a/extensions/desktop-icons/desktopManager.js
+++ b/extensions/desktop-icons/desktopManager.js
@@ -16,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-const Gtk = imports.gi.Gtk;
const Clutter = imports.gi.Clutter;
const GObject = imports.gi.GObject;
const Gio = imports.gi.Gio;
@@ -132,7 +131,6 @@ var DesktopManager = GObject.registerClass({
startRubberBand(x, y) {
this._rubberBandInitialX = x;
this._rubberBandInitialY = y;
- this._initRubberBandColor();
this._updateRubberBand(x, y);
this._rubberBand.show();
this._grabHelper.grab({ actor: global.stage });
@@ -235,16 +233,6 @@ var DesktopManager = GObject.registerClass({
this._desktopGrids = {};
}
- /**
- * Initialize rubberband color from the GTK rubberband class
- * */
- _initRubberBandColor() {
- let rgba = DesktopIconsUtil.getGtkClassBackgroundColor('rubberband', Gtk.StateFlags.NORMAL);
- let background_color =
- 'rgba(' + rgba.red * 255 + ', ' + rgba.green * 255 + ', ' + rgba.blue * 255 + ', 0.4)';
- this._rubberBand.set_style('background-color: ' + background_color);
- }
-
async _scanFiles() {
for (let [fileItem, fileItemHandler] of this._fileItemHandlers)
Object.values(fileItemHandler).forEach(id => fileItem.disconnect(id));
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
index 9987e7f..1e8ea89 100644
--- a/extensions/desktop-icons/fileItem.js
+++ b/extensions/desktop-icons/fileItem.js
@@ -16,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-const Gtk = imports.gi.Gtk;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
@@ -649,17 +648,6 @@ var FileItem = GObject.registerClass({
DBusUtils.openFileWithOtherApplication(this.file.get_path());
}
- _getSelectionStyle() {
- let rgba = DesktopIconsUtil.getGtkClassBackgroundColor('view', Gtk.StateFlags.SELECTED);
- let background_color =
- 'rgba(' + rgba.red * 255 + ', ' + rgba.green * 255 + ', ' + rgba.blue * 255 + ', 0.6)';
- let border_color =
- 'rgba(' + rgba.red * 255 + ', ' + rgba.green * 255 + ', ' + rgba.blue * 255 + ', 0.8)';
-
- return 'background-color: ' + background_color + ';' +
- 'border-color: ' + border_color + ';';
- }
-
get menu() {
return this._menu;
}
@@ -901,12 +889,10 @@ var FileItem = GObject.registerClass({
if (isSelected == this._isSelected)
return;
- if (isSelected) {
- this._container.set_style(this._getSelectionStyle());
- } else {
- this._container.set_style('background-color: transparent');
- this._container.set_style('border-color: transparent');
- }
+ if (isSelected)
+ this._container.add_style_pseudo_class('selected');
+ else
+ this._container.remove_style_pseudo_class('selected');
this._isSelected = isSelected;
}
diff --git a/extensions/desktop-icons/stylesheet.css b/extensions/desktop-icons/stylesheet.css
index 61b4ce8..4fd31c3 100644
--- a/extensions/desktop-icons/stylesheet.css
+++ b/extensions/desktop-icons/stylesheet.css
@@ -8,6 +8,15 @@
background-color: rgba(238, 238, 238, 0.2);
}
+.file-item:selected {
+ background-color: rgba(74, 144, 217, 0.6);
+ border-color: rgba(74, 144, 217, 0.8);
+}
+
+.rubber-band {
+ background-color: rgba(74, 144, 238, 0.4);
+}
+
.name-label {
text-shadow: 1px 1px black;
color: white;
--
2.32.0
From ca050d098240b3e757f172d2012f7d1b91db3ff6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 21 May 2021 00:50:52 +0200
Subject: [PATCH 2/2] desktop-icons: Port prefs to GTK4
... for compatibility with GNOME 40.
---
extensions/desktop-icons/prefs.js | 32 ++++++++++++++++++-------------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/extensions/desktop-icons/prefs.js b/extensions/desktop-icons/prefs.js
index 890bcdb..c390aa8 100644
--- a/extensions/desktop-icons/prefs.js
+++ b/extensions/desktop-icons/prefs.js
@@ -98,23 +98,29 @@ function get_schema(schema) {
function buildPrefsWidget() {
initTranslations();
- let frame = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, border_width: 10, spacing: 10 });
-
- frame.add(buildSelector('icon-size', _("Size for the desktop icons"), { 'small': _("Small"), 'standard': _("Standard"), 'large': _("Large") }));
- frame.add(buildSwitcher('show-home', _("Show the personal folder in the desktop")));
- frame.add(buildSwitcher('show-trash', _("Show the trash icon in the desktop")));
- frame.add(buildSwitcher('show-mount', _("Show mounted drives in the desktop")));
- frame.show_all();
+ let frame = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ margin_top: 10,
+ margin_bottom: 10,
+ margin_start: 10,
+ margin_end: 10,
+ spacing: 10,
+ });
+
+ frame.append(buildSelector('icon-size', _("Size for the desktop icons"), { 'small': _("Small"), 'standard': _("Standard"), 'large': _("Large") }));
+ frame.append(buildSwitcher('show-home', _("Show the personal folder in the desktop")));
+ frame.append(buildSwitcher('show-trash', _("Show the trash icon in the desktop")));
+ frame.append(buildSwitcher('show-mount', _("Show mounted drives in the desktop")));
return frame;
}
function buildSwitcher(key, labelText) {
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, spacing: 10 });
- let label = new Gtk.Label({ label: labelText, xalign: 0 });
+ let label = new Gtk.Label({ label: labelText, xalign: 0, hexpand: true });
let switcher = new Gtk.Switch({ active: settings.get_boolean(key) });
settings.bind(key, switcher, 'active', 3);
- hbox.pack_start(label, true, true, 0);
- hbox.add(switcher);
+ hbox.append(label);
+ hbox.append(switcher);
return hbox;
}
@@ -131,15 +137,15 @@ function buildSelector(key, labelText, elements) {
listStore.set (iter, [0, 1], [visibleText, val]);
}
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, spacing: 10 });
- let label = new Gtk.Label({ label: labelText, xalign: 0 });
+ let label = new Gtk.Label({ label: labelText, xalign: 0, hexpand: true });
let combo = new Gtk.ComboBox({model: listStore});
let rendererText = new Gtk.CellRendererText();
combo.pack_start (rendererText, false);
combo.add_attribute (rendererText, 'text', 0);
combo.set_id_column(1);
settings.bind(key, combo, 'active-id', 3);
- hbox.pack_start(label, true, true, 0);
- hbox.add(combo);
+ hbox.append(label);
+ hbox.append(combo);
return hbox;
}
--
2.32.0

@ -1,187 +0,0 @@
From 3de025618170bde16ab5e0bd7928ce387aa75350 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Thu, 28 Jan 2021 00:06:12 +0100
Subject: [PATCH 1/5] Add gesture-inhibitor extension
This extension may disable default GNOME Shell gestures.
---
extensions/gesture-inhibitor/extension.js | 79 +++++++++++++++++++
extensions/gesture-inhibitor/meson.build | 8 ++
extensions/gesture-inhibitor/metadata.json.in | 12 +++
...l.extensions.gesture-inhibitor.gschema.xml | 25 ++++++
meson.build | 7 +-
5 files changed, 130 insertions(+), 1 deletion(-)
create mode 100644 extensions/gesture-inhibitor/extension.js
create mode 100644 extensions/gesture-inhibitor/meson.build
create mode 100644 extensions/gesture-inhibitor/metadata.json.in
create mode 100644 extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
diff --git a/extensions/gesture-inhibitor/extension.js b/extensions/gesture-inhibitor/extension.js
new file mode 100644
index 00000000..872020ba
--- /dev/null
+++ b/extensions/gesture-inhibitor/extension.js
@@ -0,0 +1,79 @@
+// SPDX-FileCopyrightText: 2021 Carlos Garnacho <carlosg@gnome.org>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+
+import Clutter from 'gi://Clutter';
+import Gio from 'gi://Gio';
+import St from 'gi://St';
+
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+
+import {AppSwitchAction} from 'resource:///org/gnome/shell/ui/windowManager.js';
+import {EdgeDragAction} from 'resource:///org/gnome/shell/ui/edgeDragAction.js';
+
+import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
+
+export default class GestureInhibitorExtension extends Extension {
+ constructor(metadata) {
+ super(metadata);
+
+ let actions = global.stage.get_actions();
+
+ actions.forEach(a => {
+ if (a instanceof AppSwitchAction)
+ this._appSwitch = a;
+ else if (a instanceof EdgeDragAction &&
+ a._side === St.Side.BOTTOM)
+ this._showOsk = a;
+ else if (a instanceof EdgeDragAction &&
+ a._side === St.Side.TOP)
+ this._unfullscreen = a;
+ });
+
+ this._map = [
+ {setting: 'overview', action: Main.overview._swipeTracker},
+ {setting: 'app-switch', action: this._appSwitch},
+ {setting: 'show-osk', action: this._showOsk},
+ {setting: 'unfullscreen', action: this._unfullscreen},
+ {setting: 'workspace-switch', action: Main.wm._workspaceAnimation._swipeTracker},
+ ];
+
+ this._enabledDesc = Object.getOwnPropertyDescriptor(
+ Clutter.ActorMeta.prototype, 'enabled');
+ }
+
+ _overrideEnabledSetter(obj, set) {
+ if (!(obj instanceof Clutter.ActorMeta))
+ return;
+
+ const desc = set
+ ? {...this._enabledDesc, set}
+ : {...this._enabledDesc};
+ Object.defineProperty(obj, 'enabled', desc);
+ }
+
+ enable() {
+ const settings = this.getSettings();
+
+ this._map.forEach(m => {
+ settings.bind(m.setting, m.action, 'enabled',
+ Gio.SettingsBindFlags.DEFAULT);
+
+ this._overrideEnabledSetter(m.action, function (value) {
+ if (settings.get_boolean(m.setting)) {
+ // eslint-disable-next-line no-invalid-this
+ this.set_enabled(value);
+ }
+ });
+ });
+ }
+
+ disable() {
+ this._map.forEach(m => {
+ Gio.Settings.unbind(m.action, 'enabled');
+ this._overrideEnabledSetter(m.action);
+ m.action.enabled = true;
+ });
+ }
+}
diff --git a/extensions/gesture-inhibitor/meson.build b/extensions/gesture-inhibitor/meson.build
new file mode 100644
index 00000000..fdad5cc8
--- /dev/null
+++ b/extensions/gesture-inhibitor/meson.build
@@ -0,0 +1,8 @@
+extension_data += configure_file(
+ input: metadata_name + '.in',
+ output: metadata_name,
+ configuration: metadata_conf
+)
+
+# extension_sources += files('prefs.js')
+extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
diff --git a/extensions/gesture-inhibitor/metadata.json.in b/extensions/gesture-inhibitor/metadata.json.in
new file mode 100644
index 00000000..37d6a117
--- /dev/null
+++ b/extensions/gesture-inhibitor/metadata.json.in
@@ -0,0 +1,12 @@
+{
+ "uuid": "@uuid@",
+ "extension-id": "@extension_id@",
+ "settings-schema": "@gschemaname@",
+ "gettext-domain": "@gettext_domain@",
+ "name": "Gesture Inhibitor",
+ "description": "Makes touchscreen gestures optional.",
+ "shell-version": [ "@shell_current@" ],
+ "original-authors": [ "cgarnach@redhat.com" ],
+ "url": "@url@"
+}
+
diff --git a/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
new file mode 100644
index 00000000..b06d027a
--- /dev/null
+++ b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
@@ -0,0 +1,25 @@
+<schemalist>
+ <schema id="org.gnome.shell.extensions.gesture-inhibitor" path="/org/gnome/shell/extensions/gesture-inhibitor/">
+ <key name="show-osk" type="b">
+ <default>true</default>
+ <summary>Show OSK gesture</summary>
+ </key>
+ <key name="overview" type="b">
+ <default>true</default>
+ <summary>Show Overview gesture</summary>
+ </key>
+ <key name="app-switch" type="b">
+ <default>true</default>
+ <summary>Application switch gesture</summary>
+ </key>
+ <key name="workspace-switch" type="b">
+ <default>true</default>
+ <summary>Workspace switch gesture</summary>
+ </key>
+ <key name="unfullscreen" type="b">
+ <default>true</default>
+ <summary>Unfullscreen gesture</summary>
+ </key>
+ </schema>
+</schemalist>
+
diff --git a/meson.build b/meson.build
index 873da7bd..f21d0410 100644
--- a/meson.build
+++ b/meson.build
@@ -50,7 +50,12 @@ default_extensions += [
]
all_extensions = default_extensions
-all_extensions += ['auto-move-windows', 'native-window-placement', 'user-theme']
+all_extensions += [
+ 'auto-move-windows',
+ 'gesture-inhibitor',
+ 'native-window-placement',
+ 'user-theme',
+]
enabled_extensions = get_option('enable_extensions')
--
2.47.1

@ -1,479 +0,0 @@
From a30e0f7d6e93eb84f0864574b0da9816c0bbec83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 2 Dec 2021 19:39:50 +0100
Subject: [PATCH 2/5] Add classification-banner
---
extensions/classification-banner/extension.js | 163 +++++++++++++++
extensions/classification-banner/meson.build | 9 +
.../classification-banner/metadata.json.in | 11 +
...tensions.classification-banner.gschema.xml | 29 +++
extensions/classification-banner/prefs.js | 192 ++++++++++++++++++
.../classification-banner/stylesheet.css | 3 +
meson.build | 1 +
7 files changed, 408 insertions(+)
create mode 100644 extensions/classification-banner/extension.js
create mode 100644 extensions/classification-banner/meson.build
create mode 100644 extensions/classification-banner/metadata.json.in
create mode 100644 extensions/classification-banner/org.gnome.shell.extensions.classification-banner.gschema.xml
create mode 100644 extensions/classification-banner/prefs.js
create mode 100644 extensions/classification-banner/stylesheet.css
diff --git a/extensions/classification-banner/extension.js b/extensions/classification-banner/extension.js
new file mode 100644
index 00000000..32c7d794
--- /dev/null
+++ b/extensions/classification-banner/extension.js
@@ -0,0 +1,163 @@
+// SPDX-FileCopyrightText: 2021 Florian Müllner <fmuellner@gnome.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+import Clutter from 'gi://Clutter';
+import Cogl from 'gi://Cogl';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Shell from 'gi://Shell';
+import St from 'gi://St';
+
+import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
+
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+import {MonitorConstraint} from 'resource:///org/gnome/shell/ui/layout.js';
+
+class ClassificationBanner extends Clutter.Actor {
+ static {
+ GObject.registerClass(this);
+ }
+
+ #topBanner;
+ #bottomBanner;
+ #monitorConstraint;
+ #settings;
+
+ constructor(index, settings) {
+ const constraint = new MonitorConstraint({index});
+ super({
+ layout_manager: new Clutter.BinLayout(),
+ constraints: constraint,
+ });
+ this.#monitorConstraint = constraint;
+
+ Shell.util_set_hidden_from_pick(this, true);
+
+ this.#settings = settings;
+
+ this.#topBanner = new St.BoxLayout({
+ style_class: 'classification-banner',
+ x_expand: true,
+ y_expand: true,
+ y_align: Clutter.ActorAlign.START,
+ });
+ this.add_child(this.#topBanner);
+ this.#settings.bind('top-banner',
+ this.#topBanner, 'visible',
+ Gio.SettingsBindFlags.GET);
+
+ this.#bottomBanner = new St.BoxLayout({
+ style_class: 'classification-banner',
+ x_expand: true,
+ y_expand: true,
+ y_align: Clutter.ActorAlign.END,
+ });
+ this.add_child(this.#bottomBanner);
+ this.#settings.bind('bottom-banner',
+ this.#bottomBanner, 'visible',
+ Gio.SettingsBindFlags.GET);
+
+ for (const banner of [this.#topBanner, this.#bottomBanner]) {
+ const label = new St.Label({
+ style_class: 'classification-message',
+ x_align: Clutter.ActorAlign.CENTER,
+ x_expand: true,
+ });
+ banner.add_child(label);
+
+ this.#settings.bind('message',
+ label, 'text',
+ Gio.SettingsBindFlags.GET);
+ }
+
+ const hostLabel = new St.Label({
+ style_class: 'classification-system-info',
+ text: GLib.get_host_name(),
+ });
+ this.#topBanner.insert_child_at_index(hostLabel, 0);
+ this.#settings.bind('system-info',
+ hostLabel, 'visible',
+ Gio.SettingsBindFlags.GET);
+
+ const userLabel = new St.Label({
+ style_class: 'classification-system-info',
+ text: GLib.get_user_name(),
+ });
+ this.#topBanner.add_child(userLabel);
+ this.#settings.bind('system-info',
+ userLabel, 'visible',
+ Gio.SettingsBindFlags.GET);
+
+ global.display.connectObject('in-fullscreen-changed',
+ () => this.#updateMonitorConstraint(), this);
+ this.#updateMonitorConstraint();
+
+ this.#settings.connectObject(
+ 'changed::color', () => this.#updateStyles(),
+ 'changed::background-color', () => this.#updateStyles(),
+ this);
+ this.#updateStyles();
+ }
+
+ #getColorSetting(key) {
+ const str = this.#settings.get_string(key);
+ const [valid, color] = Cogl.Color.from_string(str);
+ if (!valid)
+ return '';
+ const {red, green, blue, alpha} = color;
+ return `${key}: rgba(${red},${green},${blue},${alpha / 255});`;
+ }
+
+ #updateMonitorConstraint() {
+ const {index} = this.#monitorConstraint;
+ this.#monitorConstraint.work_area =
+ !global.display.get_monitor_in_fullscreen(index);
+ }
+
+ #updateStyles() {
+ const bgStyle = this.#getColorSetting('background-color');
+ const fgStyle = this.#getColorSetting('color');
+ const style = `${bgStyle}${fgStyle}`;
+ this.#topBanner.set({style});
+ this.#bottomBanner.set({style});
+ }
+}
+
+export default class ClassificationBannerExtension extends Extension {
+ #banners = [];
+
+ #updateMonitors() {
+ const {monitors, panelBox, primaryIndex} = Main.layoutManager;
+ if (monitors.length !== this.#banners.length) {
+ this.#clearBanners();
+
+ const settings = this.getSettings();
+ for (let i = 0; i < monitors.length; i++) {
+ const banner = new ClassificationBanner(i, settings);
+ Main.uiGroup.add_child(banner);
+ this.#banners.push(banner);
+ }
+ }
+
+ const primaryBanner = this.#banners[primaryIndex];
+ if (primaryBanner)
+ Main.uiGroup.set_child_below_sibling(primaryBanner, panelBox);
+ }
+
+ #clearBanners() {
+ this.#banners.forEach(b => b.destroy());
+ this.#banners = [];
+ }
+
+ enable() {
+ Main.layoutManager.connectObject('monitors-changed',
+ () => this.#updateMonitors(), this);
+ this.#updateMonitors();
+ }
+
+ disable() {
+ Main.layoutManager.disconnectObject(this);
+ this.#clearBanners();
+ }
+}
diff --git a/extensions/classification-banner/meson.build b/extensions/classification-banner/meson.build
new file mode 100644
index 00000000..aa943741
--- /dev/null
+++ b/extensions/classification-banner/meson.build
@@ -0,0 +1,9 @@
+extension_data += configure_file(
+ input: metadata_name + '.in',
+ output: metadata_name,
+ configuration: metadata_conf
+)
+extension_data += files('stylesheet.css')
+
+extension_sources += files('prefs.js')
+extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
diff --git a/extensions/classification-banner/metadata.json.in b/extensions/classification-banner/metadata.json.in
new file mode 100644
index 00000000..f93b1a2d
--- /dev/null
+++ b/extensions/classification-banner/metadata.json.in
@@ -0,0 +1,11 @@
+{
+"extension-id": "@extension_id@",
+"uuid": "@uuid@",
+"settings-schema": "@gschemaname@",
+"gettext-domain": "@gettext_domain@",
+"name": "Classification Banner",
+"description": "Display classification level banner",
+"shell-version": [ "@shell_current@" ],
+"session-modes": [ "gdm", "unlock-dialog", "user" ],
+"url": "@url@"
+}
diff --git a/extensions/classification-banner/org.gnome.shell.extensions.classification-banner.gschema.xml b/extensions/classification-banner/org.gnome.shell.extensions.classification-banner.gschema.xml
new file mode 100644
index 00000000..0314ef60
--- /dev/null
+++ b/extensions/classification-banner/org.gnome.shell.extensions.classification-banner.gschema.xml
@@ -0,0 +1,29 @@
+<schemalist gettext-domain="gnome-shell-extensions">
+ <schema id="org.gnome.shell.extensions.classification-banner"
+ path="/org/gnome/shell/extensions/classification-banner/">
+ <key name="top-banner" type="b">
+ <default>true</default>
+ <summary>Show a banner at the top</summary>
+ </key>
+ <key name="bottom-banner" type="b">
+ <default>true</default>
+ <summary>Show a banner at the bottom</summary>
+ </key>
+ <key name="message" type="s">
+ <default>"UNCLASSIFIED"</default>
+ <summary>classification message</summary>
+ </key>
+ <key name="color" type="s">
+ <default>"#fff"</default>
+ <summary>text color</summary>
+ </key>
+ <key name="background-color" type="s">
+ <default>"rgba(0,122,51,0.75)"</default>
+ <summary>background color</summary>
+ </key>
+ <key name="system-info" type="b">
+ <default>false</default>
+ <summary>Include system info in top banner</summary>
+ </key>
+ </schema>
+</schemalist>
diff --git a/extensions/classification-banner/prefs.js b/extensions/classification-banner/prefs.js
new file mode 100644
index 00000000..dc73ddae
--- /dev/null
+++ b/extensions/classification-banner/prefs.js
@@ -0,0 +1,192 @@
+import Adw from 'gi://Adw';
+import Gdk from 'gi://Gdk';
+import Gio from 'gi://Gio';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+
+import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
+
+class GenericPrefs extends Adw.PreferencesGroup {
+ static {
+ GObject.registerClass(this);
+ }
+
+ #actionGroup = new Gio.SimpleActionGroup();
+ #settings;
+
+ constructor(settings) {
+ super();
+
+ this.#settings = settings;
+ this.insert_action_group('options', this.#actionGroup);
+
+ this.#actionGroup.add_action(settings.create_action('top-banner'));
+ this.#actionGroup.add_action(settings.create_action('bottom-banner'));
+ this.#actionGroup.add_action(settings.create_action('system-info'));
+
+ this.add(new Adw.SwitchRow({
+ title: _('Top Banner'),
+ action_name: 'options.top-banner',
+ }));
+
+ this.add(new Adw.SwitchRow({
+ title: _('Bottom Banner'),
+ action_name: 'options.bottom-banner',
+ }));
+
+ this.add(new Adw.SwitchRow({
+ title: _('System Info'),
+ action_name: 'options.system-info',
+ }));
+ }
+}
+
+class BannerPreset extends GObject.Object {
+ static [GObject.properties] = {
+ 'message': GObject.ParamSpec.string(
+ 'message', 'message', 'message',
+ GObject.ParamFlags.READWRITE,
+ null),
+ 'color': GObject.ParamSpec.string(
+ 'color', 'color', 'color',
+ GObject.ParamFlags.READWRITE,
+ null),
+ 'background-color': GObject.ParamSpec.string(
+ 'background-color', 'background-color', 'background-color',
+ GObject.ParamFlags.READWRITE,
+ null),
+ };
+
+ static {
+ GObject.registerClass(this);
+ }
+}
+
+class AppearancePrefs extends Adw.PreferencesGroup {
+ static {
+ GObject.registerClass(this);
+ }
+
+ #settings;
+
+ constructor(settings) {
+ super();
+
+ this.#settings = settings;
+
+ const model = new Gio.ListStore({item_type: BannerPreset.$gtype});
+ model.append(new BannerPreset({
+ message: 'UNCLASSIFIED',
+ color: '#fff',
+ background_color: 'rgba(0, 122, 51, 0.75)',
+ }));
+ model.append(new BannerPreset({
+ message: 'CONFIDENTIAL',
+ color: '#fff',
+ background_color: 'rgba(0, 51, 160, 0.75)',
+ }));
+ model.append(new BannerPreset({
+ message: 'SECRET',
+ color: '#fff',
+ background_color: 'rgba(200, 16, 46, 0.75)',
+ }));
+ model.append(new BannerPreset({
+ message: 'TOP SECRET',
+ color: '#fff',
+ background_color: 'rgba(255, 103, 31, 0.75)',
+ }));
+ model.append(new BannerPreset({
+ message: 'TOP SECRET//SCI',
+ color: '#000',
+ background_color: 'rgba(247, 234, 72, 0.75)',
+ }));
+
+ let row, activatableWidget;
+ row = this.#createPresetsRow(model);
+ row.connect('notify::selected-item', comboRow => {
+ const {message, color, backgroundColor} = comboRow.selected_item;
+ this.#settings.set_string('message', message);
+ this.#settings.set_string('color', color);
+ this.#settings.set_string('background-color', backgroundColor);
+ });
+ this.add(row);
+
+ activatableWidget = new Gtk.Entry({
+ valign: Gtk.Align.CENTER,
+ });
+ this.#settings.bind('message',
+ activatableWidget, 'text',
+ Gio.SettingsBindFlags.DEFAULT);
+ row = new Adw.ActionRow({title: _('Message'), activatableWidget});
+ row.add_suffix(activatableWidget);
+ this.add(row);
+
+ activatableWidget = this.#createColorButton('background-color', {
+ use_alpha: true,
+ });
+ row = new Adw.ActionRow({title: _('Background color'), activatableWidget});
+ row.add_suffix(activatableWidget);
+ this.add(row);
+
+ activatableWidget = this.#createColorButton('color');
+ row = new Adw.ActionRow({title: _('Text color'), activatableWidget});
+ row.add_suffix(activatableWidget);
+ this.add(row);
+ }
+
+ #createPresetsRow(model) {
+ const listFactory = new Gtk.SignalListItemFactory();
+ listFactory.connect('setup',
+ (f, item) => item.set_child(new Gtk.Label()));
+ listFactory.connect('bind', (f, listItem) => {
+ const {child, item} = listItem;
+
+ const provider = new Gtk.CssProvider();
+ provider.load_from_data(`* {
+ border-radius: 99px;
+ 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;
+ });
+
+ return new Adw.ComboRow({
+ title: _('Presets'),
+ model,
+ listFactory,
+ expression: Gtk.ConstantExpression.new_for_value(''),
+ });
+ }
+
+ #createColorButton(key, params = {}) {
+ const rgba = new Gdk.RGBA();
+ rgba.parse(this.#settings.get_string(key));
+
+ const button = new Gtk.ColorButton({
+ ...params,
+ rgba,
+ valign: Gtk.Align.CENTER,
+ });
+ this.#settings.connect(`changed::${key}`, () => {
+ const newRgba = new Gdk.RGBA();
+ newRgba.parse(this.#settings.get_string(key));
+ if (!newRgba.equal(button.rgba))
+ button.set({rgba: newRgba});
+ });
+ button.connect('notify::rgba',
+ () => this.#settings.set_string(key, button.rgba.to_string()));
+ return button;
+ }
+}
+
+export default class ClassificationPrefs extends ExtensionPreferences {
+ getPreferencesWidget() {
+ const page = new Adw.PreferencesPage();
+ page.add(new AppearancePrefs(this.getSettings()));
+ page.add(new GenericPrefs(this.getSettings()));
+ return page;
+ }
+}
diff --git a/extensions/classification-banner/stylesheet.css b/extensions/classification-banner/stylesheet.css
new file mode 100644
index 00000000..fb6a697e
--- /dev/null
+++ b/extensions/classification-banner/stylesheet.css
@@ -0,0 +1,3 @@
+.classification-system-info { padding: 0 24px; }
+.classification-message { font-weight: bold; }
+.classification-banner { font-size: 0.9em; }
diff --git a/meson.build b/meson.build
index f21d0410..0f12b451 100644
--- a/meson.build
+++ b/meson.build
@@ -52,6 +52,7 @@ default_extensions += [
all_extensions = default_extensions
all_extensions += [
'auto-move-windows',
+ 'classification-banner',
'gesture-inhibitor',
'native-window-placement',
'user-theme',
--
2.47.1

@ -1,719 +0,0 @@
From 9eb73513d7d31fd193e15c53f79c7e3a6aee71da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 12 Jan 2023 19:43:52 +0100
Subject: [PATCH 4/5] Add custom-menu extension
---
extensions/custom-menu/config.js | 445 ++++++++++++++++++++++++
extensions/custom-menu/extension.js | 201 +++++++++++
extensions/custom-menu/meson.build | 7 +
extensions/custom-menu/metadata.json.in | 10 +
meson.build | 1 +
5 files changed, 664 insertions(+)
create mode 100644 extensions/custom-menu/config.js
create mode 100644 extensions/custom-menu/extension.js
create mode 100644 extensions/custom-menu/meson.build
create mode 100644 extensions/custom-menu/metadata.json.in
diff --git a/extensions/custom-menu/config.js b/extensions/custom-menu/config.js
new file mode 100644
index 00000000..d08e3201
--- /dev/null
+++ b/extensions/custom-menu/config.js
@@ -0,0 +1,445 @@
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import Json from 'gi://Json';
+
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
+
+import {getLogger} from './extension.js';
+
+class Entry {
+ constructor(prop) {
+ this.type = prop.type;
+ this.title = prop.title || "";
+ this.__vars = prop.__vars || [];
+ this.updateEnv(prop);
+ }
+
+ setTitle(text) {
+ this.item.label.get_clutter_text().set_text(text);
+ }
+
+ updateEnv(prop) {
+ this.__env = {}
+ if (!this.__vars) return;
+ for (let i in this.__vars) {
+ let v = this.__vars[i];
+ this.__env[v] = prop[v] ? String(prop[v]) : "";
+ }
+ }
+
+ // the pulse function should be read as "a pulse arrives"
+ pulse() {
+ }
+
+ _try_destroy() {
+ try {
+ if (this.item && this.item.destroy) {
+ this.item.destroy();
+ }
+ } catch(e) { /* Ignore all errors during destory*/ }
+ }
+}
+
+class DerivedEntry {
+ constructor(prop) {
+ if (!prop.base) {
+ throw new Error("Base entry not specified in type definition.");
+ }
+ this.base = prop.base;
+ this.vars = prop.vars || [];
+ delete prop.base;
+ delete prop.vars;
+ this.prop = prop;
+ }
+
+ createInstance(addit_prop) {
+ let cls = type_map[this.base];
+ if (!cls) {
+ throw new Error("Bad base class.");
+ }
+ if (cls.createInstance) {
+ throw new Error("Not allowed to derive from dervied types");
+ }
+ for (let rp in this.prop) {
+ addit_prop[rp] = this.prop[rp];
+ }
+ addit_prop.__vars = this.vars;
+ let instance = new cls(addit_prop);
+ return instance;
+ }
+}
+
+let __pipeOpenQueue = [];
+
+/* callback: function (stdout, stderr, exit_status) { } */
+function pipeOpen(cmdline, env, callback) {
+ if (cmdline === undefined || callback === undefined) {
+ return false;
+ }
+ realPipeOpen(cmdline, env, callback);
+ return true;
+} /**/
+
+function realPipeOpen(cmdline, env, callback) {
+ let user_cb = callback;
+ let proc;
+
+ function wait_cb(_, _res) {
+ let stdout_pipe = proc.get_stdout_pipe();
+ let stderr_pipe = proc.get_stderr_pipe();
+ let stdout_content;
+ let stderr_content;
+
+ // Only the first GLib.MAXINT16 characters are fetched for optimization.
+ stdout_pipe.read_bytes_async(GLib.MAXINT16, 0, null, function(osrc, ores) {
+ const decoder = new TextDecoder();
+ stdout_content = decoder.decode(stdout_pipe.read_bytes_finish(ores).get_data());
+ stdout_pipe.close(null);
+ stderr_pipe.read_bytes_async(GLib.MAXINT16, 0, null, function(esrc, eres) {
+ stderr_content = decoder.decode(stderr_pipe.read_bytes_finish(eres).get_data());
+ stderr_pipe.close(null);
+ user_cb(stdout_content, stderr_content, proc.get_exit_status());
+ });
+ });
+ }
+
+ if (user_cb) {
+ let _pipedLauncher = new Gio.SubprocessLauncher({
+ flags:
+ Gio.SubprocessFlags.STDERR_PIPE |
+ Gio.SubprocessFlags.STDOUT_PIPE
+ });
+ for (let key in env) {
+ _pipedLauncher.setenv(key, env[key], true);
+ }
+ proc = _pipedLauncher.spawnv(['bash', '-c', cmdline]);
+ proc.wait_async(null, wait_cb);
+ } else {
+ // Detached launcher is used to spawn commands that we are not concerned about its result.
+ let _detacLauncher = new Gio.SubprocessLauncher();
+ for (let key in env) {
+ _detacLauncher.setenv(key, env[key], true);
+ }
+ proc = _detacLauncher.spawnv(['bash', '-c', cmdline]);
+ }
+ getLogger().info("Spawned " + cmdline);
+ return proc.get_identifier();
+}
+
+function _generalSpawn(command, env, title) {
+ title = title || "Process";
+ pipeOpen(command, env, function(stdout, stderr, exit_status) {
+ if (exit_status != 0) {
+ log
+ getLogger().warning(stderr);
+ getLogger().notify("proc", title + " exited with status " + exit_status, stderr);
+ }
+ });
+}
+
+// Detect menu toggle on startup
+function _toggleDetect(command, env, object) {
+ pipeOpen(command, env, function(stdout, stderr, exit_status) {
+ if (exit_status == 0) {
+ object.item.setToggleState(true);
+ }
+ });
+} /**/
+
+function quoteShellArg(arg) {
+ arg = arg.replace(/'/g, "'\"'\"'");
+ return "'" + arg + "'";
+}
+
+/**
+ * This cache is used to reduce detector cost.
+ * Each time creating an item, it check if the result of this detector is cached,
+ * which prevent the togglers from running detector on each creation.
+ * This is useful especially in search mode.
+ */
+let _toggler_state_cache = { };
+
+class TogglerEntry extends Entry {
+ constructor(prop) {
+ super(prop);
+ this.command_on = prop.command_on || "";
+ this.command_off = prop.command_off || "";
+ this.detector = prop.detector || "";
+ this.auto_on = prop.auto_on || false;
+ this.notify_when = prop.notify_when || [];
+ // if the switch is manually turned off, auto_on is disabled.
+ this._manually_switched_off = false;
+ this.pulse(); // load initial state
+ }
+
+ createItem() {
+ this._try_destroy();
+ this.item = new PopupMenu.PopupSwitchMenuItem(this.title, false);
+ this.item.label.get_clutter_text().set_use_markup(true);
+ this.item.connect('toggled', this._onManuallyToggled.bind(this));
+ this._loadState();
+ _toggleDetect(this.detector, this.__env, this);
+ return this.item;
+ }
+
+ _onManuallyToggled(_, state) {
+ // when switched on again, this flag will get cleared.
+ this._manually_switched_off = !state;
+ this._storeState(state);
+ this._onToggled(state);
+ }
+
+ _onToggled(state) {
+ if (state) {
+ _generalSpawn(this.command_on, this.__env, this.title);
+ } else {
+ _generalSpawn(this.command_off, this.__env, this.title);
+ }
+ }
+
+ _detect(callback) {
+ // abort detecting if detector is an empty string
+ if (!this.detector) {
+ return;
+ }
+ pipeOpen(this.detector, this.__env, function(out) {
+ out = String(out);
+ callback(!Boolean(out.match(/^\s*$/)));
+ });
+ }
+
+ // compare the new state with cached state notify when state is different
+ compareState(new_state) {
+ let old_state = _toggler_state_cache[this.detector];
+ if (old_state === undefined) return;
+ if (old_state == new_state) return;
+
+ if (this.notify_when.indexOf(new_state ? "on" : "off") >= 0) {
+ let not_str = this.title + (new_state ? " started." : " stopped.");
+ if (!new_state && this.auto_on) {
+ not_str += " Attempt to restart it now.";
+ }
+ getLogger().notify("state", not_str);
+ }
+ }
+
+ _storeState(state) {
+ let hash = JSON.stringify({ env: this.__env, detector: this.detector });
+ _toggler_state_cache[hash] = state;
+ }
+
+ _loadState() {
+ let hash = JSON.stringify({ env: this.__env, detector: this.detector });
+ let state = _toggler_state_cache[hash];
+ if (state !== undefined) {
+ this.item.setToggleState(state); // doesn't emit 'toggled'
+ }
+ }
+
+ pulse() {
+ this._detect(state => {
+ this.compareState(state);
+ this._storeState(state);
+ this._loadState();
+ if (!state && !this._manually_switched_off && this.auto_on) {
+ // do not call setToggleState here, because command_on may fail
+ this._onToggled(this.item, true);
+ }
+ });
+ }
+
+ perform() {
+ this.item.toggle();
+ }
+}
+
+class LauncherEntry extends Entry {
+ constructor(prop) {
+ super(prop);
+ this.command = prop.command || "";
+ }
+
+ createItem() {
+ this._try_destroy();
+ this.item = new PopupMenu.PopupMenuItem(this.title);
+ this.item.label.get_clutter_text().set_use_markup(true);
+ this.item.connect('activate', this._onClicked.bind(this));
+ return this.item;
+ }
+
+ _onClicked(_) {
+ _generalSpawn(this.command, this.__env, this.title);
+ }
+
+ perform() {
+ this.item.emit('activate');
+ }
+}
+
+class SubMenuEntry extends Entry {
+ constructor(prop) {
+ super(prop);
+
+ if (prop.entries == undefined) {
+ throw new Error("Expected entries provided in submenu entry.");
+ }
+ this.entries = [];
+ for (let i in prop.entries) {
+ let entry_prop = prop.entries[i];
+ let entry = createEntry(entry_prop);
+ this.entries.push(entry);
+ }
+ }
+
+ createItem() {
+ this._try_destroy();
+ this.item = new PopupMenu.PopupSubMenuMenuItem(this.title);
+ this.item.label.get_clutter_text().set_use_markup(true);
+ for (let i in this.entries) {
+ let entry = this.entries[i];
+ this.item.menu.addMenuItem(entry.createItem());
+ }
+ return this.item;
+ }
+
+ pulse() {
+ for (let i in this.entries) {
+ let entry = this.entries[i];
+ entry.pulse();
+ }
+ }
+}
+
+class SeparatorEntry extends Entry {
+ createItem() {
+ this._try_destroy();
+ this.item = new PopupMenu.PopupSeparatorMenuItem(this.title);
+ this.item.label.get_clutter_text().set_use_markup(true);
+ return this.item;
+ }
+}
+
+let type_map = {};
+
+////////////////////////////////////////////////////////////////////////////////
+// Config Loader loads config from JSON file.
+
+// convert Json Nodes (GLib based) to native javascript value.
+function convertJson(node) {
+ if (node.get_node_type() == Json.NodeType.VALUE) {
+ return node.get_value();
+ }
+ if (node.get_node_type() == Json.NodeType.OBJECT) {
+ let obj = {}
+ node.get_object().foreach_member(function(_, k, v_n) {
+ obj[k] = convertJson(v_n);
+ });
+ return obj;
+ }
+ if (node.get_node_type() == Json.NodeType.ARRAY) {
+ let arr = []
+ node.get_array().foreach_element(function(_, i, elem) {
+ arr.push(convertJson(elem));
+ });
+ return arr;
+ }
+ return null;
+}
+
+//
+function createEntry(entry_prop) {
+ if (!entry_prop.type) {
+ throw new Error("No type specified in entry.");
+ }
+ let cls = type_map[entry_prop.type];
+ if (!cls) {
+ throw new Error("Incorrect type '" + entry_prop.type + "'");
+ } else if (cls.createInstance) {
+ return cls.createInstance(entry_prop);
+ }
+ return new cls(entry_prop);
+}
+
+export class Loader {
+ constructor(filename) {
+ if (filename) {
+ this.loadConfig(filename);
+ }
+ }
+
+ loadConfig(filename) {
+ // reset type_map everytime load the config
+ type_map = {
+ launcher: LauncherEntry,
+ toggler: TogglerEntry,
+ submenu: SubMenuEntry,
+ separator: SeparatorEntry
+ };
+
+ type_map.systemd = new DerivedEntry({
+ base: 'toggler',
+ vars: ['unit'],
+ command_on: "pkexec systemctl start ${unit}",
+ command_off: "pkexec systemctl stop ${unit}",
+ detector: "systemctl status ${unit} | grep Active:\\\\s\\*activ[ei]",
+ });
+
+ type_map.tmux = new DerivedEntry({
+ base: 'toggler',
+ vars: ['command', 'session'],
+ command_on: 'tmux new -d -s ${session} bash -c "${command}"',
+ command_off: 'tmux kill-session -t ${session}',
+ detector: 'tmux has -t "${session}" 2>/dev/null && echo yes',
+ });
+
+ /*
+ * Refer to README file for detailed config file format.
+ */
+ this.entries = []; // CAUTION: remove all entries.
+
+ let config_parser = new Json.Parser();
+ config_parser.load_from_file(filename);
+ let conf = convertJson(config_parser.get_root());
+ if (conf.entries == undefined) {
+ throw new Error("Key 'entries' not found.");
+ }
+ if (conf.deftype) {
+ for (let tname in conf.deftype) {
+ if (type_map[tname]) {
+ throw new Error("Type \""+tname+"\" duplicated.");
+ }
+ type_map[tname] = new DerivedEntry(conf.deftype[tname]);
+ }
+ }
+
+ for (let conf_i in conf.entries) {
+ let entry_prop = conf.entries[conf_i];
+ this.entries.push(createEntry(entry_prop));
+ }
+ }
+
+ saveDefaultConfig(filename) {
+ // Write default config
+ const PERMISSIONS_MODE = 0o640;
+ const jsonString = JSON.stringify({
+ "_homepage_": "https://github.com/andreabenini/gnome-plugin.custom-menu-panel",
+ "_examples_": "https://github.com/andreabenini/gnome-plugin.custom-menu-panel/tree/main/examples",
+ "entries": [ {
+ "type": "launcher",
+ "title": "Edit menu",
+ "command": "gedit $HOME/.entries.json"
+ } ]
+ }, null, 4);
+ let fileConfig = Gio.File.new_for_path(filename);
+ if (GLib.mkdir_with_parents(fileConfig.get_parent().get_path(), PERMISSIONS_MODE) === 0) {
+ fileConfig.replace_contents(jsonString, null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null);
+ }
+ // Try to load newly saved file
+ try {
+ this.loadConfig(filename);
+ } catch(e) {
+ Main.notify(_('Cannot create and load file: '+filename));
+ }
+ }
+}
diff --git a/extensions/custom-menu/extension.js b/extensions/custom-menu/extension.js
new file mode 100644
index 00000000..9edbc548
--- /dev/null
+++ b/extensions/custom-menu/extension.js
@@ -0,0 +1,201 @@
+/* extension.js
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+/**
+ * @author Ben
+ * @see https://github.com/andreabenini/gnome-plugin.custom-menu-panel
+ */
+
+const CONFIGURATION_FILE = '/.entries.json';
+
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import St from 'gi://St';
+
+import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
+
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+import * as BackgroundMenu from 'resource:///org/gnome/shell/ui/backgroundMenu.js';
+import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
+import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
+
+import * as Config from './config.js';
+
+const LOGGER_INFO = 0;
+const LOGGER_WARNING = 1;
+const LOGGER_ERROR = 2;
+
+const {BackgroundMenu: OriginalBackgroundMenu} = BackgroundMenu;
+
+
+class CustomMenu extends PopupMenu.PopupMenu {
+ constructor(sourceActor) {
+ super(sourceActor, 0.0, St.Side.TOP, 0);
+
+ this._loadSetup();
+ }
+
+ /**
+ * LOAD Program settings from .entries.json file
+ */
+ _loadSetup() {
+ this.removeAll();
+ // Loading configuration from file
+ this.configLoader = new Config.Loader();
+ try {
+ this.configLoader.loadConfig(GLib.get_home_dir() + CONFIGURATION_FILE); // $HOME/.entries.json
+ } catch(e) {
+ this.configLoader.saveDefaultConfig(GLib.get_home_dir() + CONFIGURATION_FILE); // create default entries
+ }
+ // Build the menu
+ let i = 0;
+ for (let i in this.configLoader.entries) {
+ let item = this.configLoader.entries[i].createItem();
+ this.addMenuItem(item);
+ }
+ } /**/
+}
+
+class CustomBackgroundMenu extends CustomMenu {
+ constructor(layoutManager) {
+ super(layoutManager.dummyCursor);
+
+ this.actor.add_style_class_name('background-menu');
+
+ layoutManager.uiGroup.add_actor(this.actor);
+ this.actor.hide();
+
+ this.connect('open-state-changed', (menu, open) => {
+ if (open)
+ this._updateMaxHeight();
+ });
+ }
+
+ _updateMaxHeight() {
+ const monitor = Main.layoutManager.findMonitorForActor(this.actor);
+ const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index);
+ const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage);
+ const vMargins = this.actor.margin_top + this.actor.margin_bottom;
+ const {y: offsetY} = this.sourceActor;
+
+ const maxHeight = Math.round((monitor.height - offsetY - vMargins) / scaleFactor);
+ this.actor.style = `max-height: ${maxHeight}px;`;
+ }
+}
+
+const Indicator = GObject.registerClass(
+ class Indicator extends PanelMenu.Button {
+ _init() {
+ super._init(0.0, _('Custom Menu Panel Indicator'), true);
+ this.add_child(new St.Icon({
+ icon_name: 'view-list-bullet-symbolic',
+ style_class: 'system-status-icon',
+ }));
+
+ this.setMenu(new CustomMenu(this));
+ }
+ }
+); /**/
+
+
+class Logger {
+ constructor(log_file) {
+ this._log_file = log_file;
+ // initailize log_backend
+ if (!log_file) {
+ this._initEmptyLog();
+ } else if(log_file == "gnome-shell") {
+ this._initGnomeLog();
+ } else {
+ this._initFileLog();
+ }
+ this.level = LOGGER_WARNING;
+ this.info = function(t) {
+ if (this.level <= LOGGER_INFO) {
+ this.log(t);
+ }
+ };
+ this.warning = function(t) {
+ if (this.level <= LOGGER_WARNING) {
+ this.log(t);
+ }
+ };
+ this.error = function(t) {
+ if (this.level <= LOGGER_ERROR) {
+ this.log(t);
+ }
+ };
+ }
+
+ _initEmptyLog() {
+ this.log = function(_) { };
+ }
+
+ _initGnomeLog() {
+ this.log = function(s) {
+ global.log("custom-menu-panel> " + s);
+ };
+ }
+
+ _initFileLog() {
+ this.log = function(s) {
+ // all operations are synchronous: any needs to optimize?
+ if (!this._output_file || !this._output_file.query_exists(null) || !this._fstream || this._fstream.is_closed()) {
+ this._output_file = Gio.File.new_for_path(this._log_file);
+ this._fstream = this._output_file.append_to(Gio.FileCreateFlags.NONE, null);
+ if (!this._fstream instanceof Gio.FileIOStream) {
+ this._initGnomeLog();
+ this.log("IOError: Failed to append to " + this._log_file + " [Gio.IOErrorEnum:" + this._fstream + "]");
+ return;
+ }
+ }
+ this._fstream.write(String(new Date())+" "+s+"\n", null);
+ this._fstream.flush(null);
+ }
+ }
+
+ notify(t, str, details) {
+ this.ncond = this.ncond || ['proc', 'ext', 'state'];
+ if (this.ncond.indexOf(t) < 0) {
+ return;
+ }
+ Main.notify(str, details || "");
+ }
+}
+
+// lazy-evaluation
+let logger = null;
+export function getLogger() {
+ if (logger === null) {
+ logger = new Logger("gnome-shell");
+ }
+ return logger;
+} /**/
+
+export default class CustomMenuExtension extends Extension {
+ enable() {
+ BackgroundMenu.BackgroundMenu = CustomBackgroundMenu;
+ Main.layoutManager._updateBackgrounds();
+ }
+
+ disable() {
+ BackgroundMenu.BackgroundMenu = OriginalBackgroundMenu;
+ Main.layoutManager._updateBackgrounds();
+ }
+} /**/
diff --git a/extensions/custom-menu/meson.build b/extensions/custom-menu/meson.build
new file mode 100644
index 00000000..92450963
--- /dev/null
+++ b/extensions/custom-menu/meson.build
@@ -0,0 +1,7 @@
+extension_data += configure_file(
+ input: metadata_name + '.in',
+ output: metadata_name,
+ configuration: metadata_conf
+)
+
+extension_sources += files('config.js')
diff --git a/extensions/custom-menu/metadata.json.in b/extensions/custom-menu/metadata.json.in
new file mode 100644
index 00000000..054f639b
--- /dev/null
+++ b/extensions/custom-menu/metadata.json.in
@@ -0,0 +1,10 @@
+{
+"extension-id": "@extension_id@",
+"uuid": "@uuid@",
+"settings-schema": "@gschemaname@",
+"gettext-domain": "@gettext_domain@",
+"name": "Custom menu",
+"description": "Quick custom menu for launching your favorite applications",
+"shell-version": [ "@shell_current@" ],
+"url": "@url@"
+}
diff --git a/meson.build b/meson.build
index da36032b..175cc73f 100644
--- a/meson.build
+++ b/meson.build
@@ -54,6 +54,7 @@ all_extensions = default_extensions
all_extensions += [
'auto-move-windows',
'classification-banner',
+ 'custom-menu',
'gesture-inhibitor',
'native-window-placement',
'user-theme',
--
2.47.1

@ -1,72 +0,0 @@
From d0f2273765ab61e55c5cf10e7283a545fcafa947 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 22 Aug 2024 13:24:20 +0200
Subject: [PATCH] Add stub desktop-icons extension
---
extensions/desktop-icons/extension.js | 5 +++++
extensions/desktop-icons/meson.build | 9 +++++++++
extensions/desktop-icons/metadata.json.in | 10 ++++++++++
meson.build | 1 +
4 files changed, 25 insertions(+)
create mode 100644 extensions/desktop-icons/extension.js
create mode 100644 extensions/desktop-icons/meson.build
create mode 100644 extensions/desktop-icons/metadata.json.in
diff --git a/extensions/desktop-icons/extension.js b/extensions/desktop-icons/extension.js
new file mode 100644
index 00000000..bbc96ef2
--- /dev/null
+++ b/extensions/desktop-icons/extension.js
@@ -0,0 +1,5 @@
+// SPDX-FileCopyrightText: 2024 Florian Müllner <fmuellner@gnome.org>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+export {Extension as default} from 'resource:///org/gnome/shell/extensions/extension.js';
diff --git a/extensions/desktop-icons/meson.build b/extensions/desktop-icons/meson.build
new file mode 100644
index 00000000..7b28a2ef
--- /dev/null
+++ b/extensions/desktop-icons/meson.build
@@ -0,0 +1,9 @@
+# SPDX-FileCopyrightText: 2017 Florian Müllner <fmuellner@gnome.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+extension_data += configure_file(
+ input: metadata_name + '.in',
+ output: metadata_name,
+ configuration: metadata_conf
+)
diff --git a/extensions/desktop-icons/metadata.json.in b/extensions/desktop-icons/metadata.json.in
new file mode 100644
index 00000000..78a55abb
--- /dev/null
+++ b/extensions/desktop-icons/metadata.json.in
@@ -0,0 +1,10 @@
+{
+"extension-id": "@extension_id@",
+"uuid": "@uuid@",
+"settings-schema": "@gschemaname@",
+"gettext-domain": "@gettext_domain@",
+"name": "Desktop Icons",
+"description": "Show icons on the desktop",
+"shell-version": [ "@shell_current@" ],
+"url": "@url@"
+}
diff --git a/meson.build b/meson.build
index b915b68c..63a7432e 100644
--- a/meson.build
+++ b/meson.build
@@ -40,6 +40,7 @@ classic_extensions = [
default_extensions = classic_extensions
default_extensions += [
+ 'desktop-icons',
'drive-menu',
'heads-up-display',
'light-style',
--
2.45.2

@ -0,0 +1,158 @@
From 1692d4a91d95fecd5642b0c92bc2c5b0dbcb4184 Mon Sep 17 00:00:00 2001
From: Neal Gompa <ngompa@fedoraproject.org>
Date: Fri, 29 Oct 2021 09:37:33 -0400
Subject: [PATCH] classic: Install the session for Wayland and ship override
sessions
The regular GNOME session ships with three options:
* GNOME
* GNOME on Wayland (available when GDM starts in X11)
* GNOME on Xorg (available when GDM starts in Wayland)
The main GNOME session is set up so it works to match how GDM starts,
so GNOME is on Wayland if GDM is (or GNOME is on X11 if GDM is).
For GNOME Classic, we are missing this setup, so port this behavior
over from the GNOME session setup.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/195>
---
data/gnome-classic-wayland.desktop.in | 8 ++++++
data/gnome-classic-xorg.desktop.in | 8 ++++++
data/meson.build | 40 +++++++++++++++++++++------
meson.build | 5 ++++
meson/session-post-install.py | 20 ++++++++++++++
5 files changed, 72 insertions(+), 9 deletions(-)
create mode 100644 data/gnome-classic-wayland.desktop.in
create mode 100644 data/gnome-classic-xorg.desktop.in
create mode 100755 meson/session-post-install.py
diff --git a/data/gnome-classic-wayland.desktop.in b/data/gnome-classic-wayland.desktop.in
new file mode 100644
index 00000000..7287c689
--- /dev/null
+++ b/data/gnome-classic-wayland.desktop.in
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Name=GNOME Classic on Wayland
+Comment=This session logs you into GNOME Classic
+Exec=env GNOME_SHELL_SESSION_MODE=classic gnome-session
+TryExec=gnome-session
+Type=Application
+DesktopNames=GNOME-Classic;GNOME;
+X-GDM-SessionRegisters=true
diff --git a/data/gnome-classic-xorg.desktop.in b/data/gnome-classic-xorg.desktop.in
new file mode 100644
index 00000000..5fb338a1
--- /dev/null
+++ b/data/gnome-classic-xorg.desktop.in
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Name=GNOME Classic on Xorg
+Comment=This session logs you into GNOME Classic
+Exec=env GNOME_SHELL_SESSION_MODE=classic gnome-session
+TryExec=gnome-session
+Type=Application
+DesktopNames=GNOME-Classic;GNOME;
+X-GDM-SessionRegisters=true
diff --git a/data/meson.build b/data/meson.build
index 27f42872..47fe798e 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -1,12 +1,34 @@
-session_desktop = 'gnome-classic.desktop'
-i18n.merge_file('',
- input: session_desktop + '.in',
- output: session_desktop,
- po_dir: '../po',
- install: true,
- install_dir: xsessiondir,
- type: 'desktop'
-)
+session_desktop_base = 'gnome-classic'
+
+session_desktops = [
+ session_desktop_base,
+ session_desktop_base + '-xorg',
+ session_desktop_base + '-wayland',
+]
+
+foreach name: session_desktops
+ session_desktop = name + '.desktop'
+ if name.endswith('-xorg')
+ session_instdir = xsessiondir
+ elif name.endswith('-wayland')
+ session_instdir = wlsessiondir
+ else
+ # FIXME: The same target can not be copied into two directories.
+ # There is a workaround in meson/session-post-install.py until proper
+ # solution arises:
+ # https://github.com/mesonbuild/meson/issues/2416
+ session_instdir = xsessiondir
+ #session_instdir = [ xesssiondir, wlsessiondir ]
+ endif
+ i18n.merge_file('',
+ input: session_desktop + '.in',
+ output: session_desktop,
+ po_dir: '../po',
+ install: true,
+ install_dir: session_instdir,
+ type: 'desktop'
+ )
+endforeach
classic_uuids = []
foreach e : classic_extensions
diff --git a/meson.build b/meson.build
index dda3ddac..ea8a859d 100644
--- a/meson.build
+++ b/meson.build
@@ -20,6 +20,7 @@ themedir = join_paths(shelldir, 'theme')
schemadir = join_paths(datadir, 'glib-2.0', 'schemas')
sessiondir = join_paths(datadir, 'gnome-session', 'sessions')
xsessiondir = join_paths(datadir, 'xsessions')
+wlsessiondir = join_paths(datadir, 'wayland-sessions')
ver_arr = meson.project_version().split('.')
shell_version = ver_arr[0]
@@ -90,6 +91,10 @@ endforeach
if classic_mode_enabled
subdir('data')
+ meson.add_install_script(
+ 'meson/session-post-install.py',
+ join_paths(get_option('prefix'), datadir)
+ )
endif
subdir('extensions')
diff --git a/meson/session-post-install.py b/meson/session-post-install.py
new file mode 100755
index 00000000..36abe5e4
--- /dev/null
+++ b/meson/session-post-install.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+
+import os
+import shutil
+import sys
+
+if os.environ.get('DESTDIR'):
+ install_root = os.environ.get('DESTDIR') + os.path.abspath(sys.argv[1])
+else:
+ install_root = sys.argv[1]
+
+# FIXME: Meson is unable to copy a generated target file:
+# https://groups.google.com/forum/#!topic/mesonbuild/3iIoYPrN4P0
+dst_dir = os.path.join(install_root, 'wayland-sessions')
+if not os.path.exists(dst_dir):
+ os.makedirs(dst_dir)
+
+src = os.path.join(install_root, 'xsessions', 'gnome-classic.desktop')
+dst = os.path.join(dst_dir, 'gnome-classic.desktop')
+shutil.copyfile(src, dst)
--
2.33.1

File diff suppressed because it is too large Load Diff

@ -0,0 +1,70 @@
From 34d8854677513b016a08a04cdd9973b165146215 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 19 Mar 2024 13:16:50 +0100
Subject: [PATCH 1/2] window-list: Use more appropriate fallback icon
'icon-missing' is not an actual icon name. It somewhat works
because an invalid icon name will fallback to the correct
'image-missing', however for apps the generic app icon is
a better fallback.
---
extensions/window-list/extension.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 91ee3e6b..1f112548 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -188,7 +188,7 @@ class WindowTitle extends St.BoxLayout {
this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
} else {
this._icon.child = new St.Icon({
- icon_name: 'icon-missing',
+ icon_name: 'application-x-executable',
icon_size: ICON_TEXTURE_SIZE,
});
}
--
2.44.0
From 032cfb3593651c8344a59828a9c674f148329889 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 19 Mar 2024 14:07:12 +0100
Subject: [PATCH 2/2] window-list: Override with window icon if available
---
extensions/window-list/extension.js | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 1f112548..0c28692d 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -192,6 +192,23 @@ class WindowTitle extends St.BoxLayout {
icon_size: ICON_TEXTURE_SIZE,
});
}
+
+ // Override with window icon if available
+ if (this._hasWindowIcon()) {
+ const textureCache = St.TextureCache.get_default();
+ this._icon.child.gicon = textureCache.bind_cairo_surface_property(
+ this._metaWindow, 'icon');
+ }
+ }
+
+ _hasWindowIcon() {
+ // HACK: GI cannot handle CairoSurface, so this
+ // will throw if the icon property is null
+ try {
+ return this._metaWindow.icon !== null;
+ } catch (e) {
+ return true;
+ }
}
_onDestroy() {
--
2.44.0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,116 @@
From 0d9210e9c19c1bd9535ffb75b4834c2ccd8db6c2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 21 Apr 2022 16:34:50 +0200
Subject: [PATCH 1/2] window-list: Fix primary button action on touch
If a click event was triggered via touch rather than a pointer
device, the button parameter is 0 rather than a mouse button
number.
Account for that to make sure that touch events are not misinterpreted
as right clicks.
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/146
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/233>
---
extensions/window-list/extension.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index e122cf5f..43885378 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -381,7 +381,7 @@ class WindowButton extends BaseButton {
return;
}
- if (button === 1)
+ if (!button || button === 1)
_minimizeOrActivateWindow(this.metaWindow);
else
_openMenu(this._contextMenu);
@@ -623,7 +623,7 @@ class AppButton extends BaseButton {
if (contextMenuWasOpen)
this._contextMenu.close();
- if (button === 1) {
+ if (!button || button === 1) {
if (menuWasOpen)
return;
--
2.36.1
From b080bb7ee88d0e5b35dc4a967d2e44eab7921b6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 5 May 2022 20:55:20 +0200
Subject: [PATCH 2/2] window-list: Open menu on long press
Right-click isn't available on touch, so implement long-press as
an alternative.
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/146
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/233>
---
extensions/window-list/extension.js | 42 +++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 43885378..3d1cd053 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -266,6 +266,48 @@ const BaseButton = GObject.registerClass({
this._updateVisibility();
}
+ _setLongPressTimeout() {
+ if (this._longPressTimeoutId)
+ return;
+
+ const { longPressDuration } = Clutter.Settings.get_default();
+ this._longPressTimeoutId =
+ GLib.timeout_add(GLib.PRIORITY_DEFAULT, longPressDuration, () => {
+ delete this._longPressTimeoutId;
+
+ if (this._canOpenPopupMenu() && !this._contextMenu.isOpen)
+ _openMenu(this._contextMenu);
+ return GLib.SOURCE_REMOVE;
+ });
+ }
+
+ _removeLongPressTimeout() {
+ if (!this._longPressTimeoutId)
+ return;
+ GLib.source_remove(this._longPressTimeoutId);
+ delete this._longPressTimeoutId;
+ }
+
+ vfunc_button_press_event(buttonEvent) {
+ if (buttonEvent.button === 1)
+ this._setLongPressTimeout();
+ return super.vfunc_button_press_event(buttonEvent);
+ }
+
+ vfunc_button_release_event(buttonEvent) {
+ this._removeLongPressTimeout();
+
+ return super.vfunc_button_release_event(buttonEvent);
+ }
+
+ vfunc_touch_event(touchEvent) {
+ if (touchEvent.type === Clutter.EventType.TOUCH_BEGIN)
+ this._setLongPressTimeout();
+ else if (touchEvent.type === Clutter.EventType.TOUCH_END)
+ this._removeLongPressTimeout();
+ return super.vfunc_touch_event(touchEvent);
+ }
+
activate() {
if (this.active)
return;
--
2.36.1

@ -1,52 +1,50 @@
## START: Set by rpmautospec
## (rpmautospec version 0.6.5)
## RPMAUTOSPEC: autorelease, autochangelog
%define autorelease(e:s:pb:n) %{?-p:0.}%{lua:
release_number = 1;
base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}"));
print(release_number + base_release_number - 1);
}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}}
## END: Set by rpmautospec
%global major_version %%(cut -d "." -f 1 <<<%{version})
# Minimum GNOME Shell version supported
%global min_gs_version %%(cut -d "." -f 1 <<<%{version})
%global min_gs_version %%(cut -d "." -f 1-3 <<<%{version})
%global pkg_prefix gnome-shell-extension
%global tarball_version %%(echo %{version} | tr '~' '.')
%global major_version %%(cut -d "." -f 1 <<<%{tarball_version})
%if 0%{?rhel}
%global xsession 0
%else
%global xsession 1
%endif
Name: gnome-shell-extensions
Version: 47.2
Release: %autorelease
Version: 40.7
Release: 15%{?dist}
Summary: Modify and extend GNOME Shell functionality and behavior
License: GPL-2.0-or-later
License: GPLv2+
URL: http://wiki.gnome.org/Projects/GnomeShell/Extensions
Source0: http://ftp.gnome.org/pub/GNOME/sources/%{name}/%{major_version}/%{name}-%{tarball_version}.tar.xz
BuildRequires: meson
BuildRequires: git
BuildRequires: gettext >= 0.19.6
BuildRequires: glib2%{?_isa}
Requires: gnome-shell >= %{min_gs_version}
BuildArch: noarch
Patch: extra-extensions-0001-Add-gesture-inhibitor-extension.patch
Patch: extra-extensions-0002-Add-classification-banner.patch
Patch: extra-extensions-0003-Add-heads-up-display.patch
Patch: extra-extensions-0004-Add-custom-menu-extension.patch
Patch: extra-extensions-0005-Add-desktop-icons-extension.patch
Patch: 0001-Include-status-icons-in-classic-session.patch
Patch: window-list-reordering.patch
Patch001: 0001-Update-style.patch
Patch002: 0001-apps-menu-add-logo-icon-to-Applications-menu.patch
Patch003: add-extra-extensions.patch
Patch004: 0001-apps-menu-Explicitly-set-label_actor.patch
Patch005: resurrect-system-monitor.patch
Patch006: 0001-Include-top-icons-in-classic-session.patch
Patch007: 0001-desktop-icons-Update-Japanese-translation.patch
Patch008: desktop-icons-40-fixes.patch
Patch009: 0001-top-icons-Don-t-use-wm_class-as-role.patch
Patch010: 0001-heads-up-display-Add-extension-for-showing-persisten.patch
Patch011: 0001-Add-gesture-inhibitor-extension.patch
Patch012: gnome-classic-wayland.patch
Patch013: 0001-desktop-icons-Fix-stuck-grab-issue-with-rubber-bandi.patch
Patch014: window-list-touch.patch
Patch015: 0001-classification-banner-Handle-fullscreen-monitors.patch
Patch016: 0001-desktop-icons-Don-t-grab-focus-on-click.patch
Patch017: 0001-desktopManager-Hook-into-LayoutManager-to-create-gri.patch
Patch018: 0001-gesture-inhibitor-Allow-inhibiting-workspace-switch-.patch
Patch019: 0001-desktop-icons-Don-t-use-blocking-IO.patch
Patch020: 0001-window-list-Explicitly-dispose-settings-on-destroy.patch
Patch021: 0001-desktop-icons-Don-t-try-spawn-with-non-existent-work.patch
Patch022: 0001-docking-Only-remove-spacer-if-necessary.patch
Patch023: 0001-classification-banner-Hide-from-picks.patch
Patch024: prefer-window-icon.patch
Patch025: more-ws-previews.patch
%description
GNOME Shell Extensions is a collection of extensions providing additional and
@ -57,17 +55,19 @@ Enabled extensions:
* auto-move-windows
* classification-banner
* custom-menu
* dash-to-dock
* dash-to-panel
* desktop-icons
* drive-menu
* gesture-inhibitor
* heads-up-display
* launch-new-instance
* light-style
* heads-up-display
* native-window-placement
* panel-favorites
* places-menu
* screenshot-window-sizer
* status-icons
* system-monitor
* top-icons
* updates-dialog
* user-theme
* window-list
* windowsNavigator
@ -76,7 +76,7 @@ Enabled extensions:
%package -n %{pkg_prefix}-common
Summary: Files common to GNOME Shell Extensions
License: GPL-2.0-or-later
License: GPLv2+
Requires: gnome-shell >= %{min_gs_version}
Obsoletes: %{pkg_prefix}-horizontal-workspaces < 40.0~alpha.1-3
@ -89,8 +89,9 @@ This package provides common data files shared by various extensions.
%package -n gnome-classic-session
Summary: GNOME "classic" mode session
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-apps-menu = %{version}-%{release}
Requires: %{pkg_prefix}-desktop-icons = %{version}-%{release}
Requires: %{pkg_prefix}-launch-new-instance = %{version}-%{release}
Requires: %{pkg_prefix}-places-menu = %{version}-%{release}
Requires: %{pkg_prefix}-window-list = %{version}-%{release}
@ -101,23 +102,9 @@ This package contains the required components for the GNOME Shell "classic"
mode, which aims to provide a GNOME 2-like user interface.
%if %{xsession}
%package -n gnome-classic-session-xsession
Summary: GNOME "classic" mode session on X11
License: GPL-2.0-or-later
Requires: gnome-classic-session = %{version}-%{release}
# The X11 session is deprecated and eventually will be removed
Provides: deprecated()
%description -n gnome-classic-session-xsession
This package contains the required components for the GNOME Shell "classic"
mode on X11, which aims to provide a GNOME 2-like user interface.
%endif
%package -n %{pkg_prefix}-apps-menu
Summary: Application menu for GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
Requires: gnome-menus
@ -127,7 +114,7 @@ This GNOME Shell extension adds a GNOME 2.x style menu for applications.
%package -n %{pkg_prefix}-auto-move-windows
Summary: Assign specific workspaces to applications in GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-auto-move-windows
@ -156,18 +143,36 @@ Requires: %{pkg_prefix}-common = %{version}-%{release}
This GNOME Shell extension adds a custom menu to the desktop background.
%package -n %{pkg_prefix}-dash-to-dock
Summary: Show the dash outside the activities overview
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-dash-to-dock
This GNOME Shell extension makes the dash available outside the activities overview.
%package -n %{pkg_prefix}-dash-to-panel
Summary: Show the dash in the top bar
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-dash-to-panel
This GNOME Shell extension makes the dash available in the top bar
%package -n %{pkg_prefix}-desktop-icons
Summary: Desktop icons support for GNOME Shell (stub)
License: GPL-2.0-or-later
Summary: Desktop icons support for the classic experience
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-desktop-icons
This GNOME Shell extension provides support for icons on the desktop.
This GNOME Shell extension adds desktop icons support as seen in GNOME 2
%package -n %{pkg_prefix}-drive-menu
Summary: Drive status menu for GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-drive-menu
@ -185,20 +190,9 @@ Requires: %{pkg_prefix}-common = %{version}-%{release}
This GNOME Shell extension allows disabling the default desktop gestures.
%package -n %{pkg_prefix}-heads-up-display
Summary: Display persistent on-screen message
Group: User Interface/Desktops
License: GPLv3+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-heads-up-display
This GNOME Shell extension displays a persistent message in the top middle of the screen.
This message can appear on the login screen, lock screen, or regular user session.
%package -n %{pkg_prefix}-launch-new-instance
Summary: Always launch a new application instance for GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-launch-new-instance
@ -206,18 +200,20 @@ This GNOME Shell extension modifies the behavior of clicking in the dash and app
launcher to always launch a new application instance.
%package -n %{pkg_prefix}-light-style
Summary: Use light style in GNOME Shell
License: GPL-2.0-or-later
%package -n %{pkg_prefix}-heads-up-display
Summary: Display persistent on-screen message
Group: User Interface/Desktops
License: GPLv3+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-light-style
This GNOME Shell extension changes the default style to light.
%description -n %{pkg_prefix}-heads-up-display
This GNOME Shell extension displays a persistent message in the top middle of the screen.
This message can appear on the login screen, lock screen, or regular user session.
%package -n %{pkg_prefix}-native-window-placement
Summary: Native window placement for GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-native-window-placement
@ -225,9 +221,18 @@ This GNOME Shell extension provides additional configurability for the window
layout in the overview, including a mechanism similar to KDE4.
%package -n %{pkg_prefix}-panel-favorites
Summary: Favorite launchers in GNOME Shell's top bar
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-panel-favorites
This GNOME Shell extension adds favorite launchers to the top bar.
%package -n %{pkg_prefix}-places-menu
Summary: Places status menu for GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-places-menu
@ -237,7 +242,7 @@ places in the system.
%package -n %{pkg_prefix}-screenshot-window-sizer
Summary: Screenshot window sizer for GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-screenshot-window-sizer
@ -245,29 +250,36 @@ This GNOME Shell extension allows to easily resize windows for GNOME Software
screenshots.
%package -n %{pkg_prefix}-status-icons
Summary: Status icon support for GNOME Shell
%package -n %{pkg_prefix}-systemMonitor
Summary: System Monitor for GNOME Shell
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
Provides: %{pkg_prefix}-top-icons = %{version}-%{release}
Obsoletes: %{pkg_prefix}-top-icons < 47~beta-1
%description -n %{pkg_prefix}-status-icons
This GNOME Shell extension displays status icons in the top bar.
%description -n %{pkg_prefix}-systemMonitor
This GNOME Shell extension is a message tray indicator for CPU and memory usage
%package -n %{pkg_prefix}-system-monitor
Summary: System monitor for GNOME Shell
License: GPL-2.0-or-later
%package -n %{pkg_prefix}-top-icons
Summary: Show legacy icons on top
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-system-monitor
This GNOME Shell extension displays system usage information in the top bar.
%description -n %{pkg_prefix}-top-icons
This GNOME Shell extension moves legacy tray icons into the top bar
%package -n %{pkg_prefix}-updates-dialog
Summary: Show a modal dialog when there are software updates
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-updates-dialog
This GNOME Shell extension shows a modal dialog when there are software updates
%package -n %{pkg_prefix}-user-theme
Summary: Support for custom themes in GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-user-theme
@ -277,7 +289,7 @@ This GNOME Shell extension enables loading a GNOME Shell theme from
%package -n %{pkg_prefix}-window-list
Summary: Display a window list at the bottom of the screen in GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-window-list
@ -286,7 +298,7 @@ This GNOME Shell extension displays a window list at the bottom of the screen.
%package -n %{pkg_prefix}-windowsNavigator
Summary: Support for keyboard selection of windows and workspaces in GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-windowsNavigator
@ -296,7 +308,7 @@ in overlay mode, by pressing the Alt and Ctrl key respectively.
%package -n %{pkg_prefix}-workspace-indicator
Summary: Workspace indicator for GNOME Shell
License: GPL-2.0-or-later
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-workspace-indicator
@ -318,10 +330,6 @@ workspaces.
%find_lang %{name}
%if !%{xsession}
rm -rf %{buildroot}/%{_datadir}/xsessions
%endif
%files -n %{pkg_prefix}-common -f %{name}.lang
%doc NEWS README.md
@ -330,20 +338,16 @@ rm -rf %{buildroot}/%{_datadir}/xsessions
%files -n gnome-classic-session
%{_datadir}/gnome-shell/modes/classic.json
%{_datadir}/gnome-shell/theme/*.svg
%{_datadir}/gnome-shell/theme/gnome-classic-high-contrast.css
%{_datadir}/gnome-shell/theme/gnome-classic.css
%{_datadir}/xsessions/gnome-classic.desktop
%{_datadir}/xsessions/gnome-classic-xorg.desktop
%{_datadir}/wayland-sessions/gnome-classic.desktop
%{_datadir}/wayland-sessions/gnome-classic-wayland.desktop
%{_datadir}/glib-2.0/schemas/00_org.gnome.shell.extensions.classic.gschema.override
%if %{xsession}
%files -n gnome-classic-session-xsession
%{_datadir}/xsessions/gnome-classic.desktop
%{_datadir}/xsessions/gnome-classic-xorg.desktop
%endif
%files -n %{pkg_prefix}-apps-menu
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.apps-menu.gschema.xml
%{_datadir}/gnome-shell/extensions/apps-menu*/
@ -351,6 +355,7 @@ rm -rf %{buildroot}/%{_datadir}/xsessions
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.auto-move-windows.gschema.xml
%{_datadir}/gnome-shell/extensions/auto-move-windows*/
%files -n %{pkg_prefix}-classification-banner
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.classification-banner.gschema.xml
%{_datadir}/gnome-shell/extensions/classification-banner*/
@ -360,7 +365,18 @@ rm -rf %{buildroot}/%{_datadir}/xsessions
%{_datadir}/gnome-shell/extensions/custom-menu*/
%files -n %{pkg_prefix}-dash-to-dock
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml
%{_datadir}/gnome-shell/extensions/dash-to-dock*/
%files -n %{pkg_prefix}-dash-to-panel
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml
%{_datadir}/gnome-shell/extensions/dash-to-panel*/
%files -n %{pkg_prefix}-desktop-icons
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml
%{_datadir}/gnome-shell/extensions/desktop-icons*/
@ -373,17 +389,13 @@ rm -rf %{buildroot}/%{_datadir}/xsessions
%{_datadir}/gnome-shell/extensions/gesture-inhibitor*/
%files -n %{pkg_prefix}-heads-up-display
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.heads-up-display.gschema.xml
%{_datadir}/gnome-shell/extensions/heads-up-display*/
%files -n %{pkg_prefix}-launch-new-instance
%{_datadir}/gnome-shell/extensions/launch-new-instance*/
%files -n %{pkg_prefix}-light-style
%{_datadir}/gnome-shell/extensions/light-style*/
%files -n %{pkg_prefix}-heads-up-display
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.heads-up-display.gschema.xml
%{_datadir}/gnome-shell/extensions/heads-up-display*/
%files -n %{pkg_prefix}-native-window-placement
@ -391,6 +403,10 @@ rm -rf %{buildroot}/%{_datadir}/xsessions
%{_datadir}/gnome-shell/extensions/native-window-placement*/
%files -n %{pkg_prefix}-panel-favorites
%{_datadir}/gnome-shell/extensions/panel-favorites*/
%files -n %{pkg_prefix}-places-menu
%{_datadir}/gnome-shell/extensions/places-menu*/
@ -400,13 +416,17 @@ rm -rf %{buildroot}/%{_datadir}/xsessions
%{_datadir}/gnome-shell/extensions/screenshot-window-sizer*/
%files -n %{pkg_prefix}-status-icons
%{_datadir}/gnome-shell/extensions/status-icons*/
%files -n %{pkg_prefix}-systemMonitor
%{_datadir}/gnome-shell/extensions/systemMonitor*/
%files -n %{pkg_prefix}-system-monitor
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml
%{_datadir}/gnome-shell/extensions/system-monitor*/
%files -n %{pkg_prefix}-top-icons
%{_datadir}/gnome-shell/extensions/top-icons*/
%files -n %{pkg_prefix}-updates-dialog
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.updates-dialog.gschema.xml
%{_datadir}/gnome-shell/extensions/updates-dialog*/
%files -n %{pkg_prefix}-user-theme
@ -429,174 +449,154 @@ rm -rf %{buildroot}/%{_datadir}/xsessions
%changelog
## START: Generated by rpmautospec
* Mon Dec 02 2024 Florian Müllner <fmuellner@redhat.com> - 47.2-1
- Update to 47.2
* Wed Nov 06 2024 Florian Müllner <fmuellner@redhat.com> - 47.1-1
- Update to 47.1
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 47.0-3
- Bump release for October 2024 mass rebuild:
* Thu Oct 17 2024 Florian Müllner <fmuellner@redhat.com> - 47.0-2
- Allow reordering items in window-list
* Mon Sep 16 2024 Florian Müllner <fmuellner@redhat.com> - 47.0-1
- Update to 47.0
* Tue Sep 10 2024 Florian Müllner <fmuellner@redhat.com> - 47~rc-2
- Adjust to "top-icons" name change
* Tue Sep 03 2024 Florian Müllner <fmuellner@redhat.com> - 47~rc-1
- Update to 47.rc
* Thu Aug 22 2024 Florian Müllner <fmuellner@redhat.com> - 47~alpha-3
- Add desktop-icons stub
* Tue Jul 30 2024 Florian Müllner <fmuellner@redhat.com> - 47~alpha-2
- Adjust classification banner for GNOME 47 changes
* Tue Jul 23 2024 Florian Müllner <fmuellner@redhat.com> - 47~alpha-1
- Update to 47.alpha
* Tue Jul 02 2024 Florian Müllner <fmuellner@redhat.com> - 46.2-4
- Extend workspace buttons to screen edge
* Mon Jul 01 2024 Florian Müllner <fmuellner@redhat.com> - 46.2-3
- Conditionalize Xorg session
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 46.2-2
- Bump release for June 2024 mass rebuild
* Mon May 27 2024 Florian Müllner <fmuellner@redhat.com> - 46.2-1
- Update to 46.2
* Wed May 15 2024 Florian Müllner <fmuellner@redhat.com> - 46.1-3
- Re-apply downstream patches
* Thu May 02 2024 Tomas Pelka <tpelka@redhat.com> - 46.1-2
- Add gating.yaml via API
* Mon Apr 22 2024 Florian Müllner <fmuellner@redhat.com> - 46.1-1
- Pick up changes from F40
* Wed Apr 10 2024 Florian Müllner <fmuellner@gnome.org> - 46.0-1
- Backport F40 changes
* Wed Jan 24 2024 Fedora Release Engineering <releng@fedoraproject.org> - 46~alpha-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Fri Jan 19 2024 Fedora Release Engineering <releng@fedoraproject.org> - 46~alpha-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Sun Jan 07 2024 Florian Müllner <fmuellner@gnome.org> - 46~alpha-1
- Update to 46.alpha
* Sat Dec 02 2023 Florian Müllner <fmuellner@gnome.org> - 45.2-1
- Update to 45.2
* Tue Oct 31 2023 Florian Müllner <fmuellner@gnome.org> - 45.1-1
- Update to 45.1
* Sat Sep 16 2023 Florian Müllner <fmuellner@gnome.org> - 45.0-1
- Update to 45.0
* Wed Sep 06 2023 Adam Williamson <awilliam@redhat.com> - 45~rc-2
- Rebuild on a side tag to create combined update
* Wed Sep 06 2023 Florian Müllner <fmuellner@gnome.org> - 45~rc-1
- Update to 45.rc
* Mon Aug 07 2023 Florian Müllner <fmuellner@gnome.org> - 45~beta-1
- Update to 45.beta
* Wed Jul 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 45~alpha-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Thu Jul 06 2023 Florian Müllner <fmuellner@gnome.org> - 45~alpha-1
- Update to 45.alpha
* Sun Mar 19 2023 Florian Müllner <fmuellner@redhat.com> - 44.0-1
- Update to 44.0
* Mon Mar 06 2023 Florian Müllner <fmuellner@redhat.com> - 44~rc-1
- Update to 44.rc
* Tue Feb 14 2023 Florian Müllner <fmuellner@redhat.com> - 44~beta-1
- Update to 44.beta
* Thu Jan 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 43.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
* Fri Oct 28 2022 Florian Müllner <fmuellner@redhat.com> - 43.1-2
- Adjust gnome-shell dependency
* Wed Oct 26 2022 Florian Müllner <fmuellner@redhat.com> - 43.1-1
- Update to 43.1
* Sat Sep 17 2022 Florian Müllner <fmuellner@redhat.com> - 43.0-1
- Update to 43.0
* Sun Sep 04 2022 Florian Müllner <fmuellner@redhat.com> - 43~rc-1
- Update to 43.rc
* Wed Aug 10 2022 Florian Müllner <fmuellner@redhat.com> - 43~beta-1
- Update to 43.beta
* Thu Jul 21 2022 Fedora Release Engineering <releng@fedoraproject.org> - 43~alpha-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
* Sun Jul 10 2022 Florian Müllner <fmuellner@redhat.com> - 43~alpha-1
- Update to 43.alpha
* Sat May 28 2022 Florian Müllner <fmuellner@redhat.com> - 42.2-1
- Update to 42.2
* Fri May 06 2022 Florian Müllner <fmuellner@redhat.com> - 42.1-1
- Update to 42.1
* Sun Mar 13 2022 Florian Müllner <fmuellner@redhat.com> - 42.0-1
- Update to 42.0
* Mon Mar 07 2022 Florian Müllner <fmuellner@redhat.com> - 42~rc-1
- Update to 42.rc
* Tue Feb 15 2022 Florian Müllner <fmuellner@redhat.com> - 42~beta-1
- Update to 42.beta
* Thu Jan 20 2022 Fedora Release Engineering <releng@fedoraproject.org> - 42~alpha-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
* Tue Jan 11 2022 Florian Müllner <fmuellner@redhat.com> - 42~alpha-1
- Update to 42.alpha
* Fri Oct 29 2021 Neal Gompa <ngompa@fedoraproject.org> - 41.0-2
- Backport GNOME Classic session for Wayland (#2015741)
* Sun Sep 19 2021 Florian Müllner <fmuellner@redhat.com> - 41.0-1
- Update to 41.0
* Mon Sep 06 2021 Florian Müllner <fmuellner@redhat.com> - 41~rc.1-1
- Update to 41.rc.1
* Fri Apr 19 2024 Florian Müllner <fmuellner@redhat.com> - 40.7-15
- Fix downstream stylesheets
Resolves: RHEL-31885
* Thu Apr 18 2024 Florian Müllner <fmuellner@redhat.com> - 40.7-14
- Improve workspace previews
Resolves: RHEL-31885
* Tue Mar 19 2024 Florian Müllner <fmuellner@redhat.com> - 40.7-13
- Prefer window icons in window list
Resolves: RHEL-29659
* Fri Feb 02 2024 Florian Müllner <fmuellner@redhat.com> - 40.7-12
- Hide classification banners from picks
Resolves: RHEL-22789
* Thu Dec 14 2023 Florian Müllner <fmuellner@redhat.com> - 40.7-11
- Handle missing main dock when restoring dash
Resolves: RHEL-16723
* Tue Nov 07 2023 Florian Müllner <fmuellner@redhat.com> - 40.7-10
- Include dash-to-panel extension
Resolves: RHEL-14935
* Thu Nov 02 2023 Florian Müllner <fmuellner@redhat.com> - 40.7-9
- Fix spawning terminal without desktop directory
Resolves: RHEL-15366
* Thu Aug 17 2023 Florian Müllner <fmuellner@redhat.com> - 40.7-8
- Rebuild for custom context menu
Resolves: #2232332
* Wed Feb 15 2023 Florian Müllner <fmuellner@redhat.com> - 40.7-7
- Fix crash on `dconf update`
Resolves: #2170067
* Wed Jan 18 2023 Florian Müllner <fmuellner@redhat.com> - 40.7-6
- Avoid blocking IO in desktop-icons
Resolves: #2162019
* Thu Jan 12 2023 Florian Müllner <fmuellner@redhat.com> - 40.7-5
- Add custom-menu extension
Resolves: #2160553
* Wed Dec 14 2022 Florian Müllner <fmuellner@redhat.com> - 40.7-4
- Adjust classification banner position in fullscreen
Resolves: #2153524
- Don't grab focus when clicking desktop grid
Resolves: #2150001
- Make desktop icons resilient to background reloads
Resolves: #2139895
- Allow disabling workspace switch gesture
Resolves: #2154358
* Wed Jun 22 2022 Florian Müllner <fmuellner@redhat.com> - 40.7-3
- Improve window-list on touch
Resolves: #2099286
* Fri May 13 2022 Florian Müllner <fmuellner@redhat.com> - 40.7-2
- Require desktop-icons for classic session
Resolves: #2047697
* Wed Apr 13 2022 Florian Müllner <fmuellner@redhat.com> - 40.7-1
- Update to 40.7
Resolves: #2066168
* Tue Feb 22 2022 Florian Müllner <fmuellner@redhat.com> - 40.6-1
- Update to 40.6
Resolves: #2056410
* Tue Dec 14 2021 Florian Müllner <fmuellner@redhat.com> - 40.5-4
- Allow classification banners on lock/login screen
Resolves: #2031186
* Tue Dec 14 2021 Florian Müllner <fmuellner@redhat.com> - 40.5-3
- Fix classification-banner preferences
Resolves: #2031186
* Tue Dec 14 2021 Florian Müllner <fmuellner@redhat.com> - 40.5-2
- Add classification-banner
Resolves: #2031186
* Mon Dec 13 2021 Florian Müllner <fmuellner@redhat.com> - 40.5-1
- Update to 40.5
Resolves: #2031654
* Tue Nov 30 2021 Florian Müllner <fmuellner@redhat.com> - 40.4-8
- Fix on-screen keyboard when showing window-list
Resolves: #2019866
* Thu Nov 18 2021 Florian Müllner <fmuellner@redhat.com> - 40.4-7
- Prevent gnome-shell from re-enabling inhibited gestures
Resolves: #2013196
* Mon Nov 08 2021 Jonas Ådahl <jadahl@redhat.com> - 40.4-6
- Fix stuck grab on desktop-icons
Resolves: #2019715
* Fri Oct 29 2021 Neal Gompa <ngompa@centosproject.org> - 40.4-5
- Backport GNOME Classic session for Wayland
Resolves: #2015914
* Wed Oct 20 2021 Florian Müllner <fmuellner@redhat.com> - 40.4-4
- Adjust gesture-inhibitor extension to GNOME 40 changes
Resolves: #2013196
* Wed Oct 20 2021 Florian Müllner <fmuellner@redhat.com> - 40.4-3
- Add gesture-inhibitor extension
Resolves: #2013196
* Mon Sep 27 2021 Ray Strode <rstrode@redhat.com> - 40.4-2
- Add extension for displaying heads up message
Related: #2006985
* Mon Aug 23 2021 Florian Müllner <fmuellner@redhat.com> - 40.4-1
- Update to 40.4
Resolves: #1995095
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 40.3-2
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Mon Jul 19 2021 Florian Müllner <fmuellner@redhat.com> - 40.3-1
- Update to 40.3
Resolves: #1983551
* Sun Sep 05 2021 Florian Müllner <fmuellner@redhat.com> - 41~rc-1
- Update to 41.rc
* Tue Jun 15 2021 Florian Müllner <fmuellner@redhat.com> - 40.2-1
- Update to 40.2
Resolves: #1971431
* Wed Aug 18 2021 Florian Müllner <fmuellner@redhat.com> - 41~beta-1
- Update to 41.beta
* Thu Jun 03 2021 Florian Müllner <fmuellner@redhat.com> - 40.1-4
- Don't use status icon wm_class as top bar role
Resolves: #1967259
* Thu Jul 22 2021 Fedora Release Engineering <releng@fedoraproject.org> - 40.3-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
* Wed May 26 2021 Florian Müllner <fmuellner@redhat.com> - 40.1-3
- Fix various issues in downstream patches
Resolves: #1932261
* Mon Jul 12 2021 Florian Müllner <fmuellner@redhat.com> - 40.3-1
- Update to 40.3
* Mon May 24 2021 Florian Müllner <fmuellner@redhat.com> - 40.1-2
- Rebase downstream patches
Resolves: #1932261
* Thu Jun 10 2021 Florian Müllner <fmuellner@redhat.com> - 40.2-1
- Update to 40.2
* Thu May 13 2021 Florian Müllner <fmuellner@redhat.com> - 40.1-1
* Mon May 17 2021 Florian Müllner <fmuellner@redhat.com> - 40.1-1
- Update to 40.1
Resolves: #1951132
* Thu Apr 15 2021 Mohan Boddu <mboddu@redhat.com> - 40.0-2
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Sat Mar 20 2021 Florian Müllner <fmuellner@redhat.com> - 40.0-1
- Update to 40.0
@ -1217,5 +1217,3 @@ rm -rf %{buildroot}/%{_datadir}/xsessions
* Fri Apr 08 2011 Rahul Sundaram <sundaram@fedoraproject.org> - 3.0.0-0.6d56cfgit
- Initial build
## END: Generated by rpmautospec

Loading…
Cancel
Save