import gnome-shell-extensions-40.7-7.el9
This commit is contained in:
parent
a2e3b9aaaa
commit
b58c67ad54
@ -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>
|
From: rpm-build <rpm-build>
|
||||||
Date: Thu, 28 Jan 2021 00:06:12 +0100
|
Date: Thu, 28 Jan 2021 00:06:12 +0100
|
||||||
Subject: [PATCH 1/5] Add gesture-inhibitor extension
|
Subject: [PATCH 1/5] Add gesture-inhibitor extension
|
||||||
@ -170,22 +170,22 @@ index 00000000..37b93f21
|
|||||||
@@ -0,0 +1 @@
|
@@ -0,0 +1 @@
|
||||||
+/* Add your custom extension styling here */
|
+/* Add your custom extension styling here */
|
||||||
diff --git a/meson.build b/meson.build
|
diff --git a/meson.build b/meson.build
|
||||||
index 8b67435b..fd328df5 100644
|
index 3600e824..b3812b8d 100644
|
||||||
--- a/meson.build
|
--- a/meson.build
|
||||||
+++ b/meson.build
|
+++ b/meson.build
|
||||||
@@ -48,6 +48,7 @@ all_extensions += [
|
@@ -49,6 +49,7 @@ all_extensions += [
|
||||||
'auto-move-windows',
|
|
||||||
'classification-banner',
|
'classification-banner',
|
||||||
|
'custom-menu',
|
||||||
'dash-to-dock',
|
'dash-to-dock',
|
||||||
+ 'gesture-inhibitor',
|
+ 'gesture-inhibitor',
|
||||||
'native-window-placement',
|
'native-window-placement',
|
||||||
'panel-favorites',
|
'panel-favorites',
|
||||||
'systemMonitor',
|
'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>
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||||
Date: Wed, 20 Oct 2021 19:48:46 +0200
|
Date: Wed, 20 Oct 2021 19:48:46 +0200
|
||||||
Subject: [PATCH 2/5] gesture-inhibitor: Fix up indentation
|
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>
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||||
Date: Wed, 20 Oct 2021 19:47:05 +0200
|
Date: Wed, 20 Oct 2021 19:47:05 +0200
|
||||||
Subject: [PATCH 3/5] gesture-inhibitor: Adjust for GNOME 40 changes
|
Subject: [PATCH 3/5] gesture-inhibitor: Adjust for GNOME 40 changes
|
||||||
@ -344,10 +344,10 @@ index 1d67dcc0..4bdf9260 100644
|
|||||||
<default>true</default>
|
<default>true</default>
|
||||||
<summary>Show OSK gesture</summary>
|
<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>
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||||
Date: Thu, 18 Nov 2021 15:54:23 +0100
|
Date: Thu, 18 Nov 2021 15:54:23 +0100
|
||||||
Subject: [PATCH 4/5] gesture-inhibitor: Unbind setting on disable
|
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>
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||||
Date: Thu, 18 Nov 2021 16:06:09 +0100
|
Date: Thu, 18 Nov 2021 16:06:09 +0100
|
||||||
Subject: [PATCH 5/5] gesture-inhibitor: Override :enabled property
|
Subject: [PATCH 5/5] gesture-inhibitor: Override :enabled property
|
||||||
@ -434,5 +434,5 @@ index 02b34ec4..fb8a6dc0 100644
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
--
|
--
|
||||||
2.33.1
|
2.38.1
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
33
SOURCES/0001-desktop-icons-Don-t-grab-focus-on-click.patch
Normal file
33
SOURCES/0001-desktop-icons-Don-t-grab-focus-on-click.patch
Normal 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
|
||||||
|
|
108
SOURCES/0001-desktop-icons-Don-t-use-blocking-IO.patch
Normal file
108
SOURCES/0001-desktop-icons-Don-t-use-blocking-IO.patch
Normal 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
|
||||||
|
|
@ -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,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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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>
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||||
Date: Wed, 20 May 2015 17:44:50 +0200
|
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 +++++++++++++++++++++++++++
|
extensions/top-icons/extension.js | 96 +++++++++++++++++++++++++++
|
||||||
@ -152,7 +152,7 @@ index 00000000..25134b65
|
|||||||
@@ -0,0 +1 @@
|
@@ -0,0 +1 @@
|
||||||
+/* This extensions requires no special styling */
|
+/* This extensions requires no special styling */
|
||||||
diff --git a/meson.build b/meson.build
|
diff --git a/meson.build b/meson.build
|
||||||
index 188e19e5..1d94882f 100644
|
index 41a7e99d..f754767c 100644
|
||||||
--- a/meson.build
|
--- a/meson.build
|
||||||
+++ b/meson.build
|
+++ b/meson.build
|
||||||
@@ -45,6 +45,7 @@ all_extensions = default_extensions
|
@@ -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>
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||||
Date: Wed, 20 May 2015 18:05:41 +0200
|
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 +++++++++++++++++
|
extensions/dash-to-dock/Settings.ui | 2660 +++++++++++++++++
|
||||||
@ -29865,7 +29865,7 @@ index 00000000..8cb14b88
|
|||||||
+});
|
+});
|
||||||
\ No newline at end of file
|
\ No newline at end of file
|
||||||
diff --git a/meson.build b/meson.build
|
diff --git a/meson.build b/meson.build
|
||||||
index 1d94882f..e3a64a92 100644
|
index f754767c..e3d94918 100644
|
||||||
--- a/meson.build
|
--- a/meson.build
|
||||||
+++ b/meson.build
|
+++ b/meson.build
|
||||||
@@ -44,6 +44,7 @@ default_extensions += [
|
@@ -44,6 +44,7 @@ default_extensions += [
|
||||||
@ -44398,13 +44398,13 @@ index 6a40e212..14e60ccb 100644
|
|||||||
+#~ msgid "0.000"
|
+#~ msgid "0.000"
|
||||||
+#~ msgstr "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>
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||||
Date: Wed, 20 May 2015 18:55:47 +0200
|
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 ++++++++++++++++++++
|
extensions/panel-favorites/extension.js | 257 ++++++++++++++++++++
|
||||||
@ -44729,7 +44729,7 @@ index 00000000..120adacb
|
|||||||
+ -y-offset: 6px;
|
+ -y-offset: 6px;
|
||||||
+}
|
+}
|
||||||
diff --git a/meson.build b/meson.build
|
diff --git a/meson.build b/meson.build
|
||||||
index e3a64a92..47b6c46c 100644
|
index e3d94918..12706001 100644
|
||||||
--- a/meson.build
|
--- a/meson.build
|
||||||
+++ b/meson.build
|
+++ b/meson.build
|
||||||
@@ -46,6 +46,7 @@ all_extensions += [
|
@@ -46,6 +46,7 @@ all_extensions += [
|
||||||
@ -44741,13 +44741,13 @@ index e3a64a92..47b6c46c 100644
|
|||||||
'user-theme'
|
'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>
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||||
Date: Fri, 4 Mar 2016 17:07:21 +0100
|
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 ++++++++++++++++++
|
extensions/updates-dialog/extension.js | 504 ++++++++++++++++++
|
||||||
@ -45347,7 +45347,7 @@ index 00000000..25134b65
|
|||||||
@@ -0,0 +1 @@
|
@@ -0,0 +1 @@
|
||||||
+/* This extensions requires no special styling */
|
+/* This extensions requires no special styling */
|
||||||
diff --git a/meson.build b/meson.build
|
diff --git a/meson.build b/meson.build
|
||||||
index 47b6c46c..c54ef777 100644
|
index 12706001..c609ae52 100644
|
||||||
--- a/meson.build
|
--- a/meson.build
|
||||||
+++ b/meson.build
|
+++ b/meson.build
|
||||||
@@ -48,6 +48,7 @@ all_extensions += [
|
@@ -48,6 +48,7 @@ all_extensions += [
|
||||||
@ -45372,13 +45372,13 @@ index 0ed12762..10b1d517 100644
|
|||||||
extensions/window-list/extension.js
|
extensions/window-list/extension.js
|
||||||
extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml
|
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>
|
From: Carlos Soriano <csoriano@gnome.org>
|
||||||
Date: Mon, 13 Aug 2018 17:28:41 +0200
|
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 +++
|
.../desktop-icons/createFolderDialog.js | 165 +++
|
||||||
@ -56921,7 +56921,7 @@ index 00000000..a468f4ab
|
|||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
diff --git a/meson.build b/meson.build
|
diff --git a/meson.build b/meson.build
|
||||||
index c54ef777..08213618 100644
|
index c609ae52..b83f0795 100644
|
||||||
--- a/meson.build
|
--- a/meson.build
|
||||||
+++ b/meson.build
|
+++ b/meson.build
|
||||||
@@ -28,6 +28,7 @@ uuid_suffix = '@gnome-shell-extensions.gcampax.github.com'
|
@@ -28,6 +28,7 @@ uuid_suffix = '@gnome-shell-extensions.gcampax.github.com'
|
||||||
@ -66729,13 +66729,13 @@ index 14e60ccb..4bdf7154 100644
|
|||||||
+#~ msgid "Huge"
|
+#~ msgid "Huge"
|
||||||
+#~ msgstr "巨大圖示"
|
+#~ 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>
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||||
Date: Thu, 2 Dec 2021 19:39:50 +0100
|
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 ++++++++++++++++++
|
extensions/classification-banner/adwShim.js | 202 ++++++++++++++++++
|
||||||
@ -67417,7 +67417,7 @@ index 00000000..fb6a697e
|
|||||||
+.classification-message { font-weight: bold; }
|
+.classification-message { font-weight: bold; }
|
||||||
+.classification-banner { font-size: 0.9em; }
|
+.classification-banner { font-size: 0.9em; }
|
||||||
diff --git a/meson.build b/meson.build
|
diff --git a/meson.build b/meson.build
|
||||||
index 08213618..dea0a409 100644
|
index b83f0795..c71636cb 100644
|
||||||
--- a/meson.build
|
--- a/meson.build
|
||||||
+++ b/meson.build
|
+++ b/meson.build
|
||||||
@@ -45,6 +45,7 @@ default_extensions += [
|
@@ -45,6 +45,7 @@ default_extensions += [
|
||||||
@ -67429,5 +67429,789 @@ index 08213618..dea0a409 100644
|
|||||||
'native-window-placement',
|
'native-window-placement',
|
||||||
'panel-favorites',
|
'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
|
||||||
|
|
||||||
|
116
SOURCES/window-list-touch.patch
Normal file
116
SOURCES/window-list-touch.patch
Normal 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
|
||||||
|
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
Name: gnome-shell-extensions
|
Name: gnome-shell-extensions
|
||||||
Version: 40.7
|
Version: 40.7
|
||||||
Release: 2%{?dist}
|
Release: 7%{?dist}
|
||||||
Summary: Modify and extend GNOME Shell functionality and behavior
|
Summary: Modify and extend GNOME Shell functionality and behavior
|
||||||
|
|
||||||
License: GPLv2+
|
License: GPLv2+
|
||||||
@ -33,6 +33,13 @@ Patch010: 0001-heads-up-display-Add-extension-for-showing-persisten.patch
|
|||||||
Patch011: 0001-Add-gesture-inhibitor-extension.patch
|
Patch011: 0001-Add-gesture-inhibitor-extension.patch
|
||||||
Patch012: gnome-classic-wayland.patch
|
Patch012: gnome-classic-wayland.patch
|
||||||
Patch013: 0001-desktop-icons-Fix-stuck-grab-issue-with-rubber-bandi.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
|
%description
|
||||||
GNOME Shell Extensions is a collection of extensions providing additional and
|
GNOME Shell Extensions is a collection of extensions providing additional and
|
||||||
@ -42,6 +49,7 @@ Enabled extensions:
|
|||||||
* apps-menu
|
* apps-menu
|
||||||
* auto-move-windows
|
* auto-move-windows
|
||||||
* classification-banner
|
* classification-banner
|
||||||
|
* custom-menu
|
||||||
* dash-to-dock
|
* dash-to-dock
|
||||||
* desktop-icons
|
* desktop-icons
|
||||||
* drive-menu
|
* drive-menu
|
||||||
@ -119,6 +127,16 @@ Requires: %{pkg_prefix}-common = %{version}-%{release}
|
|||||||
This GNOME Shell extension adds a banner that displays the classification level.
|
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
|
%package -n %{pkg_prefix}-dash-to-dock
|
||||||
Summary: Show the dash outside the activities overview
|
Summary: Show the dash outside the activities overview
|
||||||
License: GPLv2+
|
License: GPLv2+
|
||||||
@ -328,6 +346,10 @@ workspaces.
|
|||||||
%{_datadir}/gnome-shell/extensions/classification-banner*/
|
%{_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
|
%files -n %{pkg_prefix}-dash-to-dock
|
||||||
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml
|
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml
|
||||||
%{_datadir}/gnome-shell/extensions/dash-to-dock*/
|
%{_datadir}/gnome-shell/extensions/dash-to-dock*/
|
||||||
@ -406,6 +428,32 @@ workspaces.
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%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
|
* Fri May 13 2022 Florian Müllner <fmuellner@redhat.com> - 40.7-2
|
||||||
- Require desktop-icons for classic session
|
- Require desktop-icons for classic session
|
||||||
Resolves: #2047697
|
Resolves: #2047697
|
||||||
|
Loading…
Reference in New Issue
Block a user