import gnome-shell-extensions-40.7-7.el9

This commit is contained in:
CentOS Sources 2023-03-28 10:15:33 +00:00 committed by Stepan Oksanichenko
parent b285417ee8
commit 4318c62e47
10 changed files with 1341 additions and 38 deletions

View File

@ -1,4 +1,4 @@
From 95bf73c668eab5c222568bdb6a3030a5bed8d4d3 Mon Sep 17 00:00:00 2001
From 38c4fc02dea622f198b078eb4003c777d982119c 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
@ -170,22 +170,22 @@ index 00000000..37b93f21
@@ -0,0 +1 @@
+/* Add your custom extension styling here */
diff --git a/meson.build b/meson.build
index 8b67435b..fd328df5 100644
index 3600e824..b3812b8d 100644
--- a/meson.build
+++ b/meson.build
@@ -48,6 +48,7 @@ all_extensions += [
'auto-move-windows',
@@ -49,6 +49,7 @@ all_extensions += [
'classification-banner',
'custom-menu',
'dash-to-dock',
+ 'gesture-inhibitor',
'native-window-placement',
'panel-favorites',
'systemMonitor',
--
2.33.1
2.38.1
From 89daf03fcc0f7b157e90a5ef4487e94e27fe8d38 Mon Sep 17 00:00:00 2001
From aff83154aa639e33e5ba925b5ddcc824a9beaf6e 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
@ -273,10 +273,10 @@ index e74ede2f..734d61cc 100644
}
--
2.33.1
2.38.1
From 00ffe8e51dbb8609461239d753d2215e66b2b76d Mon Sep 17 00:00:00 2001
From 5c8b087e99f79cc6bd83b5e7ad0775f8510e1a5d 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
@ -344,10 +344,10 @@ index 1d67dcc0..4bdf9260 100644
<default>true</default>
<summary>Show OSK gesture</summary>
--
2.33.1
2.38.1
From cd42930b27efbffdac6b259bf7417a4528f5bfdf Mon Sep 17 00:00:00 2001
From 7f8031a97046a18ebb39972150376b9f1cf9a70b 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
@ -374,10 +374,10 @@ index 13586108..02b34ec4 100644
}
--
2.33.1
2.38.1
From 294fe1f115d8c23e71608c34be296dd0080f2671 Mon Sep 17 00:00:00 2001
From 15b4dde292cd1dd33c881289e6182d7261bee544 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
@ -434,5 +434,5 @@ index 02b34ec4..fb8a6dc0 100644
});
}
--
2.33.1
2.38.1

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,7 +1,7 @@
From ce63b1027e8bf79688f38babecae0dcd867778f8 Mon Sep 17 00:00:00 2001
From 6623a374036e0f2458d4b36e268f6e4dcc19a2d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 20 May 2015 17:44:50 +0200
Subject: [PATCH 1/6] Add top-icons extension
Subject: [PATCH 1/7] Add top-icons extension
---
extensions/top-icons/extension.js | 96 +++++++++++++++++++++++++++
@ -152,7 +152,7 @@ index 00000000..25134b65
@@ -0,0 +1 @@
+/* This extensions requires no special styling */
diff --git a/meson.build b/meson.build
index 188e19e5..1d94882f 100644
index 41a7e99d..f754767c 100644
--- a/meson.build
+++ b/meson.build
@@ -45,6 +45,7 @@ all_extensions = default_extensions
@ -164,13 +164,13 @@ index 188e19e5..1d94882f 100644
]
--
2.33.1
2.38.1
From 40aa60ef32f9283147745ac960e7e22b2d608df5 Mon Sep 17 00:00:00 2001
From a38891b5a6b0ba51998298963988bf146b2e1f86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 20 May 2015 18:05:41 +0200
Subject: [PATCH 2/6] Add dash-to-dock extension
Subject: [PATCH 2/7] Add dash-to-dock extension
---
extensions/dash-to-dock/Settings.ui | 2660 +++++++++++++++++
@ -29865,7 +29865,7 @@ index 00000000..8cb14b88
+});
\ No newline at end of file
diff --git a/meson.build b/meson.build
index 1d94882f..e3a64a92 100644
index f754767c..e3d94918 100644
--- a/meson.build
+++ b/meson.build
@@ -44,6 +44,7 @@ default_extensions += [
@ -44398,13 +44398,13 @@ index 6a40e212..14e60ccb 100644
+#~ msgid "0.000"
+#~ msgstr "0.000"
--
2.33.1
2.38.1
From 7bcecaa3b0532221690b8cb0df5184a80ed15dd5 Mon Sep 17 00:00:00 2001
From 6cad2aac52022030bcbbf03066fc08937f6d177f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 20 May 2015 18:55:47 +0200
Subject: [PATCH 3/6] Add panel-favorites extension
Subject: [PATCH 3/7] Add panel-favorites extension
---
extensions/panel-favorites/extension.js | 257 ++++++++++++++++++++
@ -44729,7 +44729,7 @@ index 00000000..120adacb
+ -y-offset: 6px;
+}
diff --git a/meson.build b/meson.build
index e3a64a92..47b6c46c 100644
index e3d94918..12706001 100644
--- a/meson.build
+++ b/meson.build
@@ -46,6 +46,7 @@ all_extensions += [
@ -44741,13 +44741,13 @@ index e3a64a92..47b6c46c 100644
'user-theme'
]
--
2.33.1
2.38.1
From 7a4402c27a93cfff76504f561013498f31966da8 Mon Sep 17 00:00:00 2001
From dbd3ebbb2d3cf380f2c0a13f13618fedfd8bbad4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 4 Mar 2016 17:07:21 +0100
Subject: [PATCH 4/6] Add updates-dialog extension
Subject: [PATCH 4/7] Add updates-dialog extension
---
extensions/updates-dialog/extension.js | 504 ++++++++++++++++++
@ -45347,7 +45347,7 @@ index 00000000..25134b65
@@ -0,0 +1 @@
+/* This extensions requires no special styling */
diff --git a/meson.build b/meson.build
index 47b6c46c..c54ef777 100644
index 12706001..c609ae52 100644
--- a/meson.build
+++ b/meson.build
@@ -48,6 +48,7 @@ all_extensions += [
@ -45372,13 +45372,13 @@ index 0ed12762..10b1d517 100644
extensions/window-list/extension.js
extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml
--
2.33.1
2.38.1
From d04e5acf2bf6076aeca3c2da27c8edfdd5098606 Mon Sep 17 00:00:00 2001
From 5de33c69acd297659ac3182e85f0fe32771dd75e Mon Sep 17 00:00:00 2001
From: Carlos Soriano <csoriano@gnome.org>
Date: Mon, 13 Aug 2018 17:28:41 +0200
Subject: [PATCH 5/6] Add desktop icons extension
Subject: [PATCH 5/7] Add desktop icons extension
---
.../desktop-icons/createFolderDialog.js | 165 +++
@ -56921,7 +56921,7 @@ index 00000000..a468f4ab
+ }
+}
diff --git a/meson.build b/meson.build
index c54ef777..08213618 100644
index c609ae52..b83f0795 100644
--- a/meson.build
+++ b/meson.build
@@ -28,6 +28,7 @@ uuid_suffix = '@gnome-shell-extensions.gcampax.github.com'
@ -66729,13 +66729,13 @@ index 14e60ccb..4bdf7154 100644
+#~ msgid "Huge"
+#~ msgstr "巨大圖示"
--
2.33.1
2.38.1
From 01a4309a2574768c037f14732e8595c1f436170f Mon Sep 17 00:00:00 2001
From 794dd76a7b7caf3324736de6c26bb992fe403daf 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 6/6] Add classification-banner
Subject: [PATCH 6/7] Add classification-banner
---
extensions/classification-banner/adwShim.js | 202 ++++++++++++++++++
@ -67417,7 +67417,7 @@ index 00000000..fb6a697e
+.classification-message { font-weight: bold; }
+.classification-banner { font-size: 0.9em; }
diff --git a/meson.build b/meson.build
index 08213618..dea0a409 100644
index b83f0795..c71636cb 100644
--- a/meson.build
+++ b/meson.build
@@ -45,6 +45,7 @@ default_extensions += [
@ -67429,5 +67429,789 @@ index 08213618..dea0a409 100644
'native-window-placement',
'panel-favorites',
--
2.33.1
2.38.1
From 4cde1aa62f4605cde761c9f0f2f95af64515720d 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 7/7] Add custom-menu extension
---
extensions/custom-menu/config.js | 484 ++++++++++++++++++++++++
extensions/custom-menu/extension.js | 217 +++++++++++
extensions/custom-menu/meson.build | 7 +
extensions/custom-menu/metadata.json.in | 10 +
extensions/custom-menu/stylesheet.css | 1 +
meson.build | 1 +
6 files changed, 720 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
create mode 100644 extensions/custom-menu/stylesheet.css
diff --git a/extensions/custom-menu/config.js b/extensions/custom-menu/config.js
new file mode 100644
index 00000000..652c0223
--- /dev/null
+++ b/extensions/custom-menu/config.js
@@ -0,0 +1,484 @@
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Json = imports.gi.Json;
+const Lang = imports.lang;
+const Main = imports.ui.main;
+const PopupMenu = imports.ui.popupMenu;
+const ByteArray = imports.byteArray;
+
+const Me = imports.misc.extensionUtils.getCurrentExtension();
+const getLogger = Me.imports.extension.getLogger;
+
+const Entry = new Lang.Class({
+ Name: 'Entry',
+ Abstract: true,
+
+ _init: function(prop) {
+ this.type = prop.type;
+ this.title = prop.title || "";
+
+ this.__vars = prop.__vars || [];
+ this.updateEnv(prop);
+ },
+
+ setTitle: function(text) {
+ this.item.label.get_clutter_text().set_text(text);
+ },
+
+ updateEnv: function(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: function() { },
+
+ _try_destroy: function() {
+ try {
+ if(this.item && this.item.destroy)
+ this.item.destroy();
+ } catch(e) { /* Ignore all errors during destory*/ }
+ },
+});
+
+const DerivedEntry = new Lang.Class({
+ Name: 'DerivedEntry',
+
+ _init: function(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: function(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;
+ },
+});
+
+/*
+ * callback: function (stdout, stderr, exit_status) { }
+ */
+let __pipeOpenQueue = [];
+let __pipeExecTimer = null;
+
+function pipeOpen(cmdline, env, callback) {
+ let param = [cmdline, env, callback]
+ __pipeOpenQueue.push(param);
+ if(__pipeExecTimer === null) {
+ __pipeExecTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 50,
+ function() {
+ let param = __pipeOpenQueue.shift();
+ if(param === undefined) {
+ __pipeExecTimer = null;
+ return false;
+ }
+ if(realPipeOpen) realPipeOpen(param[0], param[1], param[2]);
+ 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) {
+ stdout_content = ByteArray.toString(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 = ByteArray.toString(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);
+
+ // log(`Spawning ${cmdline}`); TODO: BEN
+ 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);
+ }
+ });
+}
+
+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 = { };
+
+const TogglerEntry = new Lang.Class({
+ Name: 'TogglerEntry',
+ Extends: Entry,
+
+ _init: function(prop) {
+ this.parent(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: function() {
+ 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', Lang.bind(this, this._onManuallyToggled));
+ this._loadState();
+ return this.item;
+ },
+
+ _onManuallyToggled: function(_, state) {
+ // when switched on again, this flag will get cleared.
+ this._manually_switched_off = !state;
+ this._storeState(state);
+ this._onToggled(state);
+ },
+
+ _onToggled: function(state) {
+ if(state)
+ _generalSpawn(this.command_on, this.__env, this.title);
+ else
+ _generalSpawn(this.command_off, this.__env, this.title);
+ },
+
+ _detect: function(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*$/)));
+ });
+ },
+
+ compareState: function(new_state) {
+ // compare the new state with cached state
+ // notify when state is different
+ 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: function(state) {
+ let hash = JSON.stringify({ env: this.__env, detector: this.detector });
+ _toggler_state_cache[hash] = state;
+ },
+
+ _loadState: function() {
+ 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: function() {
+ this._detect(Lang.bind(this, function(state) {
+ this.compareState(state);
+
+ this._storeState(state);
+ this._loadState();
+ //global.log(this.title + ': ' + this._manually_switched_off);
+
+ 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: function() {
+ this.item.toggle();
+ },
+});
+
+const LauncherEntry = new Lang.Class({
+ Name: 'LauncherEntry',
+ Extends: Entry,
+
+ _init: function(prop) {
+ this.parent(prop);
+
+ this.command = prop.command || "";
+ },
+
+ createItem: function() {
+ this._try_destroy();
+
+ this.item = new PopupMenu.PopupMenuItem(this.title);
+ this.item.label.get_clutter_text().set_use_markup(true);
+ this.item.connect('activate', Lang.bind(this, this._onClicked));
+
+ return this.item;
+ },
+
+ _onClicked: function(_) {
+ _generalSpawn(this.command, this.__env, this.title);
+ },
+
+ perform: function() {
+ this.item.emit('activate');
+ },
+});
+
+const SubMenuEntry = new Lang.Class({
+ Name: 'SubMenuEntry',
+ Extends: Entry,
+
+ _init: function(prop) {
+ this.parent(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: function() {
+ 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: function() {
+ for(let i in this.entries) {
+ let entry = this.entries[i];
+ entry.pulse();
+ }
+ }
+});
+
+const SeparatorEntry = new Lang.Class({
+ Name: 'SeparatorEntry',
+ Extends: Entry,
+
+ _init: function(prop) { },
+
+ createItem: function() {
+ 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);
+}
+
+var Loader = new Lang.Class({
+ Name: 'ConfigLoader',
+
+ _init: function(filename) {
+ if(filename)
+ this.loadConfig(filename);
+ },
+
+ loadConfig: function(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: function(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..9f3e3ce8
--- /dev/null
+++ b/extensions/custom-menu/extension.js
@@ -0,0 +1,217 @@
+/* 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
+ */
+
+/* exported init */
+
+const GETTEXT_DOMAIN = 'custom-menu-panel';
+const CONFIGURATION_FILE = '/.entries.json';
+
+const { GObject, St } = imports.gi;
+
+const Gettext = imports.gettext.domain(GETTEXT_DOMAIN);
+const _ = Gettext.gettext;
+
+const ExtensionUtils = imports.misc.extensionUtils;
+const Lang = imports.lang;
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const BackgroundMenu = imports.ui.backgroundMenu;
+const Main = imports.ui.main;
+const PanelMenu = imports.ui.panelMenu;
+const PopupMenu = imports.ui.popupMenu;
+
+const Me = imports.misc.extensionUtils.getCurrentExtension();
+const Config = Me.imports.config
+
+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));
+ }
+ }
+);
+
+
+const Logger = new Lang.Class({
+ Name: 'Logger',
+
+ _init: function(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: function() {
+ this.log = function(_) { };
+ },
+
+ _initGnomeLog: function() {
+ this.log = function(s) {
+ global.log("custom-menu-panel> " + s);
+ };
+ },
+
+ _initFileLog: function() {
+ 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: function(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;
+function getLogger() {
+ if(logger === null)
+ logger = new Logger("gnome-shell");
+ return logger;
+}
+
+class Extension {
+ constructor(uuid) {
+ this._uuid = uuid;
+
+ ExtensionUtils.initTranslations(GETTEXT_DOMAIN);
+ }
+
+ enable() {
+ BackgroundMenu.BackgroundMenu = CustomBackgroundMenu;
+ Main.layoutManager._updateBackgrounds();
+ }
+
+ disable() {
+ BackgroundMenu.BackgroundMenu = OriginalBackgroundMenu;
+ Main.layoutManager._updateBackgrounds();
+ }
+}
+
+function init(meta) {
+ return new Extension(meta.uuid);
+}
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/extensions/custom-menu/stylesheet.css b/extensions/custom-menu/stylesheet.css
new file mode 100644
index 00000000..25134b65
--- /dev/null
+++ b/extensions/custom-menu/stylesheet.css
@@ -0,0 +1 @@
+/* This extensions requires no special styling */
diff --git a/meson.build b/meson.build
index c71636cb..23fb2c89 100644
--- a/meson.build
+++ b/meson.build
@@ -46,6 +46,7 @@ all_extensions = default_extensions
all_extensions += [
'auto-move-windows',
'classification-banner',
+ 'custom-menu',
'dash-to-dock',
'native-window-placement',
'panel-favorites',
--
2.38.1

View File

@ -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

View File

@ -7,7 +7,7 @@
Name: gnome-shell-extensions
Version: 40.7
Release: 2%{?dist}
Release: 7%{?dist}
Summary: Modify and extend GNOME Shell functionality and behavior
License: GPLv2+
@ -33,6 +33,13 @@ 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
%description
GNOME Shell Extensions is a collection of extensions providing additional and
@ -42,6 +49,7 @@ Enabled extensions:
* apps-menu
* auto-move-windows
* classification-banner
* custom-menu
* dash-to-dock
* desktop-icons
* drive-menu
@ -119,6 +127,16 @@ Requires: %{pkg_prefix}-common = %{version}-%{release}
This GNOME Shell extension adds a banner that displays the classification level.
%package -n %{pkg_prefix}-custom-menu
Summary: Add a custom menu to the desktop
Group: User Interface/Desktops
License: GPLv2+
Requires: %{pkg_prefix}-common = %{version}-%{release}
%description -n %{pkg_prefix}-custom-menu
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+
@ -328,6 +346,10 @@ workspaces.
%{_datadir}/gnome-shell/extensions/classification-banner*/
%files -n %{pkg_prefix}-custom-menu
%{_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*/
@ -406,6 +428,32 @@ workspaces.
%changelog
* 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