import gnome-shell-extensions-3.32.1-38.el8

c8-beta imports/c8-beta/gnome-shell-extensions-3.32.1-38.el8
MSVSphere Packaging Team 6 months ago
commit edfced6fd9

1
.gitignore vendored

@ -0,0 +1 @@
SOURCES/gnome-shell-extensions-3.32.1.tar.xz

@ -0,0 +1 @@
51c1c16bcd0dc9125834b32d7c539c38fa9c4f52 SOURCES/gnome-shell-extensions-3.32.1.tar.xz

@ -0,0 +1,186 @@
From 2a498fef3ec02d834346b545aeacba0a6224494e Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Thu, 28 Jan 2021 00:06:12 +0100
Subject: [PATCH] Add gesture-inhibitor extension
This extension may disable default GNOME Shell gestures.
---
extensions/gesture-inhibitor/extension.js | 75 +++++++++++++++++++
extensions/gesture-inhibitor/meson.build | 8 ++
extensions/gesture-inhibitor/metadata.json.in | 12 +++
...l.extensions.gesture-inhibitor.gschema.xml | 25 +++++++
extensions/gesture-inhibitor/stylesheet.css | 1 +
meson.build | 1 +
6 files changed, 122 insertions(+)
create mode 100644 extensions/gesture-inhibitor/extension.js
create mode 100644 extensions/gesture-inhibitor/meson.build
create mode 100644 extensions/gesture-inhibitor/metadata.json.in
create mode 100644 extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
create mode 100644 extensions/gesture-inhibitor/stylesheet.css
diff --git a/extensions/gesture-inhibitor/extension.js b/extensions/gesture-inhibitor/extension.js
new file mode 100644
index 00000000..e74ede2f
--- /dev/null
+++ b/extensions/gesture-inhibitor/extension.js
@@ -0,0 +1,75 @@
+/* extension.js
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/* exported init */
+
+const Clutter = imports.gi.Clutter;
+const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
+const ViewSelector = imports.ui.viewSelector;
+const EdgeDragAction = imports.ui.edgeDragAction;
+const WindowManager = imports.ui.windowManager;
+const St = imports.gi.St;
+const Gio = imports.gi.Gio;
+
+class Extension {
+ constructor() {
+ this._settings = ExtensionUtils.getSettings();
+ let actions = global.stage.get_actions();
+
+ actions.forEach(a => {
+ if (a instanceof ViewSelector.ShowOverviewAction)
+ this._showOverview = a;
+ else if (a instanceof WindowManager.AppSwitchAction)
+ this._appSwitch = a;
+ else if (a instanceof EdgeDragAction.EdgeDragAction &&
+ a._side == St.Side.BOTTOM)
+ this._showOsk = a;
+ else if (a instanceof EdgeDragAction.EdgeDragAction &&
+ a._side == St.Side.TOP)
+ this._unfullscreen = a;
+ else if (a instanceof EdgeDragAction.EdgeDragAction)
+ this._showAppGrid = a;
+ });
+
+ this._map = [
+ { setting: 'overview', action: this._showOverview },
+ { setting: 'app-switch', action: this._appSwitch },
+ { setting: 'show-osk', action: this._showOsk },
+ { setting: 'unfullscreen', action: this._unfullscreen },
+ { setting: 'show-app-grid', action: this._showAppGrid }
+ ];
+ }
+
+ enable() {
+ this._map.forEach(m => {
+ this._settings.bind(m.setting, m.action, 'enabled',
+ Gio.SettingsBindFlags.DEFAULT);
+ });
+ }
+
+ disable() {
+ this._map.forEach(m => {
+ m.action.enabled = true;
+ });
+ }
+}
+
+function init() {
+ return new Extension();
+}
diff --git a/extensions/gesture-inhibitor/meson.build b/extensions/gesture-inhibitor/meson.build
new file mode 100644
index 00000000..fdad5cc8
--- /dev/null
+++ b/extensions/gesture-inhibitor/meson.build
@@ -0,0 +1,8 @@
+extension_data += configure_file(
+ input: metadata_name + '.in',
+ output: metadata_name,
+ configuration: metadata_conf
+)
+
+# extension_sources += files('prefs.js')
+extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
diff --git a/extensions/gesture-inhibitor/metadata.json.in b/extensions/gesture-inhibitor/metadata.json.in
new file mode 100644
index 00000000..37d6a117
--- /dev/null
+++ b/extensions/gesture-inhibitor/metadata.json.in
@@ -0,0 +1,12 @@
+{
+ "uuid": "@uuid@",
+ "extension-id": "@extension_id@",
+ "settings-schema": "@gschemaname@",
+ "gettext-domain": "@gettext_domain@",
+ "name": "Gesture Inhibitor",
+ "description": "Makes touchscreen gestures optional.",
+ "shell-version": [ "@shell_current@" ],
+ "original-authors": [ "cgarnach@redhat.com" ],
+ "url": "@url@"
+}
+
diff --git a/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
new file mode 100644
index 00000000..1d67dcc0
--- /dev/null
+++ b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
@@ -0,0 +1,25 @@
+<schemalist>
+ <schema id="org.gnome.shell.extensions.gesture-inhibitor" path="/org/gnome/shell/extensions/gesture-inhibitor/">
+ <key name="show-app-grid" type="b">
+ <default>true</default>
+ <summary>Show app grid gesture</summary>
+ </key>
+ <key name="show-osk" type="b">
+ <default>true</default>
+ <summary>Show OSK gesture</summary>
+ </key>
+ <key name="overview" type="b">
+ <default>true</default>
+ <summary>Show Overview gesture</summary>
+ </key>
+ <key name="app-switch" type="b">
+ <default>true</default>
+ <summary>Application switch gesture</summary>
+ </key>
+ <key name="unfullscreen" type="b">
+ <default>true</default>
+ <summary>Unfullscreen gesture</summary>
+ </key>
+ </schema>
+</schemalist>
+
diff --git a/extensions/gesture-inhibitor/stylesheet.css b/extensions/gesture-inhibitor/stylesheet.css
new file mode 100644
index 00000000..37b93f21
--- /dev/null
+++ b/extensions/gesture-inhibitor/stylesheet.css
@@ -0,0 +1 @@
+/* Add your custom extension styling here */
diff --git a/meson.build b/meson.build
index e163b84d..ba84f8f3 100644
--- a/meson.build
+++ b/meson.build
@@ -55,6 +55,7 @@ all_extensions += [
'dash-to-dock',
'dash-to-panel',
'disable-screenshield',
+ 'gesture-inhibitor',
'native-window-placement',
'no-hot-corner',
'panel-favorites',
--
2.32.0

@ -0,0 +1,32 @@
From a3db60786407481efbfc4875f887d03b58f0a7b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 23 Feb 2018 16:56:46 +0100
Subject: [PATCH] Include top-icons in classic session
---
meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index 6764f9a..32743ed 100644
--- a/meson.build
+++ b/meson.build
@@ -36,6 +36,7 @@ classic_extensions = [
'desktop-icons',
'places-menu',
'launch-new-instance',
+ 'top-icons',
'window-list'
]
@@ -56,7 +57,6 @@ all_extensions += [
'no-hot-corner',
'panel-favorites',
'systemMonitor',
- 'top-icons',
'updates-dialog',
'user-theme',
'window-grouper'
--
2.21.0

@ -0,0 +1,83 @@
From f5e47cd8ca32ae433f6906b01a509c5a304894d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sat, 24 Oct 2020 01:14:44 +0200
Subject: [PATCH] Update desktop-icons gettext domain
---
extensions/desktop-icons/createFolderDialog.js | 2 +-
extensions/desktop-icons/desktopGrid.js | 2 +-
extensions/desktop-icons/fileItem.js | 2 +-
extensions/desktop-icons/prefs.js | 8 +++++---
4 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/extensions/desktop-icons/createFolderDialog.js b/extensions/desktop-icons/createFolderDialog.js
index f3e40e9..5038762 100644
--- a/extensions/desktop-icons/createFolderDialog.js
+++ b/extensions/desktop-icons/createFolderDialog.js
@@ -21,7 +21,7 @@ const { Clutter, GObject, GLib, Gio, St } = imports.gi;
const Signals = imports.signals;
const Dialog = imports.ui.dialog;
-const Gettext = imports.gettext.domain('desktop-icons');
+const Gettext = imports.gettext.domain('gnome-shell-extensions');
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js
index a2d1f12..94d2dfd 100644
--- a/extensions/desktop-icons/desktopGrid.js
+++ b/extensions/desktop-icons/desktopGrid.js
@@ -44,7 +44,7 @@ const Util = imports.misc.util;
const Clipboard = St.Clipboard.get_default();
const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD;
-const Gettext = imports.gettext.domain('desktop-icons');
+const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
index 0c6a54d..d6d43c9 100644
--- a/extensions/desktop-icons/fileItem.js
+++ b/extensions/desktop-icons/fileItem.js
@@ -42,7 +42,7 @@ const Prefs = Me.imports.prefs;
const DBusUtils = Me.imports.dbusUtils;
const DesktopIconsUtil = Me.imports.desktopIconsUtil;
-const Gettext = imports.gettext.domain('desktop-icons');
+const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
diff --git a/extensions/desktop-icons/prefs.js b/extensions/desktop-icons/prefs.js
index 4b8d986..51daf15 100644
--- a/extensions/desktop-icons/prefs.js
+++ b/extensions/desktop-icons/prefs.js
@@ -26,7 +26,7 @@ const Gettext = imports.gettext;
const Config = imports.misc.config;
-var _ = Gettext.domain('desktop-icons').gettext;
+var _ = Gettext.domain('gnome-shell-extensions').gettext;
const SCHEMA_NAUTILUS = 'org.gnome.nautilus.preferences';
const SCHEMA_GTK = 'org.gtk.Settings.FileChooser';
@@ -51,11 +51,13 @@ var CLICK_POLICY_SINGLE = false;
function initTranslations() {
let extension = ExtensionUtils.getCurrentExtension();
+ let domain = extension.metadata['gettext-domain'] || 'desktop-icons';
+
let localedir = extension.dir.get_child('locale');
if (localedir.query_exists(null))
- Gettext.bindtextdomain('desktop-icons', localedir.get_path());
+ Gettext.bindtextdomain(domain, localedir.get_path());
else
- Gettext.bindtextdomain('desktop-icons', Config.LOCALEDIR);
+ Gettext.bindtextdomain(domain, Config.LOCALEDIR);
}
function init() {
--
2.21.1

@ -0,0 +1,98 @@
From e768ad73e2d68b3f1567051675ba0539a75e3105 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sat, 18 May 2019 19:37:05 +0200
Subject: [PATCH] Update style
---
data/gnome-shell-sass | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Submodule data/gnome-shell-sass 1a56956..8842e57:
diff --git a/data/gnome-shell-sass/_common.scss b/data/gnome-shell-sass/_common.scss
index a6357ba..62d9c82 100644
--- a/data/gnome-shell-sass/_common.scss
+++ b/data/gnome-shell-sass/_common.scss
@@ -571,6 +571,18 @@ StScrollBar {
app menu inside the main app window itself rather than the top bar
*/
+/*************
+ * App Icons *
+ *************/
+/* Outline for low res icons */
+.lowres-icon {
+ icon-shadow: 0 1px 2px rgba(0,0,0,0.3);
+}
+
+/* Drapshadow for large icons */
+.icon-dropshadow {
+ icon-shadow: 0 1px 2px rgba(0,0,0,0.4);
+}
/* OSD */
.osd-window {
@@ -680,7 +692,8 @@ StScrollBar {
spacing: 8px;
}
- .ws-switcher-active-up, .ws-switcher-active-down {
+ .ws-switcher-active-up, .ws-switcher-active-down,
+ .ws-switcher-active-left, .ws-switcher-active-right {
height: 50px;
background-color: $selected_bg_color;
color: $selected_fg_color;
@@ -781,6 +794,11 @@ StScrollBar {
color: lighten($fg_color,10%);
}
+ .panel-logo-icon {
+ padding-right: .4em;
+ icon-size: 1em;
+ }
+
.system-status-icon { icon-size: 1.09em; padding: 0 5px; }
.unlock-screen &,
.login-screen &,
@@ -1406,6 +1424,14 @@ StScrollBar {
}
+ .app-well-hover-text {
+ text-align: center;
+ color: $osd_fg_color;
+ background-color: $osd_bg_color;
+ border-radius: 5px;
+ padding: 3px;
+ }
+
.app-well-app-running-dot { //running apps indicator
width: 10px; height: 3px;
background-color: $selected_bg_color;
@@ -1801,7 +1827,12 @@ StScrollBar {
.login-dialog-banner { color: darken($osd_fg_color,10%); }
.login-dialog-button-box { spacing: 5px; }
.login-dialog-message-warning { color: $warning_color; }
- .login-dialog-message-hint { padding-top: 0; padding-bottom: 20px; }
+ .login-dialog-message-hint, .login-dialog-message {
+ color: darken($osd_fg_color, 20%);
+ padding-top: 0;
+ padding-bottom: 20px;
+ min-height: 2.75em;
+ }
.login-dialog-user-selection-box { padding: 100px 0px; }
.login-dialog-not-listed-label {
padding-left: 2px;
@@ -1856,6 +1887,10 @@ StScrollBar {
padding-bottom: 12px;
spacing: 8px;
width: 23em;
+ .login-dialog-timed-login-indicator {
+ height: 2px;
+ background-color: darken($fg_color,40%);
+ }
}
.login-dialog-prompt-label {
--
2.21.0

@ -0,0 +1,33 @@
From 0bbeadadc41128b2be1f2b56c60b5a7a671d40da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 27 Jun 2019 03:57:53 +0200
Subject: [PATCH] apps-menu: Add missing chain-up
PanelMenu.Button is a bit weird in that it also "contains" its parent
actor. That container is supposed to be destroyed with the button, but
as we currently don't chain up to the parent class' _onDestroy(), we
leave behind an empty container every time the extension is disabled.
Fix this by adding the missing chain-up.
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/75
---
extensions/apps-menu/extension.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index b9e7111..9803cc1 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -433,6 +433,8 @@ class ApplicationsButton extends PanelMenu.Button {
}
_onDestroy() {
+ super._onDestroy();
+
Main.overview.disconnect(this._showingId);
Main.overview.disconnect(this._hidingId);
appSys.disconnect(this._installedChangedId);
--
2.21.0

@ -0,0 +1,40 @@
From 52ee25effa3debb21307e33ac223cf48ac7bc57a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 17 Mar 2016 17:15:38 +0100
Subject: [PATCH] apps-menu: Explicitly set label_actor
For some reason orca fails to pick up the label of category items,
so set the label_actor explicitly as workaround.
---
extensions/apps-menu/extension.js | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index d62e3d7..cc399c6 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -29,7 +29,9 @@ class ActivitiesMenuItem extends PopupMenu.PopupBaseMenuItem {
constructor(button) {
super();
this._button = button;
- this.actor.add_child(new St.Label({ text: _('Activities Overview') }));
+ let label = new St.Label({ text: _('Activities Overview') });
+ this.actor.add_child(label);
+ this.actor.label_actor = label;
}
activate(event) {
@@ -120,7 +122,9 @@ class CategoryMenuItem extends PopupMenu.PopupBaseMenuItem {
else
name = _('Favorites');
- this.actor.add_child(new St.Label({ text: name }));
+ let label = new St.Label({ text: name });
+ this.actor.add_child(label);
+ this.actor.label_actor = label;
this.actor.connect('motion-event', this._onMotionEvent.bind(this));
}
--
2.21.0

@ -0,0 +1,32 @@
From 3e3634b59455da0cbae1de4af0ce5cf97be8b80d Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 21 Jan 2014 16:48:17 -0500
Subject: [PATCH] apps-menu: add logo icon to Applications menu
Brand requested it.
---
extensions/apps-menu/extension.js | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index d7ba570..d62e3d7 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -390,6 +390,14 @@ class ApplicationsButton extends PanelMenu.Button {
let hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
+ let iconFile = Gio.File.new_for_path(
+ '/usr/share/icons/hicolor/scalable/apps/start-here.svg');
+ this._icon = new St.Icon({
+ gicon: new Gio.FileIcon({ file: iconFile }),
+ style_class: 'panel-logo-icon'
+ });
+ hbox.add_actor(this._icon);
+
this._label = new St.Label({
text: _('Applications'),
y_expand: true,
--
2.21.0

@ -0,0 +1,33 @@
From 8a5e793b3d984f3acc378cf8914410311e9dde0e Mon Sep 17 00:00:00 2001
From: Daniel van Vugt <daniel.van.vugt@canonical.com>
Date: Thu, 28 Jan 2021 16:33:50 +0800
Subject: [PATCH] auto-move-windows: Don't move windows already on all
workspaces
This fixes a particular case of mutter#992.
Although gnome-shell will also be softened to not crash in future, it's
also a good idea for the extension to explicitly decide how it wants to
handle windows that are already on all workspaces.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/157>
---
extensions/auto-move-windows/extension.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/auto-move-windows/extension.js b/extensions/auto-move-windows/extension.js
index b9bc3a0..3859809 100644
--- a/extensions/auto-move-windows/extension.js
+++ b/extensions/auto-move-windows/extension.js
@@ -72,7 +72,7 @@ class WindowMover {
}
_moveWindow(window, workspaceNum) {
- if (window.skip_taskbar)
+ if (window.skip_taskbar || window.is_on_all_workspaces())
return;
// ensure we have the required number of workspaces
--
2.37.1

@ -0,0 +1,68 @@
From 3d32ab1848011a3a7af97255307b3541a7553b09 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 6c2fe007..1cf03b3f 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;
+
if (this._settings)
this._settings.run_dispose();
this._settings = null;
@@ -95,6 +98,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',
@@ -111,6 +119,12 @@ class ClassificationBanner extends Clutter.Actor {
return `${key}: rgba(${red},${green},${blue},${alpha / 255});`;
}
+ _updateMonitorConstraint() {
+ const {index} = this._monitorConstraint;
+ this._monitorConstraint.work_area =
+ !global.display.get_monitor_in_fullscreen(index);
+ }
+
_updateStyles() {
const bgStyle = this._getColorSetting('background-color');
const fgStyle = this._getColorSetting('color');
--
2.38.1

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

@ -0,0 +1,208 @@
From 3c62051c0a154ae987bb0126e8adb6cd86aa69a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 24 Feb 2020 16:17:05 +0100
Subject: [PATCH] dashToDock: Handle no-overview case
There is no longer an overview in GNOME Classic, so in order to be
used in that environment, the extension must deal with that case.
---
extensions/dash-to-dock/docking.js | 122 ++++++++++++++++-------------
1 file changed, 68 insertions(+), 54 deletions(-)
diff --git a/extensions/dash-to-dock/docking.js b/extensions/dash-to-dock/docking.js
index d35094b..2b8353a 100644
--- a/extensions/dash-to-dock/docking.js
+++ b/extensions/dash-to-dock/docking.js
@@ -233,7 +233,7 @@ var DockedDash = class DashToDock {
// Create a new dash object
this.dash = new MyDash.MyDash(this._settings, this._remoteModel, this._monitorIndex);
- if (!this._settings.get_boolean('show-show-apps-button'))
+ if (Main.overview.isDummy || !this._settings.get_boolean('show-show-apps-button'))
this.dash.hideShowAppsButton();
// Create the main actor and the containers for sliding in and out and
@@ -272,45 +272,11 @@ var DockedDash = class DashToDock {
this.dash.actor.add_constraint(this.constrainSize);
this._signalsHandler.add([
- Main.overview,
- 'item-drag-begin',
- this._onDragStart.bind(this)
- ], [
- Main.overview,
- 'item-drag-end',
- this._onDragEnd.bind(this)
- ], [
- Main.overview,
- 'item-drag-cancelled',
- this._onDragEnd.bind(this)
- ], [
// update when workarea changes, for instance if other extensions modify the struts
//(like moving th panel at the bottom)
global.display,
'workareas-changed',
this._resetPosition.bind(this)
- ], [
- Main.overview,
- 'showing',
- this._onOverviewShowing.bind(this)
- ], [
- Main.overview,
- 'hiding',
- this._onOverviewHiding.bind(this)
- ], [
- // Hide on appview
- Main.overview.viewSelector,
- 'page-changed',
- this._pageChanged.bind(this)
- ], [
- Main.overview.viewSelector,
- 'page-empty',
- this._onPageEmpty.bind(this)
- ], [
- // Ensure the ShowAppsButton status is kept in sync
- Main.overview.viewSelector._showAppsButton,
- 'notify::checked',
- this._syncShowAppsButtonToggled.bind(this)
], [
global.display,
'in-fullscreen-changed',
@@ -325,15 +291,6 @@ var DockedDash = class DashToDock {
this.dash,
'icon-size-changed',
() => { Main.overview.dashIconSize = this.dash.iconSize; }
- ], [
- // This duplicate the similar signal which is in owerview.js.
- // Being connected and thus executed later this effectively
- // overwrite any attempt to use the size of the default dash
- //which given the customization is usually much smaller.
- // I can't easily disconnect the original signal
- Main.overview._controls.dash,
- 'icon-size-changed',
- () => { Main.overview.dashIconSize = this.dash.iconSize; }
], [
// sync hover after a popupmenu is closed
this.dash,
@@ -341,6 +298,53 @@ var DockedDash = class DashToDock {
() => { this._box.sync_hover() }
]);
+ if (!Main.overview.isDummy) {
+ this._signalsHandler.add([
+ Main.overview,
+ 'item-drag-begin',
+ this._onDragStart.bind(this)
+ ], [
+ Main.overview,
+ 'item-drag-end',
+ this._onDragEnd.bind(this)
+ ], [
+ Main.overview,
+ 'item-drag-cancelled',
+ this._onDragEnd.bind(this)
+ ], [
+ Main.overview,
+ 'showing',
+ this._onOverviewShowing.bind(this)
+ ], [
+ Main.overview,
+ 'hiding',
+ this._onOverviewHiding.bind(this)
+ ], [
+ // Hide on appview
+ Main.overview.viewSelector,
+ 'page-changed',
+ this._pageChanged.bind(this)
+ ], [
+ Main.overview.viewSelector,
+ 'page-empty',
+ this._onPageEmpty.bind(this)
+ ], [
+ // Ensure the ShowAppsButton status is kept in sync
+ Main.overview.viewSelector._showAppsButton,
+ 'notify::checked',
+ this._syncShowAppsButtonToggled.bind(this)
+ ], [
+ // This duplicate the similar signal which is in owerview.js.
+ // Being connected and thus executed later this effectively
+ // overwrite any attempt to use the size of the default dash
+ //which given the customization is usually much smaller.
+ // I can't easily disconnect the original signal
+ Main.overview._controls.dash,
+ 'icon-size-changed',
+ () => { Main.overview.dashIconSize = this.dash.iconSize; }
+ ]);
+ }
+
this._injectionsHandler = new Utils.InjectionsHandler();
this._themeManager = new Theming.ThemeManager(this._settings, this);
@@ -370,14 +374,17 @@ var DockedDash = class DashToDock {
this._dashSpacer = new OverviewControls.DashSpacer();
this._dashSpacer.setDashActor(this._box);
- if (this._position == St.Side.LEFT)
- Main.overview._controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? -1 : 0); // insert on first
- else if (this._position == St.Side.RIGHT)
- Main.overview._controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? 0 : -1); // insert on last
- else if (this._position == St.Side.TOP)
- Main.overview._overview.insert_child_at_index(this._dashSpacer, 0);
- else if (this._position == St.Side.BOTTOM)
- Main.overview._overview.insert_child_at_index(this._dashSpacer, -1);
+ if (!Main.overview.isDummy) {
+ const { _controls, _overview } = Main.overview;
+ if (this._position == St.Side.LEFT)
+ _controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? -1 : 0); // insert on first
+ else if (this._position == St.Side.RIGHT)
+ _controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? 0 : -1); // insert on last
+ else if (this._position == St.Side.TOP)
+ _overview.insert_child_at_index(this._dashSpacer, 0);
+ else if (this._position == St.Side.BOTTOM)
+ _overview.insert_child_at_index(this._dashSpacer, -1);
+ }
// Add dash container actor and the container to the Chrome.
this.actor.set_child(this._slider);
@@ -412,7 +419,7 @@ var DockedDash = class DashToDock {
// Since Gnome 3.8 dragging an app without having opened the overview before cause the attemp to
//animate a null target since some variables are not initialized when the viewSelector is created
- if (Main.overview.viewSelector._activePage == null)
+ if (!Main.overview.isDummy && Main.overview.viewSelector._activePage == null)
Main.overview.viewSelector._activePage = Main.overview.viewSelector._workspacesPage;
this._updateVisibilityMode();
@@ -493,7 +500,8 @@ var DockedDash = class DashToDock {
this._settings,
'changed::show-show-apps-button',
() => {
- if (this._settings.get_boolean('show-show-apps-button'))
+ if (!Main.overview.isDummy &&
+ this._settings.get_boolean('show-show-apps-button'))
this.dash.showShowAppsButton();
else
this.dash.hideShowAppsButton();
@@ -1681,6 +1689,9 @@ var DockManager = class DashToDock_DockManager {
// set stored icon size to the new dash
Main.overview.dashIconSize = this._allDocks[0].dash.iconSize;
+ if (Main.overview.isDummy)
+ return;
+
// Hide usual Dash
Main.overview._controls.dash.actor.hide();
@@ -1707,6 +1718,9 @@ var DockManager = class DashToDock_DockManager {
}
_restoreDash() {
+ if (Main.overview.isDummy)
+ return;
+
Main.overview._controls.dash.actor.show();
Main.overview._controls.dash.actor.set_width(-1); //reset default dash size
// This force the recalculation of the icon size
--
2.25.0

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

@ -0,0 +1,76 @@
From 93e3e938b322433aff862bbc46f80c60ab7dc2ab 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 | 35 +++++++++++++++++-----
1 file changed, 28 insertions(+), 7 deletions(-)
diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js
index 399aee03..2ce6eefb 100644
--- a/extensions/desktop-icons/desktopManager.js
+++ b/extensions/desktop-icons/desktopManager.js
@@ -53,6 +53,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: {
@@ -221,9 +236,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);
}
@@ -268,14 +281,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);
--
2.38.1

@ -0,0 +1,179 @@
From b334c8c248f849be996963cdafb1b0b69476bdf1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@redhat.com>
Date: Tue, 2 Nov 2021 09:20:11 +0100
Subject: [PATCH] desktop-icons: Fix stuck grab issue with rubber banding
The desktop icons extension can get into a state where the desktop no longer
takes mouse input.
This happens if a user starts a rubber banding operation and then drags
the mouse to somewhere on screen that has a pop up menu, and then pops
the menu up.
This commit addresses the bug by limiting the grab actor to the
backgrounds, and by explicitly ending the rubber banding operation
when one of the icons own menus is shown.
One side effect of limiting the grab actor to the backgrounds, is the
rubber banding code never gets to see motion outside of the backgrounds
anymore. In order to keep drag operations feeling fluid when the user moves
toward the edge of the screen, this commit also overrides the
grab helpers captured-event handler so those motion events keep coming.
We also start to end the rubber band if for any reason the grab it had
was released.
---
extensions/desktop-icons/desktopGrid.js | 1 +
extensions/desktop-icons/desktopManager.js | 75 ++++++++++++++--------
extensions/desktop-icons/fileItem.js | 1 +
3 files changed, 49 insertions(+), 28 deletions(-)
diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js
index 602fa7f..bd27e2a 100644
--- a/extensions/desktop-icons/desktopGrid.js
+++ b/extensions/desktop-icons/desktopGrid.js
@@ -365,6 +365,7 @@ var DesktopGrid = class {
}
_openMenu(x, y) {
+ Extension.desktopManager.endRubberBand();
Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
this.actor._desktopBackgroundMenu.open(BoxPointer.PopupAnimation.NONE);
/* Since the handler is in the press event it needs to ignore the release event
diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js
index a70cd98..c37e1e7 100644
--- a/extensions/desktop-icons/desktopManager.js
+++ b/extensions/desktop-icons/desktopManager.js
@@ -79,6 +79,7 @@ var DesktopManager = GObject.registerClass({
this._queryFileInfoCancellable = null;
this._unixMode = null;
this._writableByOthers = null;
+ this._rubberBandActive = false;
this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._recreateDesktopIcons());
this._rubberBand = new St.Widget({ style_class: 'rubber-band' });
@@ -86,6 +87,20 @@ var DesktopManager = GObject.registerClass({
Main.layoutManager._backgroundGroup.add_child(this._rubberBand);
this._grabHelper = new GrabHelper.GrabHelper(global.stage);
+ let origCapturedEvent = this._grabHelper.onCapturedEvent;
+ this._grabHelper.onCapturedEvent = (event) => {
+ if (event.type() === Clutter.EventType.MOTION) {
+ /* We handle motion events from a captured event handler so we
+ * we can see motion over actors that are on other parts of the
+ * stage.
+ */
+ this._handleMotion(event);
+ return Clutter.EVENT_STOP;
+ }
+
+ return origCapturedEvent.bind(this._grabHelper)(event);
+ };
+
this._addDesktopIcons();
this._monitorDesktopFolder();
@@ -108,30 +123,15 @@ var DesktopManager = GObject.registerClass({
this._initRubberBandColor();
this._updateRubberBand(x, y);
this._rubberBand.show();
- this._grabHelper.grab({ actor: global.stage });
+ this._rubberBandActive = true;
+ this._grabHelper.grab({
+ actor: Main.layoutManager._backgroundGroup,
+ onUngrab: () => this.endRubberBand(false),
+ });
Extension.lockActivitiesButton = true;
this._stageReleaseEventId = global.stage.connect('button-release-event', (actor, event) => {
this.endRubberBand();
});
- this._rubberBandId = global.stage.connect('motion-event', (actor, event) => {
- /* In some cases, when the user starts a rubberband selection and ends it
- * (by releasing the left button) over a window instead of doing it over
- * the desktop, the stage doesn't receive the "button-release" event.
- * This happens currently with, at least, Dash to Dock extension, but
- * it probably also happens with other applications or extensions.
- * To fix this, we also end the rubberband selection if we detect mouse
- * motion in the stage without the left button pressed during a
- * rubberband selection.
- * */
- let button = event.get_state();
- if (!(button & Clutter.ModifierType.BUTTON1_MASK)) {
- this.endRubberBand();
- return;
- }
- [x, y] = event.get_coords();
- this._updateRubberBand(x, y);
- this._updateSelection(x, y);
- });
this._rubberBandTouchId = global.stage.connect('touch-event', (actor, event) => {
// Let x11 pointer emulation do the job on X11
if (!Meta.is_wayland_compositor())
@@ -175,14 +175,37 @@ var DesktopManager = GObject.registerClass({
}
}
- endRubberBand() {
+ _handleMotion(event) {
+ /* In some cases, when the user starts a rubberband selection and ends it
+ * (by releasing the left button) over a window instead of doing it over
+ * the desktop, the stage doesn't receive the "button-release" event.
+ * This happens currently with, at least, Dash to Dock extension, but
+ * it probably also happens with other applications or extensions.
+ * To fix this, we also end the rubberband selection if we detect mouse
+ * motion in the stage without the left button pressed during a
+ * rubberband selection.
+ * */
+ let button = event.get_state();
+ if (!(button & Clutter.ModifierType.BUTTON1_MASK)) {
+ this.endRubberBand();
+ return;
+ }
+ let [x, y] = event.get_coords();
+ this._updateRubberBand(x, y);
+ this._updateSelection(x, y);
+ }
+
+ endRubberBand(ungrab=true) {
+ if (!this._rubberBandActive)
+ return;
+
+ this._rubberBandActive = false;
this._rubberBand.hide();
Extension.lockActivitiesButton = false;
- this._grabHelper.ungrab();
- global.stage.disconnect(this._rubberBandId);
+ if (ungrab)
+ this._grabHelper.ungrab();
global.stage.disconnect(this._rubberBandTouchId);
global.stage.disconnect(this._stageReleaseEventId);
- this._rubberBandId = 0;
this._rubberBandTouchId = 0;
this._stageReleaseEventId = 0;
@@ -760,10 +783,6 @@ var DesktopManager = GObject.registerClass({
global.stage.disconnect(this._stageReleaseEventId);
this._stageReleaseEventId = 0;
- if (this._rubberBandId)
- global.stage.disconnect(this._rubberBandId);
- this._rubberBandId = 0;
-
if (this._rubberBandTouchId)
global.stage.disconnect(this._rubberBandTouchId);
this._rubberBandTouchId = 0;
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
index 1cb47e8..90f326d 100644
--- a/extensions/desktop-icons/fileItem.js
+++ b/extensions/desktop-icons/fileItem.js
@@ -676,6 +676,7 @@ var FileItem = class {
}
_onPressButton(actor, event) {
+ Extension.desktopManager.endRubberBand();
this._updateClickState(event);
let button = this._eventButton(event);
if (button == 3) {
--
2.31.1

@ -0,0 +1,31 @@
From 0a7248c75c084a83852aa3d0e7a36ccebd365b81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 27 Jan 2021 11:51:28 +0100
Subject: [PATCH] desktop-icons: Update Japanese translation
---
po/ja.po | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/po/ja.po b/po/ja.po
index df5646d..4d780b9 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -293,13 +293,8 @@ msgid "Workspace %d"
msgstr "ワークスペース %d"
#: desktopGrid.js:334
-#, fuzzy
msgid "Display Settings"
-msgstr ""
-"#-#-#-#-# ja.po (gnome-shell-extensions master) #-#-#-#-#\n"
-"ディスプレイ設定\n"
-"#-#-#-#-# ja.po (desktop-icons master) #-#-#-#-#\n"
-"ディスプレイの設定"
+msgstr "ディスプレイ設定"
#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
#, fuzzy
--
2.29.2

@ -0,0 +1,28 @@
From 81b5163b43b7d45ca8bc9205476ef67789e283a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 29 Nov 2021 16:48:53 +0100
Subject: [PATCH] desktop-icons: Use a single unique name to access nautilus
... otherwise dbus-daemon will assume that activating one of the
services failed, because its executable exits early (after activating
the primary instance).
---
extensions/desktop-icons/dbusUtils.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/desktop-icons/dbusUtils.js b/extensions/desktop-icons/dbusUtils.js
index 19fe9878..b44ffa59 100644
--- a/extensions/desktop-icons/dbusUtils.js
+++ b/extensions/desktop-icons/dbusUtils.js
@@ -64,7 +64,7 @@ function init() {
FreeDesktopFileManagerProxy = new FreeDesktopFileManagerProxyInterface(
Gio.DBus.session,
- 'org.freedesktop.FileManager1',
+ 'org.gnome.Nautilus',
'/org/freedesktop/FileManager1',
(proxy, error) => {
if (error) {
--
2.33.1

@ -0,0 +1,83 @@
From f78b19068654412ca9e73a229e1537d080759c47 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Wed, 27 Jan 2021 16:55:10 +0100
Subject: [PATCH] fileItem: Ignore double click distance clicking on items
Imitate the behavior of Nautilus canvas WRT double clicks being
handled on all of the icon(s) without accounting for the double
click distance. As the extension does already lean on Nautilus
look & feel, it seems to make sense doing this.
This is not as crucial for mice as it is for touchscreens, where
the default 5px limit may be a bit on the short side depending
on device sensitivity.
---
extensions/desktop-icons/fileItem.js | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
index d6d43c9..5d3195f 100644
--- a/extensions/desktop-icons/fileItem.js
+++ b/extensions/desktop-icons/fileItem.js
@@ -65,6 +65,9 @@ var FileItem = class {
this._setMetadataCancellable = null;
this._queryFileInfoCancellable = null;
this._isSpecial = this._fileExtra != Prefs.FileType.NONE;
+ this._lastClickTime = 0;
+ this._lastClickButton = 0;
+ this._clickCount = 0;
this._file = file;
@@ -642,7 +645,24 @@ var FileItem = class {
DesktopIconsUtil.launchTerminal(this.file.get_path());
}
+ _updateClickState(event) {
+ let settings = Clutter.Settings.get_default();
+ if ((event.get_button() == this._lastClickButton) &&
+ ((event.get_time() - this._lastClickTime) < settings.double_click_time))
+ this._clickCount++;
+ else
+ this._clickCount = 1;
+
+ this._lastClickTime = event.get_time();
+ this._lastClickButton = event.get_button();
+ }
+
+ _getClickCount() {
+ return this._clickCount;
+ }
+
_onPressButton(actor, event) {
+ this._updateClickState(event);
let button = event.get_button();
if (button == 3) {
if (!this.isSelected)
@@ -661,7 +681,7 @@ var FileItem = class {
this._actionTrash.setSensitive(!specialFilesSelected);
return Clutter.EVENT_STOP;
} else if (button == 1) {
- if (event.get_click_count() == 1) {
+ if (this._getClickCount() == 1) {
let [x, y] = event.get_coords();
this._primaryButtonPressed = true;
this._buttonPressInitialX = x;
@@ -710,12 +730,12 @@ var FileItem = class {
this._primaryButtonPressed = false;
let shiftPressed = !!(event.get_state() & Clutter.ModifierType.SHIFT_MASK);
let controlPressed = !!(event.get_state() & Clutter.ModifierType.CONTROL_MASK);
- if ((event.get_click_count() == 1) && Prefs.CLICK_POLICY_SINGLE && !shiftPressed && !controlPressed)
+ if ((this._getClickCount() == 1) && Prefs.CLICK_POLICY_SINGLE && !shiftPressed && !controlPressed)
this.doOpen();
this.emit('selected', shiftPressed || controlPressed, false, true);
return Clutter.EVENT_STOP;
}
- if ((event.get_click_count() == 2) && (!Prefs.CLICK_POLICY_SINGLE))
+ if ((this._getClickCount() == 2) && (!Prefs.CLICK_POLICY_SINGLE))
this.doOpen();
}
return Clutter.EVENT_PROPAGATE;
--
2.29.2

@ -0,0 +1,31 @@
From 506c6d69eaa5e056d9580a28e9c200586b0e1fb0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 2 Dec 2022 15:20:40 +0100
Subject: [PATCH] fileItem: Just destroy menus
The menu manager is smart enough to remove the menu automatically,
and the actor will be destroyed alongside the menu. Not doing those
actions explicitly allows the automatic handling to proceed without
confusing the grab state.
---
extensions/desktop-icons/fileItem.js | 4 ----
1 file changed, 4 deletions(-)
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
index 44a93352..f2f03440 100644
--- a/extensions/desktop-icons/fileItem.js
+++ b/extensions/desktop-icons/fileItem.js
@@ -575,10 +575,6 @@ var FileItem = class {
_removeMenu() {
if (this._menu != null) {
- if (this._menuManager != null)
- this._menuManager.removeMenu(this._menu);
-
- Main.layoutManager.uiGroup.remove_child(this._menu.actor);
this._menu.destroy();
this._menu = null;
}
--
2.38.1

@ -0,0 +1,147 @@
From be4ab59a3f2bb9829dde390db3dd8868a08840eb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 2 Dec 2022 19:28:54 +0100
Subject: [PATCH] fileItem: Support .desktop files of type Link
Gio only has direct support for .desktop files of type Application.
However in the context of desktop icons (and file managers), shortcuts
of URLs are useful as well, so add explicit support for .desktop files
of type Link.
---
extensions/desktop-icons/fileItem.js | 71 +++++++++++++++++++++++-----
1 file changed, 60 insertions(+), 11 deletions(-)
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
index f2f03440..1c9a1e55 100644
--- a/extensions/desktop-icons/fileItem.js
+++ b/extensions/desktop-icons/fileItem.js
@@ -239,12 +239,32 @@ var FileItem = class {
log(`desktop-icons: File ${this._displayName} is writable by others - will not allow launching`);
if (this._isDesktopFile) {
- this._desktopFile = Gio.DesktopAppInfo.new_from_filename(this._file.get_path());
- if (!this._desktopFile) {
- log(`Couldnt parse ${this._displayName} as a desktop file, will treat it as a regular file.`);
+ try {
+ const keyFile = new GLib.KeyFile();
+ keyFile.load_from_file(this._file.get_path(), GLib.KeyFileFlags.NONE);
+
+ const type = keyFile.get_string(
+ GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_TYPE);
+ switch (type) {
+ case GLib.KEY_FILE_DESKTOP_TYPE_APPLICATION:
+ this._desktopFile = Gio.DesktopAppInfo.new_from_keyfile(keyFile);
+ if (!this._desktopFile) {
+ log(`Couldnt parse ${this._displayName} as a desktop file, will treat it as a regular file.`);
+ this._isValidDesktopFile = false;
+ } else {
+ this._isValidDesktopFile = true;
+ }
+ break;
+ case GLib.KEY_FILE_DESKTOP_TYPE_LINK:
+ const url = keyFile.get_string(
+ GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_URL);
+ if (url)
+ this._linkFile = keyFile;
+ default: // fall-through
+ this._isValidDesktopFile = false;
+ }
+ } catch (e) {
this._isValidDesktopFile = false;
- } else {
- this._isValidDesktopFile = true;
}
} else {
this._isValidDesktopFile = false;
@@ -356,8 +376,17 @@ var FileItem = class {
if (this._isBrokenSymlink) {
this._icon.child = this._createEmblemedStIcon(null, 'text-x-generic');
} else {
- if (this.trustedDesktopFile && this._desktopFile.has_key('Icon'))
- this._icon.child = this._createEmblemedStIcon(null, this._desktopFile.get_string('Icon'));
+ let iconName = null;
+
+ try {
+ if (this.trustedDesktopFile)
+ iconName = this._desktopFile.get_string('Icon');
+ else if (this._linkFile)
+ iconName = this._linkFile.get_string(GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_ICON);
+ } catch (e) {}
+
+ if (iconName)
+ this._icon.child = this._createEmblemedStIcon(null, iconName);
else
this._icon.child = this._createEmblemedStIcon(this._fileInfo.get_icon(), null);
}
@@ -411,7 +440,7 @@ var FileItem = class {
itemIcon.add_emblem(Gio.Emblem.new(Gio.ThemedIcon.new('emblem-unreadable')));
else
itemIcon.add_emblem(Gio.Emblem.new(Gio.ThemedIcon.new('emblem-symbolic-link')));
- } else if (this.trustedDesktopFile) {
+ } else if (this.trustedDesktopFile || this._linkFile) {
itemIcon.add_emblem(Gio.Emblem.new(Gio.ThemedIcon.new('emblem-symbolic-link')));
}
@@ -440,6 +469,12 @@ var FileItem = class {
return;
}
+ if (this._linkFile) {
+ this._openUri(this._linkFile.get_string(
+ GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_URL));
+ return;
+ }
+
if (this._attributeCanExecute &&
!this._isDirectory &&
!this._isValidDesktopFile &&
@@ -449,13 +484,17 @@ var FileItem = class {
return;
}
- Gio.AppInfo.launch_default_for_uri_async(this.file.get_uri(),
+ this._openUri(this.file.get_uri());
+ }
+
+ _openUri(uri) {
+ Gio.AppInfo.launch_default_for_uri_async(uri,
null, null,
(source, result) => {
try {
Gio.AppInfo.launch_default_for_uri_finish(result);
} catch (e) {
- log('Error opening file ' + this.file.get_uri() + ': ' + e.message);
+ log('Error opening file ' + uri + ': ' + e.message);
}
}
);
@@ -555,7 +594,9 @@ var FileItem = class {
}
canRename() {
- return !this.trustedDesktopFile && this._fileExtra == Prefs.FileType.NONE;
+ return !this.trustedDesktopFile &&
+ !this._linkFile &&
+ this._fileExtra == Prefs.FileType.NONE;
}
_doOpenWith() {
@@ -819,6 +860,14 @@ var FileItem = class {
if (this.trustedDesktopFile)
return this._desktopFile.get_name();
+ if (this._linkFile) {
+ try {
+ const name = this._linkFile.get_string(
+ GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_NAME);
+ return name;
+ } catch (e) {}
+ }
+
return this._displayName || null;
}
--
2.38.1

@ -0,0 +1,45 @@
From ee89a91a9ac235b69ff3c47af14d702c0309e892 Mon Sep 17 00:00:00 2001
From: Sergio Costas <raster@rastersoft.com>
Date: Thu, 25 Jul 2019 00:12:09 +0200
Subject: [PATCH] general: launch only executable files
Until now, if a file has the "execute" flag, clicking on it will try
to execute it, no matter if it is really an executable. This means
that a non-executable file (like a JPEG picture, or a text file)
won't be opened with its desired application if it has set the
executable flag.
This patch fixes this, by ensuring that the only files that can be
executed when the "execute" flag is set, are the ones that makes
sense to execute.
Fixes https://gitlab.gnome.org/World/ShellExtensions/desktop-icons/issues/144
---
extensions/desktop-icons/fileItem.js | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
index d6d43c9f..44a93352 100644
--- a/extensions/desktop-icons/fileItem.js
+++ b/extensions/desktop-icons/fileItem.js
@@ -440,10 +440,13 @@ var FileItem = class {
return;
}
- if (this._attributeCanExecute && !this._isDirectory && !this._isValidDesktopFile) {
- if (this._execLine)
- Util.spawnCommandLine(this._execLine);
- return;
+ if (this._attributeCanExecute &&
+ !this._isDirectory &&
+ !this._isValidDesktopFile &&
+ Gio.content_type_can_be_executable(this._attributeContentType)) {
+ if (this._execLine)
+ Util.spawnCommandLine(this._execLine);
+ return;
}
Gio.AppInfo.launch_default_for_uri_async(this.file.get_uri(),
--
2.31.1

@ -0,0 +1,51 @@
From ce75829479b1e7bf99e74bf835174e91c8da2276 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 | 5 ++++-
.../org.gnome.shell.extensions.gesture-inhibitor.gschema.xml | 4 ++++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/extensions/gesture-inhibitor/extension.js b/extensions/gesture-inhibitor/extension.js
index e74ede2f..bf02d075 100644
--- a/extensions/gesture-inhibitor/extension.js
+++ b/extensions/gesture-inhibitor/extension.js
@@ -37,6 +37,8 @@ class Extension {
this._showOverview = a;
else if (a instanceof WindowManager.AppSwitchAction)
this._appSwitch = a;
+ else if (a instanceof WindowManager.WorkspaceSwitchAction)
+ this._workspaceSwitch = a;
else if (a instanceof EdgeDragAction.EdgeDragAction &&
a._side == St.Side.BOTTOM)
this._showOsk = a;
@@ -52,7 +54,8 @@ class Extension {
{ setting: 'app-switch', action: this._appSwitch },
{ setting: 'show-osk', action: this._showOsk },
{ setting: 'unfullscreen', action: this._unfullscreen },
- { setting: 'show-app-grid', action: this._showAppGrid }
+ { setting: 'show-app-grid', action: this._showAppGrid },
+ { setting: 'workspace-switch', action: this._workspaceSwitch },
];
}
diff --git a/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml b/extensions/gesture-inhibitor/org.gnome.shell.extensions.gesture-inhibitor.gschema.xml
index 1d67dcc0..a5e97a3d 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
@@ -16,6 +16,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,41 @@
From dfdd10b46d670674d5e0e38f7adcd007f5884822 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Wed, 29 Sep 2021 14:33:25 +0200
Subject: [PATCH] gesture-inhibitor: Put a foot down with self-enabling
gestures
If a gesture (unfullscreen, I'm looking at you) controls its 'enabled'
property, it will bypass the will of this extension. Make it sure that
gestures are forced-off if the extension says so.
---
extensions/gesture-inhibitor/extension.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/extensions/gesture-inhibitor/extension.js b/extensions/gesture-inhibitor/extension.js
index e74ede2..66c706e 100644
--- a/extensions/gesture-inhibitor/extension.js
+++ b/extensions/gesture-inhibitor/extension.js
@@ -59,13 +59,19 @@ class Extension {
enable() {
this._map.forEach(m => {
this._settings.bind(m.setting, m.action, 'enabled',
- Gio.SettingsBindFlags.DEFAULT);
+ Gio.SettingsBindFlags.GET);
+ m.handler = m.action.connect('notify::enabled', () => {
+ if (m.action.enabled && !this._settings.get_boolean(m.setting))
+ m.action.enabled = this._settings.get_boolean(m.setting);
+ });
});
}
disable() {
this._map.forEach(m => {
m.action.enabled = true;
+ if (m.handler > 0)
+ m.action.disconnect(m.handler);
});
}
}
--
2.31.1

@ -0,0 +1,831 @@
From 8da1760af68496c6073be4d6b3c8266b64347925 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 24 Aug 2021 15:03:57 -0400
Subject: [PATCH] heads-up-display: Add extension for showing persistent heads
up display message
---
extensions/heads-up-display/extension.js | 320 ++++++++++++++++++
extensions/heads-up-display/headsUpMessage.js | 150 ++++++++
extensions/heads-up-display/meson.build | 8 +
extensions/heads-up-display/metadata.json.in | 11 +
...ll.extensions.heads-up-display.gschema.xml | 54 +++
extensions/heads-up-display/prefs.js | 175 ++++++++++
extensions/heads-up-display/stylesheet.css | 32 ++
meson.build | 1 +
8 files changed, 751 insertions(+)
create mode 100644 extensions/heads-up-display/extension.js
create mode 100644 extensions/heads-up-display/headsUpMessage.js
create mode 100644 extensions/heads-up-display/meson.build
create mode 100644 extensions/heads-up-display/metadata.json.in
create mode 100644 extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml
create mode 100644 extensions/heads-up-display/prefs.js
create mode 100644 extensions/heads-up-display/stylesheet.css
diff --git a/extensions/heads-up-display/extension.js b/extensions/heads-up-display/extension.js
new file mode 100644
index 00000000..e4ef9e85
--- /dev/null
+++ b/extensions/heads-up-display/extension.js
@@ -0,0 +1,320 @@
+/* exported init enable disable */
+
+
+const Signals = imports.signals;
+
+const {
+ Atk, Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St,
+} = imports.gi;
+
+const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
+
+const Main = imports.ui.main;
+const HeadsUpMessage = Me.imports.headsUpMessage;
+
+const Gettext = imports.gettext.domain('gnome-shell-extensions');
+const _ = Gettext.gettext;
+
+class Extension {
+ constructor() {
+ ExtensionUtils.initTranslations();
+ }
+
+ enable() {
+ this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.heads-up-display');
+ this._idleTimeoutChangedId = this._settings.connect('changed::idle-timeout', this._onIdleTimeoutChanged.bind(this));
+ this._settingsChangedId = this._settings.connect('changed', this._updateMessage.bind(this));
+
+ this._idleMonitor = Meta.IdleMonitor.get_core();
+ this._messageInhibitedUntilIdle = false;
+ this._oldMapWindow = Main.wm._mapWindow;
+ Main.wm._mapWindow = this._mapWindow;
+ this._windowManagerMapId = global.window_manager.connect('map', this._onWindowMap.bind(this));
+
+ if (Main.layoutManager._startingUp)
+ this._startupCompleteId = Main.layoutManager.connect('startup-complete', this._onStartupComplete.bind(this));
+ else
+ this._onStartupComplete(this);
+ }
+
+ disable() {
+ this._dismissMessage();
+
+ if (this._idleWatchId) {
+ this._idleMonitor.remove_watch(this._idleWatchId);
+ this._idleWatchId = 0;
+ }
+
+ if (this._sessionModeUpdatedId) {
+ Main.sessionMode.disconnect(this._sessionModeUpdatedId);
+ this._sessionModeUpdatedId = 0;
+ }
+
+ if (this._overviewShowingId) {
+ Main.overview.disconnect(this._overviewShowingId);
+ this._overviewShowingId = 0;
+ }
+
+ if (this._overviewHiddenId) {
+ Main.overview.disconnect(this._overviewHiddenId);
+ this._overviewHiddenId = 0;
+ }
+
+ if (this._panelConnectionId) {
+ Main.layoutManager.panelBox.disconnect(this._panelConnectionId);
+ this._panelConnectionId = 0;
+ }
+
+ if (this._oldMapWindow) {
+ Main.wm._mapWindow = this._oldMapWindow;
+ this._oldMapWindow = null;
+ }
+
+ if (this._windowManagerMapId) {
+ global.window_manager.disconnect(this._windowManagerMapId);
+ this._windowManagerMapId = 0;
+ }
+
+ if (this._startupCompleteId) {
+ Main.layoutManager.disconnect(this._startupCompleteId);
+ this._startupCompleteId = 0;
+ }
+
+ if (this._settingsChangedId) {
+ this._settings.disconnect(this._settingsChangedId);
+ this._settingsChangedId = 0;
+ }
+ }
+
+ _onWindowMap(shellwm, actor) {
+ let windowObject = actor.meta_window;
+ let windowType = windowObject.get_window_type();
+
+ if (windowType != Meta.WindowType.NORMAL)
+ return;
+
+ if (!this._message || !this._message.visible)
+ return;
+
+ let messageRect = new Meta.Rectangle({ x: this._message.x, y: this._message.y, width: this._message.width, height: this._message.height });
+ let windowRect = windowObject.get_frame_rect();
+
+ if (windowRect.intersect(messageRect)) {
+ windowObject.move_frame(false, windowRect.x, this._message.y + this._message.height);
+ }
+ }
+
+ _onStartupComplete() {
+ this._overviewShowingId = Main.overview.connect('showing', this._updateMessage.bind(this));
+ this._overviewHiddenId = Main.overview.connect('hidden', this._updateMessage.bind(this));
+ this._panelConnectionId = Main.layoutManager.panelBox.connect('notify::visible', this._updateMessage.bind(this));
+ this._sessionModeUpdatedId = Main.sessionMode.connect('updated', this._onSessionModeUpdated.bind(this));
+
+ this._updateMessage();
+ }
+
+ _onSessionModeUpdated() {
+ if (!Main.sessionMode.hasWindows)
+ this._messageInhibitedUntilIdle = false;
+ this._updateMessage();
+ }
+
+ _onIdleTimeoutChanged() {
+ if (this._idleWatchId) {
+ this._idleMonitor.remove_watch(this._idleWatchId);
+ this._idleWatchId = 0;
+ }
+ this._messageInhibitedUntilIdle = false;
+ }
+
+ _updateMessage() {
+ if (this._messageInhibitedUntilIdle) {
+ if (this._message)
+ this._dismissMessage();
+ return;
+ }
+
+ if (this._idleWatchId) {
+ this._idleMonitor.remove_watch(this._idleWatchId);
+ this._idleWatchId = 0;
+ }
+
+ if (Main.sessionMode.hasOverview && Main.overview.visible) {
+ this._dismissMessage();
+ return;
+ }
+
+ if (!Main.layoutManager.panelBox.visible) {
+ this._dismissMessage();
+ return;
+ }
+
+ let supportedModes = [];
+
+ if (this._settings.get_boolean('show-when-unlocked'))
+ supportedModes.push('user');
+
+ if (this._settings.get_boolean('show-when-unlocking'))
+ supportedModes.push('unlock-dialog');
+
+ if (this._settings.get_boolean('show-when-locked'))
+ supportedModes.push('lock-screen');
+
+ if (this._settings.get_boolean('show-on-login-screen'))
+ supportedModes.push('gdm');
+
+ if (!supportedModes.includes(Main.sessionMode.currentMode) &&
+ !supportedModes.includes(Main.sessionMode.parentMode)) {
+ this._dismissMessage();
+ return;
+ }
+
+ let heading = this._settings.get_string('message-heading');
+ let body = this._settings.get_string('message-body');
+
+ if (!heading && !body) {
+ this._dismissMessage();
+ return;
+ }
+
+ if (!this._message) {
+ this._message = new HeadsUpMessage.HeadsUpMessage(heading, body);
+
+ this._message.connect('notify::allocation', this._adaptSessionForMessage.bind(this));
+ this._message.connect('clicked', this._onMessageClicked.bind(this));
+ }
+
+ this._message.reactive = true;
+ this._message.track_hover = true;
+
+ this._message.setHeading(heading);
+ this._message.setBody(body);
+
+ if (!Main.sessionMode.hasWindows) {
+ this._message.track_hover = false;
+ this._message.reactive = false;
+ }
+ }
+
+ _onMessageClicked() {
+ if (!Main.sessionMode.hasWindows)
+ return;
+
+ if (this._idleWatchId) {
+ this._idleMonitor.remove_watch(this._idleWatchId);
+ this._idleWatchId = 0;
+ }
+
+ let idleTimeout = this._settings.get_uint('idle-timeout');
+ this._idleWatchId = this._idleMonitor.add_idle_watch(idleTimeout * 1000, this._onUserIdle.bind(this));
+ this._messageInhibitedUntilIdle = true;
+ this._updateMessage();
+ }
+
+ _onUserIdle() {
+ this._messageInhibitedUntilIdle = false;
+ this._updateMessage();
+ }
+
+ _dismissMessage() {
+ if (!this._message) {
+ return;
+ }
+
+ this._message.visible = false;
+ this._message.destroy();
+ this._message = null;
+ this._resetMessageTray();
+ this._resetLoginDialog();
+ }
+
+ _resetMessageTray() {
+ if (!Main.messageTray)
+ return;
+
+ Main.messageTray.actor.set_translation(0, 0, 0);
+ }
+
+ _alignMessageTray() {
+ if (!Main.messageTray)
+ return;
+
+ if (!this._message || !this._message.visible) {
+ this._resetMessageTray()
+ return;
+ }
+
+ let panelBottom = Main.layoutManager.panelBox.y + Main.layoutManager.panelBox.height;
+ let messageBottom = this._message.y + this._message.height;
+
+ Main.messageTray.actor.set_translation(0, messageBottom - panelBottom, 0);
+ }
+
+ _resetLoginDialog() {
+ if (!Main.sessionMode.isGreeter)
+ return;
+
+ if (!Main.screenShield || !Main.screenShield._dialog)
+ return;
+
+ let dialog = Main.screenShield._dialog;
+
+ if (this._authPromptAllocatedId) {
+ dialog.disconnect(this._authPromptAllocatedId);
+ this._authPromptAllocatedId = 0;
+ }
+
+ dialog.style = null;
+ dialog._bannerView.style = null;
+ }
+
+ _adaptLoginDialogForMessage() {
+ if (!Main.sessionMode.isGreeter)
+ return;
+
+ if (!Main.screenShield || !Main.screenShield._dialog)
+ return;
+
+ if (!this._message || !this._message.visible) {
+ this._resetLoginDialog()
+ return;
+ }
+
+ let dialog = Main.screenShield._dialog;
+
+ let messageHeight = this._message.y + this._message.height;
+ if (dialog._logoBin.visible)
+ messageHeight -= dialog._logoBin.height;
+
+ if (messageHeight <= 0) {
+ dialog.style = null;
+ dialog._bannerView.style = null;
+ } else {
+ dialog.style = `margin-top: ${messageHeight}px;`;
+
+ let bannerOnSide = dialog._bannerView.x + dialog._bannerView.width < dialog._authPrompt.actor.x;
+
+ if (bannerOnSide)
+ dialog._bannerView.style = `margin-bottom: ${messageHeight}px;`;
+ else
+ dialog._bannerView.style = `margin-top: ${messageHeight}px`;
+ }
+ }
+
+ _adaptSessionForMessage() {
+ this._alignMessageTray();
+
+ if (Main.sessionMode.isGreeter) {
+ this._adaptLoginDialogForMessage();
+ if (!this._authPromptAllocatedId) {
+ let dialog = Main.screenShield._dialog;
+ this._authPromptAllocatedId = dialog._authPrompt.actor.connect("notify::allocation", this._adaptLoginDialogForMessage.bind(this));
+ }
+ }
+ }
+}
+
+function init() {
+ return new Extension();
+}
diff --git a/extensions/heads-up-display/headsUpMessage.js b/extensions/heads-up-display/headsUpMessage.js
new file mode 100644
index 00000000..d828d8c9
--- /dev/null
+++ b/extensions/heads-up-display/headsUpMessage.js
@@ -0,0 +1,150 @@
+const { Atk, Clutter, GObject, Pango, St } = imports.gi;
+const Layout = imports.ui.layout;
+const Main = imports.ui.main;
+const Signals = imports.signals;
+
+var HeadsUpMessageBodyLabel = GObject.registerClass({
+}, class HeadsUpMessageBodyLabel extends St.Label {
+ _init(params) {
+ super._init(params);
+
+ this.clutter_text.single_line_mode = false;
+ this.clutter_text.line_wrap = true;
+ }
+
+ vfunc_get_preferred_width(forHeight) {
+ let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
+
+ let [labelMinimumWidth, labelNaturalWidth] = super.vfunc_get_preferred_width(forHeight);
+
+ labelMinimumWidth = Math.min(labelMinimumWidth, .75 * workArea.width);
+ labelNaturalWidth = Math.min(labelNaturalWidth, .75 * workArea.width);
+
+ return [labelMinimumWidth, labelNaturalWidth];
+ }
+
+ vfunc_get_preferred_height(forWidth) {
+ let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
+ let labelHeightUpperBound = .25 * workArea.height;
+
+ this.clutter_text.single_line_mode = true;
+ this.clutter_text.line_wrap = false;
+ let [lineHeight] = super.vfunc_get_preferred_height(-1);
+ let numberOfLines = Math.floor(labelHeightUpperBound / lineHeight);
+ numberOfLines = Math.max(numberOfLines, 1);
+
+ let labelHeight = lineHeight * numberOfLines;
+
+ this.clutter_text.single_line_mode = false;
+ this.clutter_text.line_wrap = true;
+ let [labelMinimumHeight, labelNaturalHeight] = super.vfunc_get_preferred_height(forWidth);
+
+ labelMinimumHeight = Math.min(labelMinimumHeight, labelHeight);
+ labelNaturalHeight = Math.min(labelNaturalHeight, labelHeight);
+
+ return [labelMinimumHeight, labelNaturalHeight];
+ }
+
+ vfunc_allocate(box, flags) {
+ if (!this.visible)
+ return;
+
+ super.vfunc_allocate(box, flags);
+ }
+});
+
+var HeadsUpMessage = GObject.registerClass({
+}, class HeadsUpMessage extends St.Button {
+ _init(heading, body) {
+ super._init({
+ style_class: 'message',
+ accessible_role: Atk.Role.NOTIFICATION,
+ can_focus: false,
+ });
+
+ Main.layoutManager.addChrome(this, { affectsInputRegion: true });
+
+ this.add_style_class_name('heads-up-display-message');
+
+ this._panelAllocationId = Main.layoutManager.panelBox.connect ("notify::allocation", this._alignWithPanel.bind(this));
+ this.connect("notify::allocation", this._alignWithPanel.bind(this));
+
+ this._messageTraySnappingId = Main.messageTray.connect ("notify::y", () => {
+ if (!this.visible)
+ return;
+
+ if (!Main.messageTray.visible)
+ return;
+
+ if (Main.messageTray.y >= this.y && Main.messageTray.y < this.y + this.height)
+ Main.messageTray.y = this.y + this.height;
+ });
+
+
+ let contentsBox = new St.BoxLayout({ style_class: 'heads-up-message-content',
+ vertical: true,
+ x_align: Clutter.ActorAlign.CENTER });
+ this.add_actor(contentsBox);
+
+ this.headingLabel = new St.Label({ style_class: 'heads-up-message-heading',
+ x_expand: true,
+ x_align: Clutter.ActorAlign.CENTER });
+ this.setHeading(heading);
+ contentsBox.add_actor(this.headingLabel);
+ this.contentsBox = contentsBox;
+
+ this.bodyLabel = new HeadsUpMessageBodyLabel({ style_class: 'heads-up-message-body',
+ x_expand: true,
+ y_expand: true });
+ contentsBox.add_actor(this.bodyLabel);
+
+ this.setBody(body);
+ this.bodyLabel.clutter_text.label = this.bodyLabel;
+ }
+
+ _alignWithPanel() {
+ if (!this.visible)
+ return;
+
+ this.x = Main.panel.actor.x;
+ this.x += Main.panel.actor.width / 2;
+ this.x -= this.width / 2;
+ this.x = Math.floor(this.x);
+ this.y = Main.panel.actor.y + Main.panel.actor.height;
+ this.queue_relayout();
+ }
+
+ setHeading(text) {
+ if (text) {
+ let heading = text ? text.replace(/\n/g, ' ') : '';
+ this.headingLabel.text = heading;
+ this.headingLabel.visible = true;
+ } else {
+ this.headingLabel.text = text;
+ this.headingLabel.visible = false;
+ }
+ }
+
+ setBody(text) {
+ this.bodyLabel.text = text;
+ if (text) {
+ this.bodyLabel.visible = true;
+ } else {
+ this.bodyLabel.visible = false;
+ }
+ }
+
+ destroy() {
+ if (this._panelAllocationId) {
+ Main.layoutManager.panelBox.disconnect(this._panelAllocationId);
+ this._panelAllocationId = 0;
+ }
+
+ if (this._messageTraySnappingId) {
+ Main.messageTray.disconnect(this._messageTraySnappingId);
+ this._messageTraySnappingId = 0;
+ }
+
+ super.destroy();
+ }
+});
diff --git a/extensions/heads-up-display/meson.build b/extensions/heads-up-display/meson.build
new file mode 100644
index 00000000..40c3de0a
--- /dev/null
+++ b/extensions/heads-up-display/meson.build
@@ -0,0 +1,8 @@
+extension_data += configure_file(
+ input: metadata_name + '.in',
+ output: metadata_name,
+ configuration: metadata_conf
+)
+
+extension_sources += files('headsUpMessage.js', 'prefs.js')
+extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
diff --git a/extensions/heads-up-display/metadata.json.in b/extensions/heads-up-display/metadata.json.in
new file mode 100644
index 00000000..e7ab71aa
--- /dev/null
+++ b/extensions/heads-up-display/metadata.json.in
@@ -0,0 +1,11 @@
+{
+"extension-id": "@extension_id@",
+"uuid": "@uuid@",
+"gettext-domain": "@gettext_domain@",
+"name": "Heads-up Display Message",
+"description": "Add a message to be displayed on screen always above all windows and chrome.",
+"original-authors": [ "rstrode@redhat.com" ],
+"shell-version": [ "@shell_current@" ],
+"url": "@url@",
+"session-modes": [ "gdm", "lock-screen", "unlock-dialog", "user" ]
+}
diff --git a/extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml b/extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml
new file mode 100644
index 00000000..ea1f3774
--- /dev/null
+++ b/extensions/heads-up-display/org.gnome.shell.extensions.heads-up-display.gschema.xml
@@ -0,0 +1,54 @@
+<schemalist gettext-domain="gnome-shell-extensions">
+ <schema id="org.gnome.shell.extensions.heads-up-display"
+ path="/org/gnome/shell/extensions/heads-up-display/">
+ <key name="idle-timeout" type="u">
+ <default>30</default>
+ <summary>Idle Timeout</summary>
+ <description>
+ Number of seconds until message is reshown after user goes idle.
+ </description>
+ </key>
+ <key name="message-heading" type="s">
+ <default>""</default>
+ <summary>Message to show at top of display</summary>
+ <description>
+ The top line of the heads up display message.
+ </description>
+ </key>
+ <key name="message-body" type="s">
+ <default>""</default>
+ <summary>Banner message</summary>
+ <description>
+ A message to always show at the top of the screen.
+ </description>
+ </key>
+ <key name="show-on-login-screen" type="b">
+ <default>true</default>
+ <summary>Show on login screen</summary>
+ <description>
+ Whether or not the message should display on the login screen
+ </description>
+ </key>
+ <key name="show-when-locked" type="b">
+ <default>false</default>
+ <summary>Show on screen shield</summary>
+ <description>
+ Whether or not the message should display when the screen is locked
+ </description>
+ </key>
+ <key name="show-when-unlocking" type="b">
+ <default>false</default>
+ <summary>Show on unlock screen</summary>
+ <description>
+ Whether or not the message should display on the unlock screen.
+ </description>
+ </key>
+ <key name="show-when-unlocked" type="b">
+ <default>false</default>
+ <summary>Show in user session</summary>
+ <description>
+ Whether or not the message should display when the screen is unlocked.
+ </description>
+ </key>
+ </schema>
+</schemalist>
diff --git a/extensions/heads-up-display/prefs.js b/extensions/heads-up-display/prefs.js
new file mode 100644
index 00000000..b4b6f94c
--- /dev/null
+++ b/extensions/heads-up-display/prefs.js
@@ -0,0 +1,175 @@
+
+/* Desktop Icons GNOME Shell extension
+ *
+ * Copyright (C) 2017 Carlos Soriano <csoriano@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+const { Gio, GObject, Gdk, Gtk } = imports.gi;
+const ExtensionUtils = imports.misc.extensionUtils;
+const Gettext = imports.gettext.domain('gnome-shell-extensions');
+const _ = Gettext.gettext;
+const N_ = e => e;
+const cssData = `
+ .no-border {
+ border: none;
+ }
+
+ .border {
+ border: 1px solid;
+ border-radius: 3px;
+ border-color: #b6b6b3;
+ box-shadow: inset 0 0 0 1px rgba(74, 144, 217, 0);
+ background-color: white;
+ }
+
+ .margins {
+ padding-left: 8px;
+ padding-right: 8px;
+ padding-bottom: 8px;
+ }
+
+ .message-label {
+ font-weight: bold;
+ }
+`;
+
+var settings;
+
+function init() {
+ settings = ExtensionUtils.getSettings("org.gnome.shell.extensions.heads-up-display");
+ let cssProvider = new Gtk.CssProvider();
+ cssProvider.load_from_data(cssData);
+
+ let screen = Gdk.Screen.get_default();
+ Gtk.StyleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+}
+
+function buildPrefsWidget() {
+ ExtensionUtils.initTranslations();
+
+ let contents = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ border_width: 20,
+ spacing: 10,
+ });
+
+ contents.add(buildSwitch('show-when-locked', _("Show message when screen is locked")));
+ contents.add(buildSwitch('show-when-unlocking', _("Show message on unlock screen")));
+ contents.add(buildSwitch('show-when-unlocked', _("Show message when screen is unlocked")));
+ contents.add(buildSpinButton('idle-timeout', _("Seconds after user goes idle before reshowing message")));
+
+ let outerMessageBox = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ border_width: 0,
+ spacing: 5,
+ });
+ contents.add(outerMessageBox);
+
+ let messageLabel = new Gtk.Label({
+ label: 'Message',
+ halign: Gtk.Align.START,
+ });
+ messageLabel.get_style_context().add_class("message-label");
+ outerMessageBox.add(messageLabel);
+
+ let innerMessageBox = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ border_width: 0,
+ spacing: 0,
+ });
+ innerMessageBox.get_style_context().add_class("border");
+ outerMessageBox.add(innerMessageBox);
+
+ innerMessageBox.add(buildEntry('message-heading', _("Message Heading")));
+ innerMessageBox.add(buildTextView('message-body', _("Message Body")));
+ contents.show_all();
+ return contents;
+}
+
+function buildTextView(key, labelText) {
+ let textView = new Gtk.TextView({
+ accepts_tab: false,
+ wrap_mode: Gtk.WrapMode.WORD,
+ });
+ settings.bind(key, textView.get_buffer(), 'text', Gio.SettingsBindFlags.DEFAULT);
+
+ let scrolledWindow = new Gtk.ScrolledWindow({
+ expand: true,
+ });
+ let styleContext = scrolledWindow.get_style_context();
+ styleContext.add_class("margins");
+
+ scrolledWindow.add(textView);
+ return scrolledWindow;
+}
+function buildEntry(key, labelText) {
+ let entry = new Gtk.Entry({ placeholder_text: labelText });
+ let styleContext = entry.get_style_context();
+ styleContext.add_class("no-border");
+ settings.bind(key, entry, 'text', Gio.SettingsBindFlags.DEFAULT);
+
+ entry.get_settings()['gtk-entry-select-on-focus'] = false;
+
+ return entry;
+}
+
+function buildSpinButton(key, labelText) {
+ let hbox = new Gtk.Box({
+ orientation: Gtk.Orientation.HORIZONTAL,
+ spacing: 10,
+ });
+ let label = new Gtk.Label({
+ label: labelText,
+ xalign: 0,
+ });
+ let adjustment = new Gtk.Adjustment({
+ value: 0,
+ lower: 0,
+ upper: 2147483647,
+ step_increment: 1,
+ page_increment: 60,
+ page_size: 60,
+ });
+ let spinButton = new Gtk.SpinButton({
+ adjustment: adjustment,
+ climb_rate: 1.0,
+ digits: 0,
+ max_width_chars: 3,
+ width_chars: 3,
+ });
+ settings.bind(key, spinButton, 'value', Gio.SettingsBindFlags.DEFAULT);
+ hbox.pack_start(label, true, true, 0);
+ hbox.add(spinButton);
+ return hbox;
+}
+
+function buildSwitch(key, labelText) {
+ let hbox = new Gtk.Box({
+ orientation: Gtk.Orientation.HORIZONTAL,
+ spacing: 10,
+ });
+ let label = new Gtk.Label({
+ label: labelText,
+ xalign: 0,
+ });
+ let switcher = new Gtk.Switch({
+ active: settings.get_boolean(key),
+ });
+ settings.bind(key, switcher, 'active', Gio.SettingsBindFlags.DEFAULT);
+ hbox.pack_start(label, true, true, 0);
+ hbox.add(switcher);
+ return hbox;
+}
diff --git a/extensions/heads-up-display/stylesheet.css b/extensions/heads-up-display/stylesheet.css
new file mode 100644
index 00000000..93034469
--- /dev/null
+++ b/extensions/heads-up-display/stylesheet.css
@@ -0,0 +1,32 @@
+.heads-up-display-message {
+ background-color: rgba(0.24, 0.24, 0.24, 0.80);
+ border: 1px solid black;
+ border-radius: 6px;
+ color: #eeeeec;
+ font-size: 11pt;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ padding: 0.9em;
+}
+
+.heads-up-display-message:insensitive {
+ background-color: rgba(0.24, 0.24, 0.24, 0.33);
+}
+
+.heads-up-display-message:hover {
+ background-color: rgba(0.24, 0.24, 0.24, 0.2);
+ border: 1px solid rgba(0.0, 0.0, 0.0, 0.5);
+ color: #4d4d4d;
+ transition-duration: 250ms;
+}
+
+.heads-up-message-heading {
+ height: 1.75em;
+ font-size: 1.25em;
+ font-weight: bold;
+ text-align: center;
+}
+
+.heads-up-message-body {
+ text-align: center;
+}
diff --git a/meson.build b/meson.build
index ba84f8f3..c5fc86ef 100644
--- a/meson.build
+++ b/meson.build
@@ -44,6 +44,7 @@ classic_extensions = [
default_extensions = classic_extensions
default_extensions += [
'drive-menu',
+ 'heads-up-display',
'screenshot-window-sizer',
'windowsNavigator',
'workspace-indicator'
--
2.32.0

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

@ -0,0 +1,55 @@
From b4eeaf7ea12fa7d9713e80371490d8060396b3cb Mon Sep 17 00:00:00 2001
From: Milan Crha <mcrha@redhat.com>
Date: Fri, 17 Apr 2020 09:21:42 +0200
Subject: [PATCH] window-list: Invalid current mode selected in Preferences
It seems that gtk+ resets the active radio whenever a new radio button
is added into the group, thus rather restore the current mode after
the group is fully populated.
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/119
---
extensions/window-list/prefs.js | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js
index 78792b5..17e9799 100644
--- a/extensions/window-list/prefs.js
+++ b/extensions/window-list/prefs.js
@@ -50,6 +50,7 @@ class WindowListPrefsWidget extends Gtk.Grid {
};
let radio = null;
+ let currentRadio = null;
for (let i = 0; i < modes.length; i++) {
let mode = modes[i];
let label = modeLabels[mode];
@@ -59,18 +60,24 @@ class WindowListPrefsWidget extends Gtk.Grid {
}
radio = new Gtk.RadioButton({
- active: currentMode == mode,
+ active: !i,
label: label,
group: radio
});
grid.add(radio);
+ if (currentMode === mode)
+ currentRadio = radio;
+
radio.connect('toggled', button => {
if (button.active)
this._settings.set_string('grouping-mode', mode);
});
}
+ if (currentRadio)
+ currentRadio.active = true;
+
let check = new Gtk.CheckButton({
label: _('Show on all monitors'),
margin_top: 6
--
2.26.2

@ -0,0 +1,30 @@
From ee25c2aac70b86f31c91f6491dad4c67a59bc261 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 26 Jan 2021 21:14:47 +0100
Subject: [PATCH] window-list: Leave "fake overview" when destroyed
Otherwise we leave an incomplete overview-like state around, which
can cause issues later when the extension is re-enabled (for example
when coming back from screen lock).
https://bugzilla.redhat.com/show_bug.cgi?id=1904371
---
extensions/window-list/windowPicker.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/extensions/window-list/windowPicker.js b/extensions/window-list/windowPicker.js
index 12a7627..afb5d27 100644
--- a/extensions/window-list/windowPicker.js
+++ b/extensions/window-list/windowPicker.js
@@ -210,6 +210,8 @@ var WindowPicker = class {
}
_onDestroy() {
+ this._fakeOverviewVisible(false);
+
if (this._monitorsChangedId)
Main.layoutManager.disconnect(this._monitorsChangedId);
this._monitorsChangedId = 0;
--
2.31.1

File diff suppressed because it is too large Load Diff

@ -0,0 +1,176 @@
From 1f9f4af38f991b462ee5f872a697d88a9e115499 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 20 Jan 2021 20:18:39 +0100
Subject: [PATCH 1/2] workspace-indicator: Add tooltips to workspace thumbnails
When showing previews instead of the menu, the workspace names from
our preferences don't appear anywhere. Some users care strongly about
those, so expose them as tooltip on hover.
---
extensions/workspace-indicator/extension.js | 40 +++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js
index 69eef88c..b10e37ff 100644
--- a/extensions/workspace-indicator/extension.js
+++ b/extensions/workspace-indicator/extension.js
@@ -8,6 +8,7 @@ const ExtensionUtils = imports.misc.extensionUtils;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
+const Tweener = imports.ui.tweener;
const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
@@ -15,6 +16,9 @@ const _ = Gettext.gettext;
const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
const WORKSPACE_KEY = 'workspace-names';
+const TOOLTIP_OFFSET = 6;
+const TOOLTIP_ANIMATION_TIME = 150;
+
let WindowPreview = GObject.registerClass({
GTypeName: 'WorkspaceIndicatorWindowPreview'
}, class WindowPreview extends St.Button {
@@ -117,7 +121,14 @@ let WorkspaceThumbnail = GObject.registerClass({
y_fill: true
});
+ this._tooltip = new St.Label({
+ style_class: 'dash-label',
+ visible: false,
+ });
+ Main.uiGroup.add_child(this._tooltip);
+
this.connect('destroy', this._onDestroy.bind(this));
+ this.connect('notify::hover', this._syncTooltip.bind(this));
this._index = index;
this._delegate = this; // needed for DND
@@ -204,7 +215,36 @@ let WorkspaceThumbnail = GObject.registerClass({
ws.activate(global.get_current_time());
}
+ _syncTooltip() {
+ if (this.hover) {
+ this._tooltip.text = Meta.prefs_get_workspace_name(this._index);
+ this._tooltip.opacity = 0;
+ this._tooltip.show();
+
+ const [stageX, stageY] = this.get_transformed_position();
+ const thumbWidth = this.allocation.get_width();
+ const thumbHeight = this.allocation.get_height();
+ const tipWidth = this._tooltip.width;
+ const xOffset = Math.floor((thumbWidth - tipWidth) / 2);
+ const monitor = Main.layoutManager.findMonitorForActor(this);
+ const x = Math.min(
+ Math.max(stageX + xOffset, monitor.x),
+ monitor.x + monitor.width - tipWidth);
+ const y = stageY + thumbHeight + TOOLTIP_OFFSET;
+ this._tooltip.set_position(x, y);
+ }
+
+ Tweener.addTween(this._tooltip, {
+ opacity: this.hover ? 255 : 0,
+ time: TOOLTIP_ANIMATION_TIME * 1000,
+ transition: 'easeOutQuad',
+ onComplete: () => (this._tooltip.visible = this.hover),
+ });
+ }
+
_onDestroy() {
+ this._tooltip.destroy();
+
this._workspace.disconnect(this._windowAddedId);
this._workspace.disconnect(this._windowRemovedId);
global.display.disconnect(this._restackedId);
--
2.31.1
From 19e19e11214b6b9deae110cd6a4c9232d77c18cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 20 Jan 2021 20:29:01 +0100
Subject: [PATCH 2/2] window-list: Add tooltips to workspace thumbnails
When showing previews instead of the menu, the workspace names
don't appear anywhere. Some users care strongly about those, so
expose them as tooltip on hover.
---
extensions/window-list/workspaceIndicator.js | 40 ++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
index ca476111..33ec9b0e 100644
--- a/extensions/window-list/workspaceIndicator.js
+++ b/extensions/window-list/workspaceIndicator.js
@@ -5,10 +5,14 @@ const DND = imports.ui.dnd;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
+const Tweener = imports.ui.tweener;
const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
+const TOOLTIP_OFFSET = 6;
+const TOOLTIP_ANIMATION_TIME = 150;
+
let WindowPreview = GObject.registerClass({
GTypeName: 'WindowListWindowPreview'
}, class WindowPreview extends St.Button {
@@ -111,7 +115,14 @@ let WorkspaceThumbnail = GObject.registerClass({
y_fill: true
});
+ this._tooltip = new St.Label({
+ style_class: 'dash-label',
+ visible: false,
+ });
+ Main.uiGroup.add_child(this._tooltip);
+
this.connect('destroy', this._onDestroy.bind(this));
+ this.connect('notify::hover', this._syncTooltip.bind(this));
this._index = index;
this._delegate = this; // needed for DND
@@ -198,7 +209,36 @@ let WorkspaceThumbnail = GObject.registerClass({
ws.activate(global.get_current_time());
}
+ _syncTooltip() {
+ if (this.hover) {
+ this._tooltip.text = Meta.prefs_get_workspace_name(this._index);
+ this._tooltip.opacity = 0;
+ this._tooltip.show();
+
+ const [stageX, stageY] = this.get_transformed_position();
+ const thumbWidth = this.allocation.get_width();
+ const tipWidth = this._tooltip.width;
+ const tipHeight = this._tooltip.height;
+ const xOffset = Math.floor((thumbWidth - tipWidth) / 2);
+ const monitor = Main.layoutManager.findMonitorForActor(this);
+ const x = Math.min(
+ Math.max(stageX + xOffset, monitor.x),
+ monitor.x + monitor.width - tipWidth);
+ const y = stageY - tipHeight - TOOLTIP_OFFSET;
+ this._tooltip.set_position(x, y);
+ }
+
+ Tweener.addTween(this._tooltip, {
+ opacity: this.hover ? 255 : 0,
+ time: TOOLTIP_ANIMATION_TIME * 1000,
+ transition: 'easeOutQuad',
+ onComplete: () => (this._tooltip.visible = this.hover),
+ });
+ }
+
_onDestroy() {
+ this._tooltip.destroy();
+
this._workspace.disconnect(this._windowAddedId);
this._workspace.disconnect(this._windowRemovedId);
global.display.disconnect(this._restackedId);
--
2.31.1

@ -0,0 +1,267 @@
From bcbf9709802e7644c5911615dabdee7d8ca07719 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Mon, 31 May 2021 19:29:34 +0200
Subject: [PATCH 1/3] desktopManager: Handle TOUCH_UPDATE/END events explicitly
for rubberband
These events need specific handling for Wayland, as we do not get emulated
pointer events in that platform. Handle these for rubberband selection.
---
extensions/desktop-icons/desktopManager.js | 67 ++++++++++++++++------
1 file changed, 48 insertions(+), 19 deletions(-)
diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js
index 399aee0..a70cd98 100644
--- a/extensions/desktop-icons/desktopManager.js
+++ b/extensions/desktop-icons/desktopManager.js
@@ -130,26 +130,49 @@ var DesktopManager = GObject.registerClass({
}
[x, y] = event.get_coords();
this._updateRubberBand(x, y);
- let x0, y0, x1, y1;
- if (x >= this._rubberBandInitialX) {
- x0 = this._rubberBandInitialX;
- x1 = x;
- } else {
- x1 = this._rubberBandInitialX;
- x0 = x;
- }
- if (y >= this._rubberBandInitialY) {
- y0 = this._rubberBandInitialY;
- y1 = y;
- } else {
- y1 = this._rubberBandInitialY;
- y0 = y;
- }
- for (let [fileUri, fileItem] of this._fileItems) {
- fileItem.emit('selected', true, true,
- fileItem.intersectsWith(x0, y0, x1 - x0, y1 - y0));
- }
+ this._updateSelection(x, y);
});
+ this._rubberBandTouchId = global.stage.connect('touch-event', (actor, event) => {
+ // Let x11 pointer emulation do the job on X11
+ if (!Meta.is_wayland_compositor())
+ return Clutter.EVENT_PROPAGATE;
+ if (!global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
+ return Clutter.EVENT_PROPAGATE;
+
+ if (event.type() == Clutter.EventType.TOUCH_END) {
+ this.endRubberBand();
+ return Clutter.EVENT_STOP;
+ } else if (event.type() == Clutter.EventType.TOUCH_UPDATE) {
+ [x, y] = event.get_coords();
+ this._updateRubberBand(x, y);
+ this._updateSelection(x, y);
+ return Clutter.EVENT_STOP;
+ }
+
+ return Clutter.EVENT_PROPAGATE;
+ });
+ }
+
+ _updateSelection(x, y) {
+ let x0, y0, x1, y1;
+ if (x >= this._rubberBandInitialX) {
+ x0 = this._rubberBandInitialX;
+ x1 = x;
+ } else {
+ x1 = this._rubberBandInitialX;
+ x0 = x;
+ }
+ if (y >= this._rubberBandInitialY) {
+ y0 = this._rubberBandInitialY;
+ y1 = y;
+ } else {
+ y1 = this._rubberBandInitialY;
+ y0 = y;
+ }
+ for (let [fileUri, fileItem] of this._fileItems) {
+ fileItem.emit('selected', true, true,
+ fileItem.intersectsWith(x0, y0, x1 - x0, y1 - y0));
+ }
}
endRubberBand() {
@@ -157,8 +180,10 @@ var DesktopManager = GObject.registerClass({
Extension.lockActivitiesButton = false;
this._grabHelper.ungrab();
global.stage.disconnect(this._rubberBandId);
+ global.stage.disconnect(this._rubberBandTouchId);
global.stage.disconnect(this._stageReleaseEventId);
this._rubberBandId = 0;
+ this._rubberBandTouchId = 0;
this._stageReleaseEventId = 0;
this._selection = new Set([...this._selection, ...this._currentSelection]);
@@ -739,6 +764,10 @@ var DesktopManager = GObject.registerClass({
global.stage.disconnect(this._rubberBandId);
this._rubberBandId = 0;
+ if (this._rubberBandTouchId)
+ global.stage.disconnect(this._rubberBandTouchId);
+ this._rubberBandTouchId = 0;
+
this._rubberBand.destroy();
if (this._queryFileInfoCancellable)
--
2.31.1
From 0733004ffeb517f7a80ff41e7181027e8b92b17e Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Mon, 31 May 2021 19:31:03 +0200
Subject: [PATCH 2/3] desktopGrid: Handle TOUCH_BEGIN events explicitly
We do not get pointer emulated events on Wayland, so touch events should
be handled explicitly there. Handle starting rubberband selection via
touch.
---
extensions/desktop-icons/desktopGrid.js | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js
index 94d2dfd..602fa7f 100644
--- a/extensions/desktop-icons/desktopGrid.js
+++ b/extensions/desktop-icons/desktopGrid.js
@@ -21,6 +21,7 @@ const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
+const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
@@ -123,6 +124,7 @@ var DesktopGrid = class {
() => this._backgroundDestroyed());
this._grid.connect('button-press-event', (actor, event) => this._onPressButton(actor, event));
+ this._grid.connect('touch-event', (actor, event) => this._onTouchEvent(actor, event));
this._grid.connect('key-press-event', this._onKeyPress.bind(this));
@@ -506,6 +508,23 @@ var DesktopGrid = class {
return Clutter.EVENT_PROPAGATE;
}
+ _onTouchEvent(actor, event) {
+ // Let x11 pointer emulation do the job on X11
+ if (!Meta.is_wayland_compositor())
+ return Clutter.EVENT_PROPAGATE;
+
+ if (event.type() == Clutter.EventType.TOUCH_BEGIN &&
+ global.display.is_pointer_emulating_sequence(event.get_event_sequence())) {
+ Extension.desktopManager.clearSelection();
+ let [x, y] = event.get_coords();
+ let [gridX, gridY] = this._grid.get_transformed_position();
+ Extension.desktopManager.startRubberBand(x, y, gridX, gridY);
+ return Clutter.EVENT_STOP;
+ }
+
+ return Clutter.EVENT_PROPAGATE;
+ }
+
_addDesktopBackgroundMenu() {
this.actor._desktopBackgroundMenu = this._createDesktopBackgroundMenu();
this.actor._desktopBackgroundManager = new PopupMenu.PopupMenuManager({ actor: this.actor });
--
2.31.1
From 2d978ffc58562c4f4d00b1afb03da58be3102e29 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Mon, 31 May 2021 19:31:50 +0200
Subject: [PATCH 3/3] fileItem: Handle (multi) touch explicitly via touch
events
Wayland does not get pointer emulated events, so we must handle TOUCH_BEGIN/
END here for file clicking/tapping to work there.
---
extensions/desktop-icons/fileItem.js | 34 ++++++++++++++++++++++++----
1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
index 143cb9b..1cb47e8 100644
--- a/extensions/desktop-icons/fileItem.js
+++ b/extensions/desktop-icons/fileItem.js
@@ -117,6 +117,7 @@ var FileItem = class {
this._container.connect('motion-event', (actor, event) => this._onMotion(actor, event));
this._container.connect('leave-event', (actor, event) => this._onLeave(actor, event));
this._container.connect('button-release-event', (actor, event) => this._onReleaseButton(actor, event));
+ this._container.connect('touch-event', (actor, event) => this._onTouchEvent(actor, event));
/* Set the metadata and update relevant UI */
this._updateMetadataFromFileInfo(fileInfo);
@@ -648,16 +649,26 @@ var FileItem = class {
DesktopIconsUtil.launchTerminal(this.file.get_path());
}
+ _eventButton(event) {
+ // Emulate button1 press on touch events
+ if (event.type() == Clutter.EventType.TOUCH_BEGIN ||
+ event.type() == Clutter.EventType.TOUCH_END ||
+ event.type() == Clutter.EventType.TOUCH_UPDATE)
+ return 1;
+
+ return event.get_button();
+ }
+
_updateClickState(event) {
let settings = Clutter.Settings.get_default();
- if ((event.get_button() == this._lastClickButton) &&
+ if ((this._eventButton(event) == this._lastClickButton) &&
((event.get_time() - this._lastClickTime) < settings.double_click_time))
this._clickCount++;
else
this._clickCount = 1;
this._lastClickTime = event.get_time();
- this._lastClickButton = event.get_button();
+ this._lastClickButton = this._eventButton(event);
}
_getClickCount() {
@@ -666,7 +677,7 @@ var FileItem = class {
_onPressButton(actor, event) {
this._updateClickState(event);
- let button = event.get_button();
+ let button = this._eventButton(event);
if (button == 3) {
if (!this.isSelected)
this.emit('selected', false, false, true);
@@ -725,7 +736,7 @@ var FileItem = class {
}
_onReleaseButton(actor, event) {
- let button = event.get_button();
+ let button = this._eventButton(event);
if (button == 1) {
// primaryButtonPressed is TRUE only if the user has pressed the button
// over an icon, and if (s)he has not started a drag&drop operation
@@ -744,6 +755,21 @@ var FileItem = class {
return Clutter.EVENT_PROPAGATE;
}
+ _onTouchEvent(actor, event) {
+ // Let x11 pointer emulation do the job on X11
+ if (!Meta.is_wayland_compositor())
+ return Clutter.EVENT_PROPAGATE;
+ if (!global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
+ return Clutter.EVENT_PROPAGATE;
+
+ if (event.type() == Clutter.EventType.TOUCH_BEGIN)
+ this._onPressButton(actor, event);
+ else if (event.type() == Clutter.EventType.TOUCH_UPDATE)
+ this._onMotion(actor, event);
+ else if (event.type() == Clutter.EventType.TOUCH_END)
+ this._onReleaseButton(actor, event);
+ }
+
get savedCoordinates() {
return this._savedCoordinates;
}
--
2.31.1

@ -0,0 +1,27 @@
[Desktop Entry]
Name[de]=Klassisch (Wayland Anzeige-Server)
Name[es]=Clásico (servidor gráfico Wayland)
Name[fr]=Classic (serveur affichage Wayland)
Name[it]=Classico (server grafico Wayland)
Name[ja]=クラシック (Wayland ディスプレイサーバー)
Name[ko]=클래식 (Wayland 디스플레이 서버)
Name[pt_BR]=Clássico (servidor de exibição Wayland)
Name[ru]=Классический (дисплейный сервер Wayland)
Name[zh_CN]=经典Wayland 显现服务器)
Name[zh_TW]=經典Wayland顯示服務器
Name=Classic (Wayland display server)
Comment[de]=Diese Sitzung meldet Sie in GNOME Classic an
Comment[es]=Esta sesión inicia GNOME clásico
Comment[fr]=Cette session vous connnecte à GNOME Classique
Comment[it]=Questa sessione si avvia con GNOME classico
Comment[ja]=GNOME クラシックモードでログインします
Comment[ko]=이 세션을 사용하면 그놈 클래식에 로그인합니다
Comment[pt_BR]=Essa sessão se inicia como GNOME Clássico
Comment[ru]=Данный сеанс использует классический рабочий стол GNOME
Comment[zh_CN]=该会话将登录到“GNOME 经典模式”
Comment[zh_TW]=這個作業階段讓您登入 GNOME Classic
Comment=This session logs you into GNOME Classic
Exec=env GNOME_SHELL_SESSION_MODE=classic gnome-session --session gnome-classic
TryExec=gnome-session
Type=Application
DesktopNames=GNOME-Classic;GNOME;

@ -0,0 +1,27 @@
[Desktop Entry]
Name[de]=Klassisch (X11 Anzeige-Server)
Name[es]=Clásico (servidor gráfico X11)
Name[fr]=Classic (serveur affichage X11)
Name[it]=Classico (server grafico X11)
Name[ja]=クラシック (X11 ディスプレイサーバー)
Name[ko]=클래식 (X11 디스플레이 서버)
Name[pt_BR]=Clássico (servidor de exibição X11)
Name[ru]=Классический (дисплейный сервер X11)
Name[zh_CN]=经典X11 显示服务器)
Name[zh_TW]=經典X11顯示服務器
Name=Classic (X11 display server)
Comment[de]=Diese Sitzung meldet Sie in GNOME Classic an
Comment[es]=Esta sesión inicia GNOME clásico
Comment[fr]=Cette session vous connnecte à GNOME Classique
Comment[it]=Questa sessione si avvia con GNOME classico
Comment[ja]=GNOME クラシックモードでログインします
Comment[ko]=이 세션을 사용하면 그놈 클래식에 로그인합니다
Comment[pt_BR]=Essa sessão se inicia como GNOME Clássico
Comment[ru]=Данный сеанс использует классический рабочий стол GNOME
Comment[zh_CN]=该会话将登录到“GNOME 经典模式”
Comment[zh_TW]=這個作業階段讓您登入 GNOME Classic
Comment=This session logs you into GNOME Classic
Exec=env GNOME_SHELL_SESSION_MODE=classic gnome-session --session gnome-classic
TryExec=gnome-session
Type=Application
DesktopNames=GNOME-Classic;GNOME;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,126 @@
From f8ec838485ae81cf2e8ab2b899ad4154c7c06fbd 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 1f854aa2..fedc4195 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -358,7 +358,7 @@ class WindowButton extends BaseButton {
return;
}
- if (button == 1)
+ if (!button || button === 1)
_minimizeOrActivateWindow(this.metaWindow);
else
_openMenu(this._contextMenu);
@@ -601,7 +601,7 @@ class AppButton extends BaseButton {
if (contextMenuWasOpen)
this._contextMenu.close();
- if (button == 1) {
+ if (!button || button === 1) {
if (menuWasOpen)
return;
--
2.36.1
From d3cf07f8065935736e8a79d06ec79c971c453453 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 | 45 +++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index fedc4195..0baaeecb 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -229,6 +229,9 @@ class BaseButton {
this.actor.connect('clicked', this._onClicked.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
this.actor.connect('popup-menu', this._onPopupMenu.bind(this));
+ this.actor.connect('button-press-event', this._onButtonPress.bind(this));
+ this.actor.connect('button-release-event', this._onButtonRelease.bind(this));
+ this.actor.connect('touch-event', this._onTouch.bind(this));
this._contextMenuManager = new PopupMenu.PopupMenuManager(this);
@@ -250,6 +253,48 @@ class BaseButton {
return this.actor.has_style_class_name('focused');
}
+ _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;
+ }
+
+ _onButtonPress(button, event) {
+ if (event.get_button() === 1)
+ this._setLongPressTimeout();
+ return Clutter.EVENT_PROPAGATE;
+ }
+
+ _onButtonRelease() {
+ this._removeLongPressTimeout();
+ return Clutter.EVENT_PROPAGATE;
+ }
+
+ _onTouch(event) {
+ const type = event.get_type();
+ if (type === Clutter.EventType.TOUCH_BEGIN)
+ this._setLongPressTimeout();
+ else if (type === Clutter.EventType.TOUCH_END)
+ this._removeLongPressTimeout();
+ return Clutter.EVENT_PROPAGATE;
+ }
+
activate() {
if (this.active)
return;
--
2.36.1

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save