commit
10acbf6b75
@ -0,0 +1 @@
|
||||
SOURCES/gnome-shell-3.32.2.tar.xz
|
@ -0,0 +1 @@
|
||||
331e9cf71cd1d2a4e9238d87d216da4c6f3a400e SOURCES/gnome-shell-3.32.2.tar.xz
|
@ -0,0 +1,25 @@
|
||||
From f5ddd0fc02e99597e4b8506ac35523a6fa8ac22f Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Wed, 4 Mar 2020 16:08:31 +0100
|
||||
Subject: [PATCH] Do not change Wacom LEDs through g-s-d
|
||||
|
||||
Let the wacom kernel driver sort it out by itself.
|
||||
---
|
||||
js/ui/windowManager.js | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
|
||||
index dfe1b44..b2e938c 100644
|
||||
--- a/js/ui/windowManager.js
|
||||
+++ b/js/ui/windowManager.js
|
||||
@@ -1037,7 +1037,6 @@ var WindowManager = class {
|
||||
|
||||
if (this._gsdWacomProxy) {
|
||||
this._gsdWacomProxy.SetOLEDLabelsRemote(pad.get_device_node(), labels);
|
||||
- this._gsdWacomProxy.SetGroupModeLEDRemote(pad.get_device_node(), group, mode);
|
||||
}
|
||||
});
|
||||
|
||||
--
|
||||
2.24.1
|
||||
|
@ -0,0 +1,58 @@
|
||||
From a94260b4f2f72ea9328a0194b8656f1fb3e98675 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Sat, 14 Dec 2019 19:15:53 +0100
|
||||
Subject: [PATCH] a11y: Change HC icon theme first
|
||||
|
||||
There are two ways for applications to provide a high contrast icon:
|
||||
|
||||
1. install an icon into the HighContrast theme
|
||||
2. install a symbolic icon into the default hicolor theme
|
||||
|
||||
The latter is preferred nowadays, and implemented in the high-contrast
|
||||
CSS variant by enforcing the symbolic icon style.
|
||||
|
||||
However together with the way we currently enable/disable high-contrast,
|
||||
this can lead to the following race:
|
||||
1. the GTK theme is changed from HighContrast
|
||||
2. we reload the default stylesheet
|
||||
3. the icon style changes to "regular", so we request a
|
||||
new icon from the HighContrast icon theme
|
||||
4. the icon theme is changed from HighContrast
|
||||
5. we evict existing icons from the cache
|
||||
6. we reload icons for the new icon theme; however as we
|
||||
find a pending request (from 3), we re-use it
|
||||
7. the request from 3 finishes, and we end up with a
|
||||
wrong icon in the cache
|
||||
|
||||
The simplest fix is to change the icon theme before the GTK theme: Unlike the
|
||||
theme name, the icon style is encoded in the cache key, so we won't re-use
|
||||
an old (and incorrect) request in that case.
|
||||
---
|
||||
js/ui/status/accessibility.js | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/js/ui/status/accessibility.js b/js/ui/status/accessibility.js
|
||||
index 10223ec84..90948d465 100644
|
||||
--- a/js/ui/status/accessibility.js
|
||||
+++ b/js/ui/status/accessibility.js
|
||||
@@ -154,14 +154,14 @@ class ATIndicator extends PanelMenu.Button {
|
||||
interfaceSettings.is_writable(KEY_ICON_THEME),
|
||||
enabled => {
|
||||
if (enabled) {
|
||||
- interfaceSettings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
|
||||
interfaceSettings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME);
|
||||
+ interfaceSettings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
|
||||
} else if(!hasHC) {
|
||||
- interfaceSettings.set_string(KEY_GTK_THEME, gtkTheme);
|
||||
interfaceSettings.set_string(KEY_ICON_THEME, iconTheme);
|
||||
+ interfaceSettings.set_string(KEY_GTK_THEME, gtkTheme);
|
||||
} else {
|
||||
- interfaceSettings.reset(KEY_GTK_THEME);
|
||||
interfaceSettings.reset(KEY_ICON_THEME);
|
||||
+ interfaceSettings.reset(KEY_GTK_THEME);
|
||||
}
|
||||
});
|
||||
return highContrast;
|
||||
--
|
||||
2.23.0
|
||||
|
@ -0,0 +1,40 @@
|
||||
From 34e6bbeebef37ae688ca0527bde03fa26b143bb7 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Thu, 27 Jun 2019 14:27:34 -0400
|
||||
Subject: [PATCH] animation: fix unintentional loop while polkit dialog is
|
||||
active
|
||||
|
||||
The polkit password dialog has a spinner that gets displayed
|
||||
while the users password is being verified.
|
||||
|
||||
Unfortunately, the spinner stop method unintentionally calls
|
||||
back into itself after the stop fade out animation is complete.
|
||||
The stop method is called at startup, so the looping begins as
|
||||
soon as the dialog is visible and continues until the dialog is
|
||||
dismissed.
|
||||
|
||||
This commit fixes the loop by having the stop method cease
|
||||
calling itself, and instead having it call the stop method on the
|
||||
superclass.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/602
|
||||
---
|
||||
js/ui/animation.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/animation.js b/js/ui/animation.js
|
||||
index c21b22565..58d7f4018 100644
|
||||
--- a/js/ui/animation.js
|
||||
+++ b/js/ui/animation.js
|
||||
@@ -162,7 +162,7 @@ var Spinner = class extends AnimatedIcon {
|
||||
time: SPINNER_ANIMATION_TIME,
|
||||
transition: 'linear',
|
||||
onComplete: () => {
|
||||
- this.stop(false);
|
||||
+ super.stop();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,28 @@
|
||||
From 23755cc20f3c05b97f769e27553f2ab482d60137 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Wed, 20 May 2015 16:44:00 +0200
|
||||
Subject: [PATCH] app: Fall back to window title instead of WM_CLASS
|
||||
|
||||
It's a bad fallback as it's clearly window-specific (rather than
|
||||
app-specific), but it likely looks prettier when we fail to associate
|
||||
a .desktop file ...
|
||||
---
|
||||
src/shell-app.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/shell-app.c b/src/shell-app.c
|
||||
index 10efa9135..7d40186c9 100644
|
||||
--- a/src/shell-app.c
|
||||
+++ b/src/shell-app.c
|
||||
@@ -259,7 +259,7 @@ shell_app_get_name (ShellApp *app)
|
||||
const char *name = NULL;
|
||||
|
||||
if (window)
|
||||
- name = meta_window_get_wm_class (window);
|
||||
+ name = meta_window_get_title (window);
|
||||
if (!name)
|
||||
name = C_("program", "Unknown");
|
||||
return name;
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,111 @@
|
||||
From a1c35ebb8f29103035526e6f48eba4ff37551964 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 21 Jun 2018 18:03:31 +0200
|
||||
Subject: [PATCH] appDisplay: Show full app name on hover
|
||||
|
||||
---
|
||||
data/theme/gnome-shell-sass/_common.scss | 8 ++++
|
||||
js/ui/appDisplay.js | 48 ++++++++++++++++++++++++
|
||||
2 files changed, 56 insertions(+)
|
||||
|
||||
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
|
||||
index 3b0d2bf04..293ea2ab9 100644
|
||||
--- a/data/theme/gnome-shell-sass/_common.scss
|
||||
+++ b/data/theme/gnome-shell-sass/_common.scss
|
||||
@@ -1411,6 +1411,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;
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index adaefa7dd..a07db6573 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -1478,6 +1478,20 @@ var AppIcon = class AppIcon {
|
||||
this.actor.connect('clicked', this._onClicked.bind(this));
|
||||
this.actor.connect('popup-menu', this._onKeyboardPopupMenu.bind(this));
|
||||
|
||||
+ this._hoverText = null;
|
||||
+ this._hoverTimeoutId = 0;
|
||||
+
|
||||
+ if (this.icon.label) {
|
||||
+ this._hoverText = new St.Label({ style_class: 'app-well-hover-text',
|
||||
+ text: this.icon.label.text,
|
||||
+ visible: false });
|
||||
+ this._hoverText.clutter_text.line_wrap = true;
|
||||
+ Main.layoutManager.addChrome(this._hoverText);
|
||||
+
|
||||
+ this.actor.connect('notify::hover', this._syncHoverText.bind(this));
|
||||
+ this.connect('sync-tooltip', this._syncHoverText.bind(this));
|
||||
+ }
|
||||
+
|
||||
this._menu = null;
|
||||
this._menuManager = new PopupMenu.PopupMenuManager(this);
|
||||
|
||||
@@ -1509,12 +1523,39 @@ var AppIcon = class AppIcon {
|
||||
this.app.disconnect(this._stateChangedId);
|
||||
this._stateChangedId = 0;
|
||||
this._removeMenuTimeout();
|
||||
+ this._removeHoverTimeout();
|
||||
+ if (this._hoverText)
|
||||
+ this._hoverText.destroy();
|
||||
+ this._hoverText = null;
|
||||
}
|
||||
|
||||
_createIcon(iconSize) {
|
||||
return this.app.create_icon_texture(iconSize);
|
||||
}
|
||||
|
||||
+ _syncHoverText() {
|
||||
+ if (this.shouldShowTooltip()) {
|
||||
+ if (this._hoverTimeoutId)
|
||||
+ return;
|
||||
+
|
||||
+ this._hoverTimeoutId = Mainloop.timeout_add(300, () => {
|
||||
+ this._hoverText.style = `max-width: ${2 * this.icon.iconSize}px;`;
|
||||
+ this._hoverText.ensure_style();
|
||||
+
|
||||
+ let [x, y] = this.icon.label.get_transformed_position();
|
||||
+ let offset = (this._hoverText.width - this.icon.label.width) / 2;
|
||||
+ this._hoverText.set_position(Math.floor(x - offset), Math.floor(y));
|
||||
+ this._hoverText.show();
|
||||
+
|
||||
+ this._hoverTimeoutId = 0;
|
||||
+ return GLib.SOURCE_REMOVE;
|
||||
+ });
|
||||
+ } else {
|
||||
+ this._removeHoverTimeout();
|
||||
+ this._hoverText.hide();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
_removeMenuTimeout() {
|
||||
if (this._menuTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
@@ -1522,6 +1563,13 @@ var AppIcon = class AppIcon {
|
||||
}
|
||||
}
|
||||
|
||||
+ _removeHoverTimeout() {
|
||||
+ if (this._hoverTimeoutId > 0) {
|
||||
+ Mainloop.source_remove(this._hoverTimeoutId);
|
||||
+ this._hoverTimeoutId = 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
_updateRunningStyle() {
|
||||
if (this.app.state != Shell.AppState.STOPPED)
|
||||
this._dot.show();
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,29 @@
|
||||
From 165fc5147cd2c9bf4bc10a1c5a9a940ec4ddd8d9 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Tue, 15 Jan 2019 12:51:16 -0500
|
||||
Subject: [PATCH 1/4] background: refresh after suspend on wayland
|
||||
|
||||
At the moment we only refresh after suspend on Xorg.
|
||||
|
||||
We need to do it on wayland, too.
|
||||
---
|
||||
src/shell-util.c | 3 ---
|
||||
1 file changed, 3 deletions(-)
|
||||
|
||||
diff --git a/src/shell-util.c b/src/shell-util.c
|
||||
index 31bb18e70..c6e5abed6 100644
|
||||
--- a/src/shell-util.c
|
||||
+++ b/src/shell-util.c
|
||||
@@ -395,9 +395,6 @@ get_gl_vendor (void)
|
||||
gboolean
|
||||
shell_util_need_background_refresh (void)
|
||||
{
|
||||
- if (!clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
|
||||
- return FALSE;
|
||||
-
|
||||
if (g_strcmp0 (get_gl_vendor (), "NVIDIA Corporation") == 0)
|
||||
return TRUE;
|
||||
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,37 @@
|
||||
From 1dcae7bbba222a1c8bdfc2d76a9f716e638b0334 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Thu, 8 Jun 2017 12:04:31 -0400
|
||||
Subject: [PATCH] data: install process-working.svg to filesystem
|
||||
|
||||
This helps prevent unlock failure on inplace upgrades between
|
||||
7.3 and 7.4
|
||||
---
|
||||
data/theme/meson.build | 2 ++
|
||||
meson.build | 1 +
|
||||
2 files changed, 3 insertions(+)
|
||||
|
||||
diff --git a/data/theme/meson.build b/data/theme/meson.build
|
||||
index 22bae3dd2..d5acb8d10 100644
|
||||
--- a/data/theme/meson.build
|
||||
+++ b/data/theme/meson.build
|
||||
@@ -23,3 +23,5 @@ foreach style: styles
|
||||
],
|
||||
depend_files: theme_sources)
|
||||
endforeach
|
||||
+
|
||||
+install_data('process-working.svg', install_dir: themedir)
|
||||
diff --git a/meson.build b/meson.build
|
||||
index 21a80bcc8..0acaba705 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -57,6 +57,7 @@ localedir = join_paths(datadir, 'locale')
|
||||
portaldir = join_paths(datadir, 'xdg-desktop-portal', 'portals')
|
||||
schemadir = join_paths(datadir, 'glib-2.0', 'schemas')
|
||||
servicedir = join_paths(datadir, 'dbus-1', 'services')
|
||||
+themedir = join_paths(pkgdatadir, 'theme')
|
||||
|
||||
# XXX: Once https://github.com/systemd/systemd/issues/9595 is fixed and we can
|
||||
# depend on this version, replace with something like:
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,65 @@
|
||||
From 6e80934456f0b4cc48da6a7201700dc4386a3474 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 27 Feb 2020 13:46:44 -0800
|
||||
Subject: [PATCH] environment: reduce calls to g_time_zone_new_local()
|
||||
|
||||
Creating a new GTimeZone for the local timezone can be quite expensive if
|
||||
done repeatedly. It requires an open(), mmap(), and parsing of
|
||||
/etc/localtime.
|
||||
|
||||
This patch was provided by Florian, and I've tested it as far back as
|
||||
3.28.4 to ensure that we are really reducing the number of open() calls
|
||||
on the compositor thread.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/1051
|
||||
|
||||
Signed-off-by: Christian Hergert <chergert@redhat.com>
|
||||
---
|
||||
js/ui/environment.js | 22 +++++++++++++++++++++-
|
||||
1 file changed, 21 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/environment.js b/js/ui/environment.js
|
||||
index 9c125d3eb..809b48e45 100644
|
||||
--- a/js/ui/environment.js
|
||||
+++ b/js/ui/environment.js
|
||||
@@ -11,6 +11,9 @@ imports.gi.versions.TelepathyLogger = '0.2';
|
||||
|
||||
const { Clutter, Gio, GLib, Shell, St } = imports.gi;
|
||||
const Gettext = imports.gettext;
|
||||
+const System = imports.system;
|
||||
+
|
||||
+let _localTimeZone = null;
|
||||
|
||||
// We can't import shell JS modules yet, because they may have
|
||||
// variable initializations, etc, that depend on init() already having
|
||||
@@ -117,9 +120,26 @@ function init() {
|
||||
}
|
||||
};
|
||||
|
||||
+ // Override to clear our own timezone cache as well
|
||||
+ const origClearDateCaches = System.clearDateCaches;
|
||||
+ System.clearDateCaches = function () {
|
||||
+ _localTimeZone = null;
|
||||
+ origClearDateCaches();
|
||||
+ };
|
||||
+
|
||||
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
|
||||
Date.prototype.toLocaleFormat = function(format) {
|
||||
- return Shell.util_format_date(format, this.getTime());
|
||||
+ if (_localTimeZone === null)
|
||||
+ _localTimeZone = GLib.TimeZone.new_local();
|
||||
+
|
||||
+ let dt = GLib.DateTime.new(_localTimeZone,
|
||||
+ this.getYear(),
|
||||
+ this.getMonth() + 1,
|
||||
+ this.getDate(),
|
||||
+ this.getHours(),
|
||||
+ this.getMinutes(),
|
||||
+ this.getSeconds());
|
||||
+ return dt ? dt.format(format) : '';
|
||||
};
|
||||
|
||||
let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR');
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,87 @@
|
||||
From 1b6eb29ade832647510b36ddc13c9b88a25036df Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
|
||||
Date: Wed, 11 Sep 2019 20:18:20 +0200
|
||||
Subject: [PATCH 1/4] extensionSystem: Handle added or removed sessionMode
|
||||
extensions
|
||||
|
||||
Right now we're only handling added sessionMode extensions correctly on
|
||||
sessionMode updates, also handle the other case and disable removed
|
||||
sessionMode extensions on sessionMode updates.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/96
|
||||
---
|
||||
js/ui/extensionSystem.js | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
|
||||
index 81804ea5e..77929f2a6 100644
|
||||
--- a/js/ui/extensionSystem.js
|
||||
+++ b/js/ui/extensionSystem.js
|
||||
@@ -515,62 +515,62 @@ var ExtensionManager = class {
|
||||
if (!this._initted) {
|
||||
this._loadExtensions();
|
||||
this._initted = true;
|
||||
} else {
|
||||
this._enabledExtensions.forEach(uuid => {
|
||||
this._callExtensionEnable(uuid);
|
||||
});
|
||||
}
|
||||
this._enabled = true;
|
||||
}
|
||||
|
||||
_disableAllExtensions() {
|
||||
if (!this._enabled)
|
||||
return;
|
||||
|
||||
if (this._initted) {
|
||||
this._extensionOrder.slice().reverse().forEach(uuid => {
|
||||
this._callExtensionDisable(uuid);
|
||||
});
|
||||
}
|
||||
|
||||
this._enabled = false;
|
||||
}
|
||||
|
||||
_sessionUpdated() {
|
||||
// For now sessionMode.allowExtensions controls extensions from both the
|
||||
// 'enabled-extensions' preference and the sessionMode.enabledExtensions
|
||||
// property; it might make sense to make enabledExtensions independent
|
||||
// from allowExtensions in the future
|
||||
if (Main.sessionMode.allowExtensions) {
|
||||
- if (this._initted)
|
||||
- this._enabledExtensions = this._getEnabledExtensions();
|
||||
+ // Take care of added or removed sessionMode extensions
|
||||
+ this._onEnabledExtensionsChanged();
|
||||
this._enableAllExtensions();
|
||||
} else {
|
||||
this._disableAllExtensions();
|
||||
}
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(ExtensionManager.prototype);
|
||||
|
||||
class ExtensionUpdateSource extends MessageTray.Source {
|
||||
constructor() {
|
||||
const appSys = Shell.AppSystem.get_default();
|
||||
this._app = appSys.lookup_app('gnome-shell-extension-prefs.desktop');
|
||||
|
||||
super(this._app.get_name());
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
return this._app.app_info.get_icon();
|
||||
}
|
||||
|
||||
_createPolicy() {
|
||||
return new MessageTray.NotificationApplicationPolicy(this._app.id);
|
||||
}
|
||||
|
||||
open() {
|
||||
this._app.activate();
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
}
|
||||
}
|
||||
--
|
||||
2.27.0
|
||||
|
@ -0,0 +1,42 @@
|
||||
From 720eb83ba0b0e5e37185d7e7ed86fe9175cf18f4 Mon Sep 17 00:00:00 2001
|
||||
From: Rui Matos <tiagomatos@gmail.com>
|
||||
Date: Fri, 8 Nov 2013 13:58:09 +0100
|
||||
Subject: [PATCH] extensions: Add a SESSION_MODE extension type
|
||||
|
||||
This allows e.g. gnome-tweak-tool to present these extensions in a
|
||||
different way since they can't be disabled.
|
||||
---
|
||||
js/misc/extensionUtils.js | 3 ++-
|
||||
js/ui/extensionSystem.js | 2 ++
|
||||
2 files changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/misc/extensionUtils.js b/js/misc/extensionUtils.js
|
||||
index cf308b31f..fb1e2b506 100644
|
||||
--- a/js/misc/extensionUtils.js
|
||||
+++ b/js/misc/extensionUtils.js
|
||||
@@ -13,7 +13,8 @@ const FileUtils = imports.misc.fileUtils;
|
||||
|
||||
var ExtensionType = {
|
||||
SYSTEM: 1,
|
||||
- PER_USER: 2
|
||||
+ PER_USER: 2,
|
||||
+ SESSION_MODE: 3
|
||||
};
|
||||
|
||||
// Maps uuid -> metadata object
|
||||
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
|
||||
index 6244c39b4..9ffdb4f3d 100644
|
||||
--- a/js/ui/extensionSystem.js
|
||||
+++ b/js/ui/extensionSystem.js
|
||||
@@ -322,6 +322,8 @@ function _loadExtensions() {
|
||||
let finder = new ExtensionUtils.ExtensionFinder();
|
||||
finder.connect('extension-found', (finder, extension) => {
|
||||
loadExtension(extension);
|
||||
+ if (Main.sessionMode.enabledExtensions.indexOf(extension.uuid) != -1)
|
||||
+ extension.type = ExtensionUtils.ExtensionType.SESSION_MODE;
|
||||
});
|
||||
finder.scanExtensions();
|
||||
}
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,237 @@
|
||||
From 592bf9b4ba879a365375a7edcb6c48258386e413 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Tue, 18 Jul 2017 12:58:14 -0400
|
||||
Subject: [PATCH 1/2] gdm: add AuthList control
|
||||
|
||||
Ultimately, we want to add support for GDM's new ChoiceList
|
||||
PAM extension. That extension allows PAM modules to present
|
||||
a list of choices to the user. Before we can support that
|
||||
extension, however, we need to have a list control in the
|
||||
login-screen/unlock screen. This commit adds that control.
|
||||
|
||||
For the most part, it's a copy-and-paste of the gdm userlist,
|
||||
but with less features. It lacks API specific to the users,
|
||||
lacks the built in timed login indicator, etc. It does feature
|
||||
a label heading.
|
||||
---
|
||||
js/gdm/authList.js | 195 ++++++++++++++++++++++++++++++++++
|
||||
js/js-resources.gresource.xml | 1 +
|
||||
2 files changed, 196 insertions(+)
|
||||
create mode 100644 js/gdm/authList.js
|
||||
|
||||
diff --git a/js/gdm/authList.js b/js/gdm/authList.js
|
||||
new file mode 100644
|
||||
index 000000000..fc1c3d6e4
|
||||
--- /dev/null
|
||||
+++ b/js/gdm/authList.js
|
||||
@@ -0,0 +1,195 @@
|
||||
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
+/*
|
||||
+ * Copyright 2017 Red Hat, Inc
|
||||
+ *
|
||||
+ * 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, 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 Clutter = imports.gi.Clutter;
|
||||
+const GObject = imports.gi.GObject;
|
||||
+const Gtk = imports.gi.Gtk;
|
||||
+const Lang = imports.lang;
|
||||
+const Meta = imports.gi.Meta;
|
||||
+const Signals = imports.signals;
|
||||
+const St = imports.gi.St;
|
||||
+
|
||||
+const Tweener = imports.ui.tweener;
|
||||
+
|
||||
+const _SCROLL_ANIMATION_TIME = 0.5;
|
||||
+
|
||||
+const AuthListItem = new Lang.Class({
|
||||
+ Name: 'AuthListItem',
|
||||
+
|
||||
+ _init(key, text) {
|
||||
+ this.key = key;
|
||||
+ let label = new St.Label({ style_class: 'auth-list-item-label',
|
||||
+ y_align: Clutter.ActorAlign.CENTER });
|
||||
+ label.text = text;
|
||||
+
|
||||
+ this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
|
||||
+ button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
+ can_focus: true,
|
||||
+ child: label,
|
||||
+ reactive: true,
|
||||
+ x_align: St.Align.START,
|
||||
+ x_fill: true });
|
||||
+
|
||||
+ this.actor.connect('key-focus-in', () => {
|
||||
+ this._setSelected(true);
|
||||
+ });
|
||||
+ this.actor.connect('key-focus-out', () => {
|
||||
+ this._setSelected(false);
|
||||
+ });
|
||||
+ this.actor.connect('notify::hover', () => {
|
||||
+ this._setSelected(this.actor.hover);
|
||||
+ });
|
||||
+
|
||||
+ this.actor.connect('clicked', this._onClicked.bind(this));
|
||||
+ },
|
||||
+
|
||||
+ _onClicked() {
|
||||
+ this.emit('activate');
|
||||
+ },
|
||||
+
|
||||
+ _setSelected(selected) {
|
||||
+ if (selected) {
|
||||
+ this.actor.add_style_pseudo_class('selected');
|
||||
+ this.actor.grab_key_focus();
|
||||
+ } else {
|
||||
+ this.actor.remove_style_pseudo_class('selected');
|
||||
+ }
|
||||
+ }
|
||||
+});
|
||||
+Signals.addSignalMethods(AuthListItem.prototype);
|
||||
+
|
||||
+var AuthList = new Lang.Class({
|
||||
+ Name: 'AuthList',
|
||||
+
|
||||
+ _init() {
|
||||
+ this.actor = new St.BoxLayout({ vertical: true,
|
||||
+ style_class: 'login-dialog-auth-list-layout' });
|
||||
+
|
||||
+ this.label = new St.Label({ style_class: 'prompt-dialog-headline' });
|
||||
+ this.actor.add_actor(this.label);
|
||||
+
|
||||
+ this._scrollView = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
|
||||
+ this._scrollView.set_policy(Gtk.PolicyType.NEVER,
|
||||
+ Gtk.PolicyType.AUTOMATIC);
|
||||
+ this.actor.add_actor(this._scrollView);
|
||||
+
|
||||
+ this._box = new St.BoxLayout({ vertical: true,
|
||||
+ style_class: 'login-dialog-user-list',
|
||||
+ pseudo_class: 'expanded' });
|
||||
+
|
||||
+ this._scrollView.add_actor(this._box);
|
||||
+ this._items = {};
|
||||
+
|
||||
+ this.actor.connect('key-focus-in', this._moveFocusToItems.bind(this));
|
||||
+ },
|
||||
+
|
||||
+ _moveFocusToItems() {
|
||||
+ let hasItems = Object.keys(this._items).length > 0;
|
||||
+
|
||||
+ if (!hasItems)
|
||||
+ return;
|
||||
+
|
||||
+ if (global.stage.get_key_focus() != this.actor)
|
||||
+ return;
|
||||
+
|
||||
+ let focusSet = this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
+ if (!focusSet) {
|
||||
+ Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
|
||||
+ this._moveFocusToItems();
|
||||
+ return false;
|
||||
+ });
|
||||
+ }
|
||||
+ },
|
||||
+
|
||||
+ _onItemActivated(activatedItem) {
|
||||
+ this.emit('activate', activatedItem.key);
|
||||
+ },
|
||||
+
|
||||
+ scrollToItem(item) {
|
||||
+ let box = item.actor.get_allocation_box();
|
||||
+
|
||||
+ let adjustment = this._scrollView.get_vscroll_bar().get_adjustment();
|
||||
+
|
||||
+ let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
|
||||
+ Tweener.removeTweens(adjustment);
|
||||
+ Tweener.addTween (adjustment,
|
||||
+ { value: value,
|
||||
+ time: _SCROLL_ANIMATION_TIME,
|
||||
+ transition: 'easeOutQuad' });
|
||||
+ },
|
||||
+
|
||||
+ jumpToItem(item) {
|
||||
+ let box = item.actor.get_allocation_box();
|
||||
+
|
||||
+ let adjustment = this._scrollView.get_vscroll_bar().get_adjustment();
|
||||
+
|
||||
+ let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
|
||||
+
|
||||
+ adjustment.set_value(value);
|
||||
+ },
|
||||
+
|
||||
+ getItem(key) {
|
||||
+ let item = this._items[key];
|
||||
+
|
||||
+ if (!item)
|
||||
+ return null;
|
||||
+
|
||||
+ return item;
|
||||
+ },
|
||||
+
|
||||
+ addItem(key, text) {
|
||||
+ this.removeItem(key);
|
||||
+
|
||||
+ let item = new AuthListItem(key, text);
|
||||
+ this._box.add(item.actor, { x_fill: true });
|
||||
+
|
||||
+ this._items[key] = item;
|
||||
+
|
||||
+ item.connect('activate',
|
||||
+ this._onItemActivated.bind(this));
|
||||
+
|
||||
+ // Try to keep the focused item front-and-center
|
||||
+ item.actor.connect('key-focus-in',
|
||||
+ () => { this.scrollToItem(item); });
|
||||
+
|
||||
+ this._moveFocusToItems();
|
||||
+
|
||||
+ this.emit('item-added', item);
|
||||
+ },
|
||||
+
|
||||
+ removeItem(key) {
|
||||
+ let item = this._items[key];
|
||||
+
|
||||
+ if (!item)
|
||||
+ return;
|
||||
+
|
||||
+ item.actor.destroy();
|
||||
+ delete this._items[key];
|
||||
+ },
|
||||
+
|
||||
+ numItems() {
|
||||
+ return Object.keys(this._items).length;
|
||||
+ },
|
||||
+
|
||||
+ clear() {
|
||||
+ this.label.text = "";
|
||||
+ this._box.destroy_all_children();
|
||||
+ this._items = {};
|
||||
+ }
|
||||
+});
|
||||
+Signals.addSignalMethods(AuthList.prototype);
|
||||
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
|
||||
index 836d1c674..002b202f8 100644
|
||||
--- a/js/js-resources.gresource.xml
|
||||
+++ b/js/js-resources.gresource.xml
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gnome/shell">
|
||||
+ <file>gdm/authList.js</file>
|
||||
<file>gdm/authPrompt.js</file>
|
||||
<file>gdm/batch.js</file>
|
||||
<file>gdm/fingerprint.js</file>
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,39 @@
|
||||
From 2acede02f30833c3fb891db8483f933f7b41508c Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Wed, 21 Oct 2020 21:32:03 +0200
|
||||
Subject: [PATCH] keyboard: Only enable keyboard if
|
||||
ClutterDeviceManager::touch-mode is enabled
|
||||
|
||||
---
|
||||
js/ui/keyboard.js | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/keyboard.js b/js/ui/keyboard.js
|
||||
index 94b5325..b1ee270 100644
|
||||
--- a/js/ui/keyboard.js
|
||||
+++ b/js/ui/keyboard.js
|
||||
@@ -1051,6 +1051,9 @@ var Keyboard = class Keyboard {
|
||||
this._suggestions = null;
|
||||
this._emojiKeyVisible = true;
|
||||
|
||||
+ let manager = Clutter.DeviceManager.get_default();
|
||||
+ manager.connect('notify::touch-mode', this._syncEnabled.bind(this));
|
||||
+
|
||||
this._focusTracker = new FocusTracker();
|
||||
this._focusTracker.connect('position-changed', this._onFocusPositionChanged.bind(this));
|
||||
this._focusTracker.connect('reset', () => {
|
||||
@@ -1120,8 +1123,10 @@ var Keyboard = class Keyboard {
|
||||
|
||||
_syncEnabled() {
|
||||
let wasEnabled = this._enabled;
|
||||
+ let manager = Clutter.DeviceManager.get_default();
|
||||
+ let autoEnabled = manager.get_touch_mode() && this._lastDeviceIsTouchscreen();
|
||||
this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
|
||||
- this._enabled = this._enableKeyboard || this._lastDeviceIsTouchscreen();
|
||||
+ this._enabled = this._enableKeyboard || autoEnabled;
|
||||
if (!this._enabled && !this._keyboardController)
|
||||
return;
|
||||
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,51 @@
|
||||
From d2661753076a60a7981836e4a85e88c4588fb1b2 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 17 Nov 2022 15:21:42 +0100
|
||||
Subject: [PATCH] layout: Initialize regions unconditionally
|
||||
|
||||
We currently initialize regions in all code paths except for the
|
||||
greeter. But while there are no windows on the login screen, the
|
||||
work area can still be used for positioning, for example for
|
||||
notifications.
|
||||
|
||||
Part-of:
|
||||
<https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2546>
|
||||
---
|
||||
js/ui/layout.js | 15 +++++++--------
|
||||
1 file changed, 7 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/js/ui/layout.js b/js/ui/layout.js
|
||||
index beb4c0a5d..bb51946b7 100644
|
||||
--- a/js/ui/layout.js
|
||||
+++ b/js/ui/layout.js
|
||||
@@ -624,20 +624,19 @@ var LayoutManager = GObject.registerClass({
|
||||
reactive: true });
|
||||
this.addChrome(this._coverPane);
|
||||
|
||||
+ // Force an update of the regions before we scale the UI group to
|
||||
+ // get the correct allocation for the struts.
|
||||
+ // Do this even when we don't animate on restart, so that maximized
|
||||
+ // windows restore to the right size.
|
||||
+ this._updateRegions();
|
||||
+
|
||||
if (Meta.is_restart()) {
|
||||
- // On restart, we don't do an animation. Force an update of the
|
||||
- // regions immediately so that maximized windows restore to the
|
||||
- // right size taking struts into account.
|
||||
- this._updateRegions();
|
||||
+ // On restart, we don't do an animation.
|
||||
} else if (Main.sessionMode.isGreeter) {
|
||||
this.panelBox.translation_y = -this.panelBox.height;
|
||||
} else {
|
||||
this._updateBackgrounds();
|
||||
|
||||
- // We need to force an update of the regions now before we scale
|
||||
- // the UI group to get the correct allocation for the struts.
|
||||
- this._updateRegions();
|
||||
-
|
||||
this.keyboardBox.hide();
|
||||
|
||||
let monitor = this.primaryMonitor;
|
||||
--
|
||||
2.38.1
|
||||
|
@ -0,0 +1,56 @@
|
||||
From 35cbad572120125d3b823f37d2100b2beee4c1d8 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 8 Jun 2017 17:07:56 +0200
|
||||
Subject: [PATCH] layout: Make the hot corner optional
|
||||
|
||||
Whether people love or hate the hot corner depends in large extents
|
||||
on hardware sensitivity and habits, which is hard to get right
|
||||
universally. So bite the bullet and support an option to enable or
|
||||
disable hot corners ...
|
||||
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=688320
|
||||
---
|
||||
js/ui/layout.js | 14 +++++++++++++-
|
||||
1 file changed, 13 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/layout.js b/js/ui/layout.js
|
||||
index 2b3bb7442..beb4c0a5d 100644
|
||||
--- a/js/ui/layout.js
|
||||
+++ b/js/ui/layout.js
|
||||
@@ -1,6 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
-const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
+const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Background = imports.ui.background;
|
||||
@@ -267,6 +267,13 @@ var LayoutManager = GObject.registerClass({
|
||||
this._backgroundGroup.lower_bottom();
|
||||
this._bgManagers = [];
|
||||
|
||||
+ this._interfaceSettings = new Gio.Settings({
|
||||
+ schema_id: 'org.gnome.desktop.interface'
|
||||
+ });
|
||||
+
|
||||
+ this._interfaceSettings.connect('changed::enable-hot-corners',
|
||||
+ this._updateHotCorners.bind(this));
|
||||
+
|
||||
// Need to update struts on new workspaces when they are added
|
||||
let workspaceManager = global.workspace_manager;
|
||||
workspaceManager.connect('notify::n-workspaces',
|
||||
@@ -358,6 +365,11 @@ var LayoutManager = GObject.registerClass({
|
||||
});
|
||||
this.hotCorners = [];
|
||||
|
||||
+ if (!this._interfaceSettings.get_boolean('enable-hot-corners')) {
|
||||
+ this.emit('hot-corners-changed');
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
let size = this.panelBox.height;
|
||||
|
||||
// build new hot corners
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,49 @@
|
||||
From 6d26b6f9f66e14843f175305441a2464dd255fd1 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 27 Jul 2020 10:58:49 -0400
|
||||
Subject: [PATCH] loginDialog: Reset auth prompt on vt switch before fade in
|
||||
|
||||
At the moment, if a user switches to the login screen vt,
|
||||
the login screen fades in whatever was on screen prior, and
|
||||
then does a reset.
|
||||
|
||||
It makes more sense to reset first, so we fade in what the
|
||||
user is going to interact with instead of what they interacted
|
||||
with before.
|
||||
|
||||
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2997
|
||||
---
|
||||
js/gdm/loginDialog.js | 10 ++++------
|
||||
1 file changed, 4 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
|
||||
index 214c2f512..eb6846d5c 100644
|
||||
--- a/js/gdm/loginDialog.js
|
||||
+++ b/js/gdm/loginDialog.js
|
||||
@@ -923,6 +923,9 @@ var LoginDialog = GObject.registerClass({
|
||||
if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||
return;
|
||||
|
||||
+ if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||
+ this._authPrompt.reset();
|
||||
+
|
||||
Tweener.addTween(this,
|
||||
{ opacity: 255,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
@@ -935,12 +938,7 @@ var LoginDialog = GObject.registerClass({
|
||||
children[i].opacity = this.opacity;
|
||||
}
|
||||
},
|
||||
- onUpdateScope: this,
|
||||
- onComplete() {
|
||||
- if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||
- this._authPrompt.reset();
|
||||
- },
|
||||
- onCompleteScope: this });
|
||||
+ onUpdateScope: this });
|
||||
}
|
||||
|
||||
_gotGreeterSessionProxy(proxy) {
|
||||
--
|
||||
2.32.0
|
||||
|
@ -0,0 +1,32 @@
|
||||
From 9cfa56d4f3c5fe513630c58c09bd2421f3ca580b Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 26 Jun 2017 14:35:05 -0400
|
||||
Subject: [PATCH] loginDialog: make info messages themed
|
||||
|
||||
They were lacking a definition before leading them to
|
||||
show up invisible.
|
||||
---
|
||||
data/theme/gnome-shell-sass/_common.scss | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
|
||||
index c2df28279..a382ce561 100644
|
||||
--- a/data/theme/gnome-shell-sass/_common.scss
|
||||
+++ b/data/theme/gnome-shell-sass/_common.scss
|
||||
@@ -1801,7 +1801,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;
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,38 @@
|
||||
From ba3ce64fbbce20192a55f9d438d1032c0bac0557 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 29 Oct 2020 18:21:06 +0100
|
||||
Subject: [PATCH] main: Dump stack on segfaults by default
|
||||
|
||||
---
|
||||
src/main.c | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/main.c b/src/main.c
|
||||
index 245837783..788309de7 100644
|
||||
--- a/src/main.c
|
||||
+++ b/src/main.c
|
||||
@@ -39,6 +39,7 @@ static int caught_signal = 0;
|
||||
#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1
|
||||
#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4
|
||||
|
||||
+#define DEFAULT_SHELL_DEBUG SHELL_DEBUG_BACKTRACE_SEGFAULTS
|
||||
enum {
|
||||
SHELL_DEBUG_BACKTRACE_WARNINGS = 1,
|
||||
SHELL_DEBUG_BACKTRACE_SEGFAULTS = 2,
|
||||
@@ -268,8 +269,11 @@ shell_init_debug (const char *debug_env)
|
||||
{ "backtrace-segfaults", SHELL_DEBUG_BACKTRACE_SEGFAULTS },
|
||||
};
|
||||
|
||||
- _shell_debug = g_parse_debug_string (debug_env, keys,
|
||||
- G_N_ELEMENTS (keys));
|
||||
+ if (debug_env)
|
||||
+ _shell_debug = g_parse_debug_string (debug_env, keys,
|
||||
+ G_N_ELEMENTS (keys));
|
||||
+ else
|
||||
+ _shell_debug = DEFAULT_SHELL_DEBUG;
|
||||
}
|
||||
|
||||
static void
|
||||
--
|
||||
2.29.2
|
||||
|
@ -0,0 +1,49 @@
|
||||
From 0d95c2087aba7f0b07cb303c1f15d097b45f1b09 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
|
||||
Date: Tue, 28 Apr 2020 23:26:11 +0200
|
||||
Subject: [PATCH] main: Unset the right prevFocus actor after the focus stack
|
||||
got shifted
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When a modal that's not on top of the modalActorFocusStack gets popped,
|
||||
we shift the focus stack as described in popModal() to ensure the chain
|
||||
remains correct. That however destroys the association of a modal actor
|
||||
and its prevFocus actor on the focus stack, because the prevFocus actors
|
||||
are now moved to different entries of the stack.
|
||||
|
||||
Now when a prevFocus actor gets destroyed, we don't handle that case
|
||||
correctly and search for the modal actor that was associated with the
|
||||
prevFocus actor before the stack was shifted, which means we end up
|
||||
unsetting the wrong prevFocus actor.
|
||||
|
||||
So fix that and search the stack for the prevFocus actor which is being
|
||||
destroyed instead to unset the correct entry.
|
||||
|
||||
Thanks to Florian Müllner for figuring out the actual issue and
|
||||
proposing this fix.
|
||||
|
||||
Fixes https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2446
|
||||
---
|
||||
js/ui/main.js | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index dd1d8463d..ca3dcaa3c 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -486,7 +486,9 @@ function pushModal(actor, params) {
|
||||
let prevFocusDestroyId;
|
||||
if (prevFocus != null) {
|
||||
prevFocusDestroyId = prevFocus.connect('destroy', () => {
|
||||
- let index = _findModal(actor);
|
||||
+ const index = modalActorFocusStack.findIndex(
|
||||
+ record => record.prevFocus === prevFocus);
|
||||
+
|
||||
if (index >= 0)
|
||||
modalActorFocusStack[index].prevFocus = null;
|
||||
});
|
||||
--
|
||||
2.35.1
|
||||
|
@ -0,0 +1,29 @@
|
||||
From bd4a3186dc21f2c8d3e0f851cf262a34ddb6b625 Mon Sep 17 00:00:00 2001
|
||||
From: Lubomir Rintel <lkundrak@v3.sk>
|
||||
Date: Fri, 4 Oct 2019 14:21:25 +0200
|
||||
Subject: [PATCH] networkAgent: add support for SAE secrets
|
||||
|
||||
NetworkManager supports "WPA3 Personal" networks for some time now, they
|
||||
use the SAE authentication. Add support for it alongside other
|
||||
password-based mechanisms.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/751
|
||||
---
|
||||
js/ui/components/networkAgent.js | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/js/ui/components/networkAgent.js b/js/ui/components/networkAgent.js
|
||||
index 32d40fb2b..3ff957bf6 100644
|
||||
--- a/js/ui/components/networkAgent.js
|
||||
+++ b/js/ui/components/networkAgent.js
|
||||
@@ -216,6 +216,7 @@ var NetworkSecretDialog = class extends ModalDialog.ModalDialog {
|
||||
// First the easy ones
|
||||
case 'wpa-none':
|
||||
case 'wpa-psk':
|
||||
+ case 'sae':
|
||||
secrets.push({ label: _("Password: "), key: 'psk',
|
||||
value: wirelessSecuritySetting.psk || '',
|
||||
validate: this._validateWpaPsk, password: true });
|
||||
--
|
||||
2.32.0
|
||||
|
@ -0,0 +1,80 @@
|
||||
From 2bb826291c420dd1b601758c7a686ac48e1086a6 Mon Sep 17 00:00:00 2001
|
||||
From: Carlos Garnacho <carlosg@gnome.org>
|
||||
Date: Mon, 16 Dec 2019 12:39:49 +0100
|
||||
Subject: [PATCH] padOsd: Re-query action labels after mode switches
|
||||
|
||||
Do this so the pad OSD is able to update dynamically to mode changes,
|
||||
showing immediately the new actions for the current mode(s).
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/898
|
||||
---
|
||||
js/ui/padOsd.js | 31 ++++++++++++++++++++++++++++---
|
||||
1 file changed, 28 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/js/ui/padOsd.js b/js/ui/padOsd.js
|
||||
index a4af47297..b4b3fe453 100644
|
||||
--- a/js/ui/padOsd.js
|
||||
+++ b/js/ui/padOsd.js
|
||||
@@ -555,6 +555,14 @@ var PadDiagram = GObject.registerClass({
|
||||
this.add_actor(label);
|
||||
}
|
||||
|
||||
+ updateLabels(callback) {
|
||||
+ for (let i = 0; i < this._labels.length; i++) {
|
||||
+ let [label, action, idx, dir] = this._labels[i];
|
||||
+ let str = callback(action, idx, dir);
|
||||
+ label.set_text(str);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
_applyLabel(label, action, idx, dir, str) {
|
||||
if (str != null) {
|
||||
label.set_text(str);
|
||||
@@ -758,17 +766,29 @@ var PadOsd = class {
|
||||
global.display.request_pad_osd(pad, editionMode);
|
||||
}
|
||||
|
||||
- _createLabel(type, number, dir) {
|
||||
+ _getActionText(type, number) {
|
||||
let str = global.display.get_pad_action_label(this.padDevice, type, number);
|
||||
- let label = new St.Label({ text: str ? str : _("None") });
|
||||
+ return str ? str : _("None");
|
||||
+ }
|
||||
+
|
||||
+ _createLabel(type, number, dir) {
|
||||
+ let label = new St.Label({ text: this._getActionText(type, number) });
|
||||
this._padDiagram.addLabel(label, type, number, dir);
|
||||
}
|
||||
|
||||
+ _updateActionLabels() {
|
||||
+ this._padDiagram.updateLabels(this._getActionText.bind(this));
|
||||
+ }
|
||||
+
|
||||
_onCapturedEvent(actor, event) {
|
||||
+ let isModeSwitch =
|
||||
+ (event.type() == Clutter.EventType.PAD_BUTTON_PRESS ||
|
||||
+ event.type() == Clutter.EventType.PAD_BUTTON_RELEASE) &&
|
||||
+ this.padDevice.get_mode_switch_button_group(event.get_button()) >= 0;
|
||||
+
|
||||
if (event.type() == Clutter.EventType.PAD_BUTTON_PRESS &&
|
||||
event.get_source_device() == this.padDevice) {
|
||||
this._padDiagram.activateButton(event.get_button());
|
||||
- let isModeSwitch = this.padDevice.get_mode_switch_button_group(event.get_button()) >= 0;
|
||||
|
||||
/* Buttons that switch between modes cannot be edited */
|
||||
if (this._editionMode && !isModeSwitch)
|
||||
@@ -777,6 +797,11 @@ var PadOsd = class {
|
||||
} else if (event.type() == Clutter.EventType.PAD_BUTTON_RELEASE &&
|
||||
event.get_source_device() == this.padDevice) {
|
||||
this._padDiagram.deactivateButton(event.get_button());
|
||||
+
|
||||
+ if (isModeSwitch) {
|
||||
+ this._endActionEdition();
|
||||
+ this._updateActionLabels();
|
||||
+ }
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (event.type() == Clutter.EventType.KEY_PRESS &&
|
||||
(!this._editionMode || event.get_key_symbol() == Clutter.Escape)) {
|
||||
--
|
||||
2.24.0
|
||||
|
@ -0,0 +1,54 @@
|
||||
From aadb0e19999c339ac1d6501a2e52b363e57e26ef Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Wed, 15 Jan 2014 16:45:34 -0500
|
||||
Subject: [PATCH] panel: add an icon to the ActivitiesButton
|
||||
|
||||
Requested by brand
|
||||
---
|
||||
data/theme/gnome-shell-sass/_common.scss | 5 +++++
|
||||
js/ui/panel.js | 9 ++++++++-
|
||||
2 files changed, 13 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
|
||||
index a382ce561..3b0d2bf04 100644
|
||||
--- a/data/theme/gnome-shell-sass/_common.scss
|
||||
+++ b/data/theme/gnome-shell-sass/_common.scss
|
||||
@@ -769,6 +769,11 @@ StScrollBar {
|
||||
//dimensions of the icon are hardcoded
|
||||
}
|
||||
|
||||
+ .panel-logo-icon {
|
||||
+ padding-right: .4em;
|
||||
+ icon-size: 1em;
|
||||
+ }
|
||||
+
|
||||
&:hover {
|
||||
color: lighten($fg_color, 10%);
|
||||
}
|
||||
diff --git a/js/ui/panel.js b/js/ui/panel.js
|
||||
index 16484850a..ede1c2b82 100644
|
||||
--- a/js/ui/panel.js
|
||||
+++ b/js/ui/panel.js
|
||||
@@ -465,11 +465,18 @@ class ActivitiesButton extends PanelMenu.Button {
|
||||
|
||||
this.actor.name = 'panelActivities';
|
||||
|
||||
+ let box = new St.BoxLayout();
|
||||
+ this.actor.add_actor(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' });
|
||||
+ box.add_actor(this._icon);
|
||||
+
|
||||
/* Translators: If there is no suitable word for "Activities"
|
||||
in your language, you can use the word for "Overview". */
|
||||
this._label = new St.Label({ text: _("Activities"),
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
- this.actor.add_actor(this._label);
|
||||
+ box.add_actor(this._label);
|
||||
|
||||
this.actor.label_actor = this._label;
|
||||
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,36 @@
|
||||
From fb0a9a60ab8f1c0dd96e789969ab9b6e48a9fce4 Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Fourdan <ofourdan@redhat.com>
|
||||
Date: Tue, 21 Jul 2020 16:33:04 +0200
|
||||
Subject: [PATCH] popupMenu: Handle keypress if numlock is enabled
|
||||
|
||||
On Wayland, navigating menus with the keyboard would not open drop-down
|
||||
menus when NumLock is enabled.
|
||||
|
||||
That's old issue (gnome-shell#550) that was not completely fixed with
|
||||
commit 88556226 because the lock mask needs to be filtered out in
|
||||
_onKeyPress() as well.
|
||||
|
||||
Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/550
|
||||
---
|
||||
js/ui/popupMenu.js | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
|
||||
index 6de081ce81..9835face19 100644
|
||||
--- a/js/ui/popupMenu.js
|
||||
+++ b/js/ui/popupMenu.js
|
||||
@@ -801,9 +801,10 @@ var PopupMenu = class extends PopupMenuBase {
|
||||
|
||||
let state = event.get_state();
|
||||
|
||||
- // if user has a modifier down (except capslock)
|
||||
+ // if user has a modifier down (except capslock and numlock)
|
||||
// then don't handle the key press here
|
||||
state &= ~Clutter.ModifierType.LOCK_MASK;
|
||||
+ state &= ~Clutter.ModifierType.MOD2_MASK;
|
||||
state &= Clutter.ModifierType.MODIFIER_MASK;
|
||||
|
||||
if (state)
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,33 @@
|
||||
From cacce594f07295bb1b9e0685913a287e3cea2453 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Fri, 3 Jul 2015 13:54:36 -0400
|
||||
Subject: [PATCH] screenShield: unblank when inserting smartcard
|
||||
|
||||
If a user inserts the smartcard when the screen is locked/blanked
|
||||
we should ask them their pin right away.
|
||||
|
||||
At the moment they have to wiggle the mouse or do some other
|
||||
action to get the screen to unblank.
|
||||
---
|
||||
js/ui/screenShield.js | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
|
||||
index a005a206b..cd38f11fc 100644
|
||||
--- a/js/ui/screenShield.js
|
||||
+++ b/js/ui/screenShield.js
|
||||
@@ -513,8 +513,10 @@ var ScreenShield = class {
|
||||
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
||||
this._smartcardManager.connect('smartcard-inserted',
|
||||
(manager, token) => {
|
||||
- if (this._isLocked && token.UsedToLogin)
|
||||
+ if (this._isLocked && token.UsedToLogin) {
|
||||
+ this._wakeUpScreen();
|
||||
this._liftShield(true, 0);
|
||||
+ }
|
||||
});
|
||||
|
||||
this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,253 @@
|
||||
From 67a4506d4d8a0cbbaca5df4adfc309e54e557aee Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 5 Jan 2021 12:04:23 +0100
|
||||
Subject: [PATCH] screencast: Stop recording when screen size or resource scale
|
||||
change
|
||||
|
||||
Video encoders don't really handle changing the size of the video, and if
|
||||
we'd e.g. change resolution while recording, we would end up with a corrupt
|
||||
video file. Handle this more gracefully by stopping the recording if the
|
||||
conditions change.
|
||||
---
|
||||
js/ui/screencast.js | 92 +++++++++++++++++++++++++++++++++++++++++---
|
||||
src/shell-recorder.c | 50 ++++++++++++------------
|
||||
src/shell-recorder.h | 1 +
|
||||
3 files changed, 114 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/js/ui/screencast.js b/js/ui/screencast.js
|
||||
index 0b0b14a8e..54f8fb5ae 100644
|
||||
--- a/js/ui/screencast.js
|
||||
+++ b/js/ui/screencast.js
|
||||
@@ -1,6 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
-const { Gio, GLib, Shell } = imports.gi;
|
||||
+const { Gio, GLib, Meta, Shell } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
@@ -53,16 +53,27 @@ var ScreencastService = class {
|
||||
this._stopRecordingForSender(name);
|
||||
}
|
||||
|
||||
- _stopRecordingForSender(sender) {
|
||||
+ _stopRecordingForSender(sender, closeNow=false) {
|
||||
let recorder = this._recorders.get(sender);
|
||||
if (!recorder)
|
||||
return false;
|
||||
|
||||
Gio.bus_unwatch_name(recorder._watchNameId);
|
||||
- recorder.close();
|
||||
+ if (closeNow)
|
||||
+ recorder.close_now();
|
||||
+ else
|
||||
+ recorder.close();
|
||||
this._recorders.delete(sender);
|
||||
this.emit('updated');
|
||||
|
||||
+ let connection = this._dbusImpl.get_connection();
|
||||
+ let info = this._dbusImpl.get_info();
|
||||
+ connection.emit_signal(sender,
|
||||
+ this._dbusImpl.get_object_path(),
|
||||
+ info ? info.name : null,
|
||||
+ 'Stopped',
|
||||
+ null);
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -78,6 +89,53 @@ var ScreencastService = class {
|
||||
recorder.set_draw_cursor(options['draw-cursor']);
|
||||
}
|
||||
|
||||
+ _ensureResourceScaleChangedHandler() {
|
||||
+ if (this._resourceScaleChangedHandlerId)
|
||||
+ return;
|
||||
+
|
||||
+ this._resourceScaleChangedHandlerId =
|
||||
+ global.stage.connect('notify::resource-scale',
|
||||
+ () => {
|
||||
+ for (let sender of this._recorders.keys()) {
|
||||
+ let recorder = this._recorders.get(sender);
|
||||
+
|
||||
+ if (!recorder.is_recording())
|
||||
+ continue;
|
||||
+
|
||||
+ this._stopRecordingForSender(sender, true);
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ _ensureMonitorsChangedHandler() {
|
||||
+ if (this._monitorsChangedHandlerId)
|
||||
+ return;
|
||||
+
|
||||
+ this._monitorsChangedHandlerId = Main.layoutManager.connect('monitors-changed',
|
||||
+ () => {
|
||||
+ for (let sender of this._recorders.keys()) {
|
||||
+ let recorder = this._recorders.get(sender);
|
||||
+
|
||||
+ if (!recorder.is_recording())
|
||||
+ continue;
|
||||
+
|
||||
+ let geometry = recorder._geometry;
|
||||
+ let screenWidth = global.screen_width;
|
||||
+ let screenHeight = global.screen_height;
|
||||
+
|
||||
+ if (recorder._isAreaScreecast) {
|
||||
+ if (geometry.x + geometry.width > screenWidth ||
|
||||
+ geometry.y + geometry.height > screenHeight)
|
||||
+ this._stopRecordingForSender(sender, true);
|
||||
+ } else {
|
||||
+ if (geometry.width != screenWidth ||
|
||||
+ geometry.height != screenHeight)
|
||||
+ this._stopRecordingForSender(sender, true);
|
||||
+ }
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
ScreencastAsync(params, invocation) {
|
||||
let returnValue = [false, ''];
|
||||
if (!Main.sessionMode.allowScreencast ||
|
||||
@@ -95,8 +153,20 @@ var ScreencastService = class {
|
||||
this._applyOptionalParameters(recorder, options);
|
||||
let [success, fileName] = recorder.record();
|
||||
returnValue = [success, fileName ? fileName : ''];
|
||||
- if (!success)
|
||||
+ if (success) {
|
||||
+ recorder._isAreaScreecast = false;
|
||||
+ recorder._geometry =
|
||||
+ new Meta.Rectangle({
|
||||
+ x: 0,
|
||||
+ y: 0,
|
||||
+ width: global.screen_width,
|
||||
+ height: global.screen_height
|
||||
+ });
|
||||
+ this._ensureResourceScaleChangedHandler();
|
||||
+ this._ensureMonitorsChangedHandler();
|
||||
+ } else {
|
||||
this._stopRecordingForSender(sender);
|
||||
+ }
|
||||
}
|
||||
|
||||
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||
@@ -131,8 +201,20 @@ var ScreencastService = class {
|
||||
this._applyOptionalParameters(recorder, options);
|
||||
let [success, fileName] = recorder.record();
|
||||
returnValue = [success, fileName ? fileName : ''];
|
||||
- if (!success)
|
||||
+ if (success) {
|
||||
+ recorder._isAreaScreecast = true;
|
||||
+ recorder._geometry =
|
||||
+ new Meta.Rectangle({
|
||||
+ x: x,
|
||||
+ y: y,
|
||||
+ width: width,
|
||||
+ height: height
|
||||
+ });
|
||||
+ this._ensureResourceScaleChangedHandler();
|
||||
+ this._ensureMonitorsChangedHandler();
|
||||
+ } else {
|
||||
this._stopRecordingForSender(sender);
|
||||
+ }
|
||||
}
|
||||
|
||||
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||
diff --git a/src/shell-recorder.c b/src/shell-recorder.c
|
||||
index 0203ecf1c..e561a0152 100644
|
||||
--- a/src/shell-recorder.c
|
||||
+++ b/src/shell-recorder.c
|
||||
@@ -511,21 +511,6 @@ recorder_update_size (ShellRecorder *recorder)
|
||||
}
|
||||
}
|
||||
|
||||
-static void
|
||||
-recorder_on_stage_notify_size (GObject *object,
|
||||
- GParamSpec *pspec,
|
||||
- ShellRecorder *recorder)
|
||||
-{
|
||||
- recorder_update_size (recorder);
|
||||
-
|
||||
- /* This breaks the recording but tweaking the GStreamer pipeline a bit
|
||||
- * might make it work, at least if the codec can handle a stream where
|
||||
- * the frame size changes in the middle.
|
||||
- */
|
||||
- if (recorder->current_pipeline)
|
||||
- recorder_pipeline_set_caps (recorder->current_pipeline);
|
||||
-}
|
||||
-
|
||||
static gboolean
|
||||
recorder_idle_redraw (gpointer data)
|
||||
{
|
||||
@@ -622,12 +607,6 @@ recorder_connect_stage_callbacks (ShellRecorder *recorder)
|
||||
G_CALLBACK (recorder_on_stage_destroy), recorder);
|
||||
g_signal_connect_after (recorder->stage, "paint",
|
||||
G_CALLBACK (recorder_on_stage_paint), recorder);
|
||||
- g_signal_connect (recorder->stage, "notify::width",
|
||||
- G_CALLBACK (recorder_on_stage_notify_size), recorder);
|
||||
- g_signal_connect (recorder->stage, "notify::height",
|
||||
- G_CALLBACK (recorder_on_stage_notify_size), recorder);
|
||||
- g_signal_connect (recorder->stage, "notify::resource-scale",
|
||||
- G_CALLBACK (recorder_on_stage_notify_size), recorder);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -639,9 +618,6 @@ recorder_disconnect_stage_callbacks (ShellRecorder *recorder)
|
||||
g_signal_handlers_disconnect_by_func (recorder->stage,
|
||||
(void *)recorder_on_stage_paint,
|
||||
recorder);
|
||||
- g_signal_handlers_disconnect_by_func (recorder->stage,
|
||||
- (void *)recorder_on_stage_notify_size,
|
||||
- recorder);
|
||||
|
||||
/* We don't don't deselect for cursor changes in case someone else just
|
||||
* happened to be selecting for cursor events on the same window; sending
|
||||
@@ -1578,6 +1554,32 @@ shell_recorder_record (ShellRecorder *recorder,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * shell_recorder_close_now:
|
||||
+ * @recorder: the #ShellRecorder
|
||||
+ *
|
||||
+ * Stops recording immediately. It's possible to call shell_recorder_record()
|
||||
+ * again to reopen a new recording stream, but unless change the recording
|
||||
+ * filename, this may result in the old recording being overwritten.
|
||||
+ */
|
||||
+void
|
||||
+shell_recorder_close_now (ShellRecorder *recorder)
|
||||
+{
|
||||
+ g_return_if_fail (SHELL_IS_RECORDER (recorder));
|
||||
+ g_return_if_fail (recorder->state != RECORDER_STATE_CLOSED);
|
||||
+
|
||||
+ recorder_remove_update_pointer_timeout (recorder);
|
||||
+ recorder_close_pipeline (recorder);
|
||||
+
|
||||
+ recorder->state = RECORDER_STATE_CLOSED;
|
||||
+
|
||||
+ /* Reenable after the recording */
|
||||
+ meta_enable_unredirect_for_display (shell_global_get_display (shell_global_get ()));
|
||||
+
|
||||
+ /* Release the refcount we took when we started recording */
|
||||
+ g_object_unref (recorder);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* shell_recorder_close:
|
||||
* @recorder: the #ShellRecorder
|
||||
diff --git a/src/shell-recorder.h b/src/shell-recorder.h
|
||||
index c1e0e6368..1c3e6aab4 100644
|
||||
--- a/src/shell-recorder.h
|
||||
+++ b/src/shell-recorder.h
|
||||
@@ -37,6 +37,7 @@ void shell_recorder_set_area (ShellRecorder *recorder,
|
||||
gboolean shell_recorder_record (ShellRecorder *recorder,
|
||||
char **filename_used);
|
||||
void shell_recorder_close (ShellRecorder *recorder);
|
||||
+void shell_recorder_close_now (ShellRecorder *recorder);
|
||||
void shell_recorder_pause (ShellRecorder *recorder);
|
||||
gboolean shell_recorder_is_recording (ShellRecorder *recorder);
|
||||
|
||||
--
|
||||
2.27.0
|
||||
|
@ -0,0 +1,78 @@
|
||||
From 391f262aee82ac12fcf99951d6b2df362f734b31 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Mon, 15 Jun 2020 20:41:45 +0200
|
||||
Subject: [PATCH] shell/app: Handle workspace from startup notifications
|
||||
|
||||
Launching applications on a particular workspace works through
|
||||
launch contexts and startup notifications. While this is no
|
||||
longer required by a launcher/WM split, in theory this allows
|
||||
us to reliably identify the correct window to apply startup
|
||||
properties to.
|
||||
|
||||
However in practice we fail more often than not: Missing support in
|
||||
toolkits, differences between display protocols, D-Bus activation
|
||||
and single-instance applications all provide their own pitfalls.
|
||||
|
||||
So instead, take advantage of the fact that launcher and WM live in
|
||||
the same process, and go with the unsophisticated approach: Just
|
||||
remember the last workspace that was requested when launching an
|
||||
app, then move the next window that is associated with the app to
|
||||
that workspace.
|
||||
|
||||
This will break X11 applications that set an initial workspace, but
|
||||
that's legacy functionality anyway (given that there's no wayland
|
||||
protocol for that functionality), and seems a price worth paying
|
||||
for making launching apps on workspaces more reliable.
|
||||
---
|
||||
src/shell-app.c | 19 +++++++++++--------
|
||||
1 file changed, 11 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/shell-app.c b/src/shell-app.c
|
||||
index 7d40186c9..f716bc5f8 100644
|
||||
--- a/src/shell-app.c
|
||||
+++ b/src/shell-app.c
|
||||
@@ -1067,6 +1067,10 @@ _shell_app_add_window (ShellApp *app,
|
||||
if (!app->running_state)
|
||||
create_running_state (app);
|
||||
|
||||
+ if (app->started_on_workspace >= 0)
|
||||
+ meta_window_change_workspace_by_index (window, app->started_on_workspace, FALSE);
|
||||
+ app->started_on_workspace = -1;
|
||||
+
|
||||
app->running_state->window_sort_stale = TRUE;
|
||||
app->running_state->windows = g_slist_prepend (app->running_state->windows, g_object_ref (window));
|
||||
g_signal_connect_object (window, "unmanaged", G_CALLBACK(shell_app_on_unmanaged), app, 0);
|
||||
@@ -1156,16 +1160,14 @@ _shell_app_handle_startup_sequence (ShellApp *app,
|
||||
shell_app_state_transition (app, SHELL_APP_STATE_STARTING);
|
||||
meta_x11_display_focus_the_no_focus_window (x11_display,
|
||||
meta_startup_sequence_get_timestamp (sequence));
|
||||
- app->started_on_workspace = meta_startup_sequence_get_workspace (sequence);
|
||||
}
|
||||
|
||||
- if (!starting)
|
||||
- {
|
||||
- if (app->running_state && app->running_state->windows)
|
||||
- shell_app_state_transition (app, SHELL_APP_STATE_RUNNING);
|
||||
- else /* application have > 1 .desktop file */
|
||||
- shell_app_state_transition (app, SHELL_APP_STATE_STOPPED);
|
||||
- }
|
||||
+ if (starting)
|
||||
+ app->started_on_workspace = meta_startup_sequence_get_workspace (sequence);
|
||||
+ else if (app->running_state && app->running_state->windows)
|
||||
+ shell_app_state_transition (app, SHELL_APP_STATE_RUNNING);
|
||||
+ else /* application have > 1 .desktop file */
|
||||
+ shell_app_state_transition (app, SHELL_APP_STATE_STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1473,6 +1475,7 @@ static void
|
||||
shell_app_init (ShellApp *self)
|
||||
{
|
||||
self->state = SHELL_APP_STATE_STOPPED;
|
||||
+ self->started_on_workspace = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
--
|
||||
2.29.2
|
||||
|
@ -0,0 +1,28 @@
|
||||
From 3182ad73c8f88628cb51a96feba0fc32ce7f01c9 Mon Sep 17 00:00:00 2001
|
||||
From: Illya Klymov <xanf@xanf.me>
|
||||
Date: Mon, 8 Jul 2019 03:29:36 +0000
|
||||
Subject: [PATCH] shell-recorder: Restore cursor recording
|
||||
|
||||
Due to changes introduced in 5357e0a1 cursor recording interaction with
|
||||
magnifier was reversed. This fix restores original correct behavior
|
||||
Related issue: https://gitlab.gnome.org/GNOME/gnome-shell/issues/1208
|
||||
---
|
||||
src/shell-recorder.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/shell-recorder.c b/src/shell-recorder.c
|
||||
index 0203ecf1c..cf1cc336f 100644
|
||||
--- a/src/shell-recorder.c
|
||||
+++ b/src/shell-recorder.c
|
||||
@@ -465,7 +465,7 @@ recorder_record_frame (ShellRecorder *recorder,
|
||||
|
||||
g_object_get (settings, "magnifier-active", &magnifier_active, NULL);
|
||||
|
||||
- if (magnifier_active)
|
||||
+ if (!magnifier_active)
|
||||
recorder_draw_cursor (recorder, buffer);
|
||||
}
|
||||
|
||||
--
|
||||
2.35.1
|
||||
|
@ -0,0 +1,66 @@
|
||||
From 660ebe0125b591355116934ee57b08010e05246c Mon Sep 17 00:00:00 2001
|
||||
From: Rui Matos <tiagomatos@gmail.com>
|
||||
Date: Fri, 8 Nov 2013 11:36:04 +0100
|
||||
Subject: [PATCH] shellDBus: Add a DBus method to load a single extension
|
||||
|
||||
This allows e.g. gnome-tweak-tool to install an extension from a zip
|
||||
file and load it into the running shell.
|
||||
---
|
||||
.../org.gnome.Shell.Extensions.xml | 13 +++++++++++++
|
||||
js/ui/shellDBus.js | 16 ++++++++++++++++
|
||||
2 files changed, 29 insertions(+)
|
||||
|
||||
diff --git a/data/dbus-interfaces/org.gnome.Shell.Extensions.xml b/data/dbus-interfaces/org.gnome.Shell.Extensions.xml
|
||||
index 34a65af44..ce69439fc 100644
|
||||
--- a/data/dbus-interfaces/org.gnome.Shell.Extensions.xml
|
||||
+++ b/data/dbus-interfaces/org.gnome.Shell.Extensions.xml
|
||||
@@ -189,6 +189,19 @@
|
||||
-->
|
||||
<method name="CheckForUpdates"/>
|
||||
|
||||
+ <!--
|
||||
+ LoadUserExtension:
|
||||
+ @uuid: The UUID of the extension
|
||||
+ @success: Whether the operation was successful
|
||||
+
|
||||
+ Load a newly installed user extension
|
||||
+ -->
|
||||
+
|
||||
+ <method name="LoadUserExtension">
|
||||
+ <arg type="s" direction="in" name="uuid"/>
|
||||
+ <arg type="b" direction="out" name="success"/>
|
||||
+ </method>
|
||||
+
|
||||
<signal name="ExtensionStatusChanged">
|
||||
<arg type="s" name="uuid"/>
|
||||
<arg type="i" name="state"/>
|
||||
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
|
||||
index 19d07acce..112d60feb 100644
|
||||
--- a/js/ui/shellDBus.js
|
||||
+++ b/js/ui/shellDBus.js
|
||||
@@ -341,6 +341,22 @@ var GnomeShellExtensions = class {
|
||||
ExtensionDownloader.checkForUpdates();
|
||||
}
|
||||
|
||||
+ LoadUserExtension(uuid) {
|
||||
+ let extension = ExtensionUtils.extensions[uuid];
|
||||
+ if (extension)
|
||||
+ return true;
|
||||
+
|
||||
+ let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
|
||||
+ try {
|
||||
+ extension = ExtensionUtils.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER);
|
||||
+ ExtensionSystem.loadExtension(extension);
|
||||
+ } catch (e) {
|
||||
+ log('Could not load user extension from %s'.format(dir.get_path()));
|
||||
+ return false;
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
get ShellVersion() {
|
||||
return Config.PACKAGE_VERSION;
|
||||
}
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,91 @@
|
||||
From e6cd96a9f6a89f77ca0fab72aff8c56354b59f38 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Wed, 21 Aug 2019 15:01:34 -0400
|
||||
Subject: [PATCH 1/4] shellEntry: Determine if password entry from content
|
||||
purpose not menu item
|
||||
|
||||
Right now shellEntry decides whether or not it's a password entry based
|
||||
on whether or not it has a "Show Text" context menu.
|
||||
|
||||
That's a little roundabout, and gets in the way off providing lockdown
|
||||
that disables the menu.
|
||||
|
||||
This commit changes shellEntry to base whether or not it's a password
|
||||
entry from it's input content purpose instead of from the presence
|
||||
or absence of a context menu.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/687
|
||||
---
|
||||
js/ui/shellEntry.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
|
||||
index 53bd1daa1..cac4ec9c2 100644
|
||||
--- a/js/ui/shellEntry.js
|
||||
+++ b/js/ui/shellEntry.js
|
||||
@@ -14,61 +14,61 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
|
||||
|
||||
this._entry = entry;
|
||||
this._clipboard = St.Clipboard.get_default();
|
||||
|
||||
// Populate menu
|
||||
let item;
|
||||
item = new PopupMenu.PopupMenuItem(_("Copy"));
|
||||
item.connect('activate', this._onCopyActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._copyItem = item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Paste"));
|
||||
item.connect('activate', this._onPasteActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._pasteItem = item;
|
||||
|
||||
this._passwordItem = null;
|
||||
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
this.actor.hide();
|
||||
}
|
||||
|
||||
_makePasswordItem() {
|
||||
let item = new PopupMenu.PopupMenuItem('');
|
||||
item.connect('activate', this._onPasswordActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._passwordItem = item;
|
||||
}
|
||||
|
||||
get isPassword() {
|
||||
- return this._passwordItem != null;
|
||||
+ return this._entry.input_purpose == Clutter.InputContentPurpose.PASSWORD;
|
||||
}
|
||||
|
||||
set isPassword(v) {
|
||||
if (v == this.isPassword)
|
||||
return;
|
||||
|
||||
if (v) {
|
||||
this._makePasswordItem();
|
||||
this._entry.input_purpose = Clutter.InputContentPurpose.PASSWORD;
|
||||
} else {
|
||||
this._passwordItem.destroy();
|
||||
this._passwordItem = null;
|
||||
this._entry.input_purpose = Clutter.InputContentPurpose.NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
open(animate) {
|
||||
this._updatePasteItem();
|
||||
this._updateCopyItem();
|
||||
if (this._passwordItem)
|
||||
this._updatePasswordItem();
|
||||
|
||||
super.open(animate);
|
||||
this._entry.add_style_pseudo_class('focus');
|
||||
|
||||
let direction = St.DirectionType.TAB_FORWARD;
|
||||
if (!this.actor.navigate_focus(null, direction, false))
|
||||
this.actor.grab_key_focus();
|
||||
}
|
||||
|
||||
--
|
||||
2.27.0
|
||||
|
@ -0,0 +1,36 @@
|
||||
From fd8c4dc073b121b1093d68472cac3292d2c6605c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Mon, 14 Jun 2021 17:59:39 +0200
|
||||
Subject: [PATCH] shellEntry: Disconnect handler on destroy
|
||||
|
||||
Actors will get unmapped on destroy, so unless we disconnect from
|
||||
the notify::mapped signal, the handler will run one last time and
|
||||
try to access methods/properties on the invalidated actor.
|
||||
---
|
||||
js/ui/shellEntry.js | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
|
||||
index 4a30b22f7..53bd1daa1 100644
|
||||
--- a/js/ui/shellEntry.js
|
||||
+++ b/js/ui/shellEntry.js
|
||||
@@ -186,7 +186,7 @@ class CapsLockWarning extends St.Label {
|
||||
this._keymap = Clutter.get_default_backend().get_keymap();
|
||||
this._stateChangedId = 0;
|
||||
|
||||
- this.connect('notify::mapped', () => {
|
||||
+ const mappedId = this.connect('notify::mapped', () => {
|
||||
if (this.is_mapped()) {
|
||||
this._stateChangedId = this._keymap.connect('state-changed',
|
||||
() => this._sync(true));
|
||||
@@ -201,6 +201,7 @@ class CapsLockWarning extends St.Label {
|
||||
this.connect('destroy', () => {
|
||||
if (this._stateChangedId)
|
||||
this._keymap.disconnect(this._stateChangedId);
|
||||
+ this.disconnect(mappedId);
|
||||
});
|
||||
}
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,59 @@
|
||||
From 96404287bc4269dea7b037e7b178e54ebf616d47 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel van Vugt <daniel.van.vugt@canonical.com>
|
||||
Date: Tue, 24 Nov 2020 17:34:08 +0800
|
||||
Subject: [PATCH] st-bin: Disallow st_bin_set_child with already-parented
|
||||
children
|
||||
|
||||
Not checking for this would result in `clutter_actor_add_child`
|
||||
failing, but StBin keeping a copy in `priv->child`. So later on,
|
||||
`st_bin_remove` would never be called on it and this assertion
|
||||
would fail and crash the whole shell:
|
||||
|
||||
```
|
||||
static void
|
||||
st_bin_destroy (ClutterActor *actor)
|
||||
{
|
||||
StBinPrivate *priv = st_bin_get_instance_private (ST_BIN (actor));
|
||||
|
||||
if (priv->child)
|
||||
clutter_actor_destroy (priv->child);
|
||||
g_assert (priv->child == NULL);
|
||||
|
||||
```
|
||||
|
||||
By disallowing spurious `st_bin_set_child` calls we now prevent StBin
|
||||
from entering such a corrupt state and the above assertion won't fail
|
||||
anymore.
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1507>
|
||||
---
|
||||
src/st/st-bin.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/src/st/st-bin.c b/src/st/st-bin.c
|
||||
index f013909e8..7959a4e95 100644
|
||||
--- a/src/st/st-bin.c
|
||||
+++ b/src/st/st-bin.c
|
||||
@@ -434,6 +434,19 @@ st_bin_set_child (StBin *bin,
|
||||
if (priv->child == child)
|
||||
return;
|
||||
|
||||
+ if (child)
|
||||
+ {
|
||||
+ ClutterActor *parent = clutter_actor_get_parent (child);
|
||||
+
|
||||
+ if (parent)
|
||||
+ {
|
||||
+ g_warning ("%s: The provided 'child' actor %p already has a "
|
||||
+ "(different) parent %p and can't be made a child of %p.",
|
||||
+ G_STRFUNC, child, parent, bin);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (priv->child)
|
||||
clutter_actor_remove_child (CLUTTER_ACTOR (bin), priv->child);
|
||||
|
||||
--
|
||||
2.38.1
|
||||
|
@ -0,0 +1,94 @@
|
||||
From 1bf28eea64056846547ec33d783c7f2e0dad78a4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 22 May 2020 22:53:39 +0200
|
||||
Subject: [PATCH] st/texture-cache: Cancel pending requests on icon-theme
|
||||
changes
|
||||
|
||||
As outlined in commit 36b8dcbe07, we can end up with wrong icons
|
||||
if the icon theme changes right after a GTK theme change to/from
|
||||
HighContrast triggered a theme reload.
|
||||
|
||||
That's because when we reload icons for the new icon theme, there
|
||||
are already pending requests due to the icon-style change; those
|
||||
requests are simply re-used for the new icons, with the existing
|
||||
icon infos from the old theme.
|
||||
|
||||
The above commit applied a simple work-around by changing the
|
||||
icon theme before the GTK theme, but that only works for the
|
||||
HighContrast switch in our own UI.
|
||||
|
||||
It turns out that Settings also uses the "wrong" order, so the
|
||||
issue still reproduces with the Universal Access panel.
|
||||
|
||||
So instead of relying on everything changing the settings in the
|
||||
order we expect, cancel all ongoing requests on icon-theme changes.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1277
|
||||
---
|
||||
src/st/st-texture-cache.c | 17 +++++++++++++++--
|
||||
1 file changed, 15 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c
|
||||
index 35e9d036f..6dc351282 100644
|
||||
--- a/src/st/st-texture-cache.c
|
||||
+++ b/src/st/st-texture-cache.c
|
||||
@@ -48,6 +48,8 @@ struct _StTextureCachePrivate
|
||||
|
||||
/* File monitors to evict cache data on changes */
|
||||
GHashTable *file_monitors; /* char * -> GFileMonitor * */
|
||||
+
|
||||
+ GCancellable *cancellable;
|
||||
};
|
||||
|
||||
static void st_texture_cache_dispose (GObject *object);
|
||||
@@ -152,6 +154,9 @@ on_icon_theme_changed (StSettings *settings,
|
||||
{
|
||||
g_autofree gchar *theme;
|
||||
|
||||
+ g_cancellable_cancel (cache->priv->cancellable);
|
||||
+ g_cancellable_reset (cache->priv->cancellable);
|
||||
+
|
||||
st_texture_cache_evict_icons (cache);
|
||||
|
||||
g_object_get (settings, "gtk-icon-theme", &theme, NULL);
|
||||
@@ -186,6 +191,8 @@ st_texture_cache_init (StTextureCache *self)
|
||||
self->priv->file_monitors = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
|
||||
g_object_unref, g_object_unref);
|
||||
|
||||
+ self->priv->cancellable = g_cancellable_new ();
|
||||
+
|
||||
on_icon_theme_changed (settings, NULL, self);
|
||||
}
|
||||
|
||||
@@ -194,8 +201,11 @@ st_texture_cache_dispose (GObject *object)
|
||||
{
|
||||
StTextureCache *self = (StTextureCache*)object;
|
||||
|
||||
+ g_cancellable_cancel (self->priv->cancellable);
|
||||
+
|
||||
g_clear_object (&self->priv->settings);
|
||||
g_clear_object (&self->priv->icon_theme);
|
||||
+ g_clear_object (&self->priv->cancellable);
|
||||
|
||||
g_clear_pointer (&self->priv->keyed_cache, g_hash_table_destroy);
|
||||
g_clear_pointer (&self->priv->keyed_surface_cache, g_hash_table_destroy);
|
||||
@@ -675,11 +685,14 @@ load_texture_async (StTextureCache *cache,
|
||||
gtk_icon_info_load_symbolic_async (data->icon_info,
|
||||
&foreground_color, &success_color,
|
||||
&warning_color, &error_color,
|
||||
- NULL, on_symbolic_icon_loaded, data);
|
||||
+ cache->priv->cancellable,
|
||||
+ on_symbolic_icon_loaded, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
- gtk_icon_info_load_icon_async (data->icon_info, NULL, on_icon_loaded, data);
|
||||
+ gtk_icon_info_load_icon_async (data->icon_info,
|
||||
+ cache->priv->cancellable,
|
||||
+ on_icon_loaded, data);
|
||||
}
|
||||
}
|
||||
else
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,30 @@
|
||||
From 4e555e0efeb4b31918e199d29bee99b2a4ed1c8e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Wed, 11 May 2022 02:34:21 +0200
|
||||
Subject: [PATCH] status/volume: Hide sliders initially
|
||||
|
||||
We update the visibility on state or stream changes, but those
|
||||
changes may never happen if pipewire-pulse/pulseaudio isn't
|
||||
available (for example when running as root).
|
||||
|
||||
Hiding the sliders is preferable in that case to showing non-working
|
||||
controls.
|
||||
---
|
||||
js/ui/status/volume.js | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/js/ui/status/volume.js b/js/ui/status/volume.js
|
||||
index d555b426e..ab5065683 100644
|
||||
--- a/js/ui/status/volume.js
|
||||
+++ b/js/ui/status/volume.js
|
||||
@@ -30,6 +30,7 @@ var StreamSlider = class {
|
||||
this._control = control;
|
||||
|
||||
this.item = new PopupMenu.PopupBaseMenuItem({ activate: false });
|
||||
+ this.item.actor.hide();
|
||||
|
||||
this._slider = new Slider.Slider(0);
|
||||
|
||||
--
|
||||
2.35.1
|
||||
|
@ -0,0 +1,76 @@
|
||||
From c68fd3c94c6debdbf11020940c5a6aaee8bc230d Mon Sep 17 00:00:00 2001
|
||||
From: Feichtmeier <frederik.feichtmeier@gmail.com>
|
||||
Date: Fri, 15 Mar 2019 14:41:55 +0100
|
||||
Subject: [PATCH] theme: Update window preview style
|
||||
|
||||
- simplify the close button to use blue, lighter blue and darker blue
|
||||
solid disks for normal, hover and active states
|
||||
|
||||
- use a milky, transparent white border for the hover effect of the border
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/461
|
||||
---
|
||||
data/theme/gnome-shell-sass/_common.scss | 29 ++++++++++++------------
|
||||
1 file changed, 14 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
|
||||
index 9e0751c8c..8bf368f6e 100644
|
||||
--- a/data/theme/gnome-shell-sass/_common.scss
|
||||
+++ b/data/theme/gnome-shell-sass/_common.scss
|
||||
@@ -1164,25 +1164,23 @@ StScrollBar {
|
||||
//close buttons
|
||||
|
||||
.window-close {
|
||||
- background-color: white;
|
||||
+ background-color: $selected_bg_color;
|
||||
+ color: white;
|
||||
border-radius: 24px;
|
||||
- border: 4px solid $selected_bg_color;
|
||||
- box-shadow: inset 0 -4px 0 0 transparentize($selected_bg_color, 0.5);
|
||||
- color: $selected_bg_color;
|
||||
+ border: 2px solid $selected_bg_color;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
- -shell-close-overlap: 14px;
|
||||
+ -shell-close-overlap: 11px;
|
||||
+ box-shadow: -1px 1px 5px 0px transparentize(black, 0.5);
|
||||
|
||||
&:hover {
|
||||
- background-color: $selected_bg_color;
|
||||
- border-color: white;
|
||||
- color: white;
|
||||
+ background-color: lighten($selected_bg_color, 5%);
|
||||
+ border-color: lighten($selected_bg_color, 5%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
- background-color: mix(white, $selected_bg_color, 75%);
|
||||
- border-color: $selected_bg_color;
|
||||
- color: $selected_bg_color;
|
||||
+ background-color: darken($selected_bg_color, 5%);
|
||||
+ border-color: darken($selected_bg_color, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,13 +1245,14 @@ StScrollBar {
|
||||
}
|
||||
|
||||
.window-clone-border {
|
||||
- border: 4px solid $selected_bg_color;
|
||||
- border-radius: 4px;
|
||||
+ $_bg: transparentize(white, 0.65);
|
||||
+ border: 5px solid $_bg;
|
||||
+ border-radius: 6px;
|
||||
// For window decorations with round corners we can't match
|
||||
// the exact shape when the window is scaled. So apply a shadow
|
||||
// to fix that case
|
||||
- box-shadow: inset 0px 0px 0px 1px $selected_bg_color;
|
||||
- }
|
||||
+ box-shadow: inset 0 0 0 1px $_bg;
|
||||
+}
|
||||
.window-caption {
|
||||
spacing: 25px;
|
||||
color: $selected_fg_color;
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,45 @@
|
||||
From 20640a92f98e2145b9b6581209c978e9f6f78801 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Tue, 14 Mar 2017 17:04:36 +0100
|
||||
Subject: [PATCH] windowMenu: Bring back workspaces submenu for static
|
||||
workspaces
|
||||
|
||||
When the titlebar context menu was moved to the shell, the submenu for
|
||||
moving to a specific workspace was intentionally left out; some people
|
||||
are quite attached to it though, so bring it back when static workspaces
|
||||
are used.
|
||||
---
|
||||
js/ui/windowMenu.js | 17 +++++++++++++++++
|
||||
1 file changed, 17 insertions(+)
|
||||
|
||||
diff --git a/js/ui/windowMenu.js b/js/ui/windowMenu.js
|
||||
index 628f145ea..f8eb4398c 100644
|
||||
--- a/js/ui/windowMenu.js
|
||||
+++ b/js/ui/windowMenu.js
|
||||
@@ -115,6 +115,23 @@ var WindowMenu = class extends PopupMenu.PopupMenu {
|
||||
window.change_workspace(workspace.get_neighbor(dir));
|
||||
});
|
||||
}
|
||||
+
|
||||
+ let { workspaceManager } = global;
|
||||
+ let nWorkspaces = workspaceManager.n_workspaces;
|
||||
+ if (nWorkspaces > 1 && !Meta.prefs_get_dynamic_workspaces()) {
|
||||
+ item = new PopupMenu.PopupSubMenuMenuItem(_("Move to another workspace"));
|
||||
+ this.addMenuItem(item);
|
||||
+
|
||||
+ let currentIndex = workspaceManager.get_active_workspace_index();
|
||||
+ for (let i = 0; i < nWorkspaces; i++) {
|
||||
+ let index = i;
|
||||
+ let name = Meta.prefs_get_workspace_name(i);
|
||||
+ let subitem = item.menu.addAction(name, () => {
|
||||
+ window.change_workspace_by_index(index, false);
|
||||
+ });
|
||||
+ subitem.setSensitive(currentIndex != i);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,31 @@
|
||||
From 9115f6e7962b97c3ee2fbef7b195b7116e62c070 Mon Sep 17 00:00:00 2001
|
||||
From: Carlos Garnacho <carlosg@gnome.org>
|
||||
Date: Fri, 13 Dec 2019 18:14:51 +0100
|
||||
Subject: [PATCH] workspace: Pass device to startDrag()
|
||||
|
||||
This is necessary to make DnD operations work from tablet devices on
|
||||
wayland, as it's not the same onscreen pointer sprite than mice. Fixes
|
||||
window DnD in the overview on tablet devices, no longer having them stick
|
||||
to the wrong pointer.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/897
|
||||
---
|
||||
js/ui/workspace.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/workspace.js b/js/ui/workspace.js
|
||||
index 1e9bedc28..d470f7f40 100644
|
||||
--- a/js/ui/workspace.js
|
||||
+++ b/js/ui/workspace.js
|
||||
@@ -431,7 +431,7 @@ var WindowClone = GObject.registerClass({
|
||||
return;
|
||||
let [x, y] = action.get_coords();
|
||||
action.release();
|
||||
- this._draggable.startDrag(x, y, global.get_current_time(), this._dragTouchSequence);
|
||||
+ this._draggable.startDrag(x, y, global.get_current_time(), this._dragTouchSequence, event.get_device());
|
||||
});
|
||||
} else {
|
||||
this.emit('show-chrome');
|
||||
--
|
||||
2.23.0
|
||||
|
@ -0,0 +1,37 @@
|
||||
From b69b404118852f7955f60d1814f5e19ad61ce449 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 12 Jul 2019 03:26:51 +0000
|
||||
Subject: [PATCH] workspacesView: Work around spurious allocation changes
|
||||
|
||||
For some reason, people are still seeing those after commit d5ebd8c8.
|
||||
While this is something we really should figure out, we can work around
|
||||
the issue by keeping the view actors hidden until the update is complete.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1065
|
||||
---
|
||||
js/ui/workspacesView.js | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
|
||||
index 069937d5a..e302296a6 100644
|
||||
--- a/js/ui/workspacesView.js
|
||||
+++ b/js/ui/workspacesView.js
|
||||
@@ -666,10 +666,15 @@ var WorkspacesDisplay = class {
|
||||
this._scrollValueChanged.bind(this));
|
||||
}
|
||||
|
||||
+ // HACK: Avoid spurious allocation changes while updating views
|
||||
+ view.actor.hide();
|
||||
+
|
||||
this._workspacesViews.push(view);
|
||||
Main.layoutManager.overviewGroup.add_actor(view.actor);
|
||||
}
|
||||
|
||||
+ this._workspacesViews.forEach(v => v.actor.show());
|
||||
+
|
||||
this._updateWorkspacesFullGeometry();
|
||||
this._updateWorkspacesActualGeometry();
|
||||
}
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,31 @@
|
||||
From f27c4224aa96975ae44641612f5fff3772f5c294 Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Mon, 22 Aug 2022 13:06:05 +0200
|
||||
Subject: [PATCH] [PATCH 2/4] background: rebuild background, not just
|
||||
animation on resume
|
||||
|
||||
Previously, we would only refresh the animation on resume
|
||||
(to handle clock skew).
|
||||
|
||||
But we actually need to rebuild the background, too, on nvidia,
|
||||
so we should just do a full background change.
|
||||
---
|
||||
js/ui/background.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/background.js b/js/ui/background.js
|
||||
index 2a404ae..dd11e3e 100644
|
||||
--- a/js/ui/background.js
|
||||
+++ b/js/ui/background.js
|
||||
@@ -254,7 +254,7 @@ var Background = class Background {
|
||||
(lm, aboutToSuspend) => {
|
||||
if (aboutToSuspend)
|
||||
return;
|
||||
- this._refreshAnimation();
|
||||
+ this.emit('changed');
|
||||
});
|
||||
|
||||
this._settingsChangedSignalId =
|
||||
--
|
||||
2.35.3
|
||||
|
@ -0,0 +1,33 @@
|
||||
From 189add05c07fe9d9bed6c1399b30e51a4a934bd3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Mon, 2 Mar 2020 13:46:04 +0100
|
||||
Subject: [PATCH 2/6] environment: Fix date conversion
|
||||
|
||||
This is a regression from commit 06b690ff21204:
|
||||
|
||||
GLib.DateTime.new() expects the full four-digit year, so passing
|
||||
the abbreviated year from Date() will result in a bogus datetime.
|
||||
|
||||
Today is *not* Saturday March 2nd, 120 ...
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1061
|
||||
---
|
||||
js/ui/environment.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/environment.js b/js/ui/environment.js
|
||||
index f3f2d17c7..a9cc16dee 100644
|
||||
--- a/js/ui/environment.js
|
||||
+++ b/js/ui/environment.js
|
||||
@@ -126,7 +126,7 @@ function init() {
|
||||
_localTimeZone = GLib.TimeZone.new_local();
|
||||
|
||||
let dt = GLib.DateTime.new(_localTimeZone,
|
||||
- this.getYear(),
|
||||
+ this.getFullYear(),
|
||||
this.getMonth() + 1,
|
||||
this.getDate(),
|
||||
this.getHours(),
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,237 @@
|
||||
From b70cf463e08bff43b242b851fc7c79244f54e76b Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Tue, 10 Aug 2021 13:25:57 -0400
|
||||
Subject: [PATCH 2/4] extensionSystem: Get rid of _enabled boolean optimization
|
||||
|
||||
At the moment a session mode either allows extensions or it doesn't.
|
||||
If it allows extensions, then the entire available list of
|
||||
configured extensions get enabled as soon as the session mode is
|
||||
entered.
|
||||
|
||||
Since enabling or disabling extensions is an all or nothing situation,
|
||||
the code tracks whether extensions are already enabled when entering
|
||||
the session mode, and if so, avoids iterating through the extension list
|
||||
needlessly. It does this using a boolean named _enabled.
|
||||
|
||||
In the future, the extensions themselves will be given some say on
|
||||
whether or not they should be enabled in a given session mode. This
|
||||
means, the configured extension list may contain extensions that
|
||||
shouldn't be enabled for a given session mode, and the _enabled boolean
|
||||
will no longer be appropriated.
|
||||
|
||||
This commit drops the _enabled boolean optimization.
|
||||
---
|
||||
js/ui/extensionSystem.js | 13 -------------
|
||||
1 file changed, 13 deletions(-)
|
||||
|
||||
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
|
||||
index 77929f2a6..05630ed54 100644
|
||||
--- a/js/ui/extensionSystem.js
|
||||
+++ b/js/ui/extensionSystem.js
|
||||
@@ -1,53 +1,52 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const { GLib, Gio, GObject, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
||||
const { ExtensionState, ExtensionType } = ExtensionUtils;
|
||||
|
||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
||||
const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions';
|
||||
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
|
||||
|
||||
const UPDATE_CHECK_TIMEOUT = 24 * 60 * 60; // 1 day in seconds
|
||||
|
||||
var ExtensionManager = class {
|
||||
constructor() {
|
||||
this._initted = false;
|
||||
- this._enabled = false;
|
||||
this._updateNotified = false;
|
||||
|
||||
this._extensions = new Map();
|
||||
this._enabledExtensions = [];
|
||||
this._extensionOrder = [];
|
||||
|
||||
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
|
||||
}
|
||||
|
||||
init() {
|
||||
this._installExtensionUpdates();
|
||||
this._sessionUpdated();
|
||||
|
||||
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, UPDATE_CHECK_TIMEOUT, () => {
|
||||
ExtensionDownloader.checkForUpdates();
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
});
|
||||
ExtensionDownloader.checkForUpdates();
|
||||
}
|
||||
|
||||
lookup(uuid) {
|
||||
return this._extensions.get(uuid);
|
||||
}
|
||||
|
||||
getUuids() {
|
||||
return [...this._extensions.keys()];
|
||||
}
|
||||
|
||||
_callExtensionDisable(uuid) {
|
||||
let extension = this.lookup(uuid);
|
||||
@@ -375,63 +374,60 @@ var ExtensionManager = class {
|
||||
let hasError =
|
||||
extension.state == ExtensionState.ERROR ||
|
||||
extension.state == ExtensionState.OUT_OF_DATE;
|
||||
|
||||
let isMode = this._getModeExtensions().includes(extension.uuid);
|
||||
let modeOnly = global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY);
|
||||
|
||||
extension.canChange =
|
||||
!hasError &&
|
||||
global.settings.is_writable(ENABLED_EXTENSIONS_KEY) &&
|
||||
(isMode || !modeOnly);
|
||||
}
|
||||
|
||||
_getEnabledExtensions() {
|
||||
let extensions = this._getModeExtensions();
|
||||
|
||||
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
|
||||
return extensions;
|
||||
|
||||
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
|
||||
}
|
||||
|
||||
_onUserExtensionsEnabledChanged() {
|
||||
this._onEnabledExtensionsChanged();
|
||||
this._onSettingsWritableChanged();
|
||||
}
|
||||
|
||||
_onEnabledExtensionsChanged() {
|
||||
let newEnabledExtensions = this._getEnabledExtensions();
|
||||
|
||||
- if (!this._enabled)
|
||||
- return;
|
||||
-
|
||||
// Find and enable all the newly enabled extensions: UUIDs found in the
|
||||
// new setting, but not in the old one.
|
||||
newEnabledExtensions.filter(
|
||||
uuid => !this._enabledExtensions.includes(uuid)
|
||||
).forEach(uuid => {
|
||||
this._callExtensionEnable(uuid);
|
||||
});
|
||||
|
||||
// Find and disable all the newly disabled extensions: UUIDs found in the
|
||||
// old setting, but not in the new one.
|
||||
this._enabledExtensions.filter(
|
||||
item => !newEnabledExtensions.includes(item)
|
||||
).forEach(uuid => {
|
||||
this._callExtensionDisable(uuid);
|
||||
});
|
||||
|
||||
this._enabledExtensions = newEnabledExtensions;
|
||||
}
|
||||
|
||||
_onSettingsWritableChanged() {
|
||||
for (let extension of this._extensions.values()) {
|
||||
this._updateCanChange(extension);
|
||||
this.emit('extension-state-changed', extension);
|
||||
}
|
||||
}
|
||||
|
||||
_onVersionValidationChanged() {
|
||||
// we want to reload all extensions, but only enable
|
||||
// extensions when allowed by the sessionMode, so
|
||||
// temporarily disable them all
|
||||
@@ -482,85 +478,76 @@ var ExtensionManager = class {
|
||||
|
||||
this._enabledExtensions = this._getEnabledExtensions();
|
||||
|
||||
let perUserDir = Gio.File.new_for_path(global.userdatadir);
|
||||
FileUtils.collectFromDatadirs('extensions', true, (dir, info) => {
|
||||
let fileType = info.get_file_type();
|
||||
if (fileType != Gio.FileType.DIRECTORY)
|
||||
return;
|
||||
let uuid = info.get_name();
|
||||
let existing = this.lookup(uuid);
|
||||
if (existing) {
|
||||
log(`Extension ${uuid} already installed in ${existing.path}. ${dir.get_path()} will not be loaded`);
|
||||
return;
|
||||
}
|
||||
|
||||
let extension;
|
||||
let type = dir.has_prefix(perUserDir)
|
||||
? ExtensionType.PER_USER
|
||||
: ExtensionType.SYSTEM;
|
||||
try {
|
||||
extension = this.createExtensionObject(uuid, dir, type);
|
||||
} catch (e) {
|
||||
logError(e, `Could not load extension ${uuid}`);
|
||||
return;
|
||||
}
|
||||
this.loadExtension(extension);
|
||||
});
|
||||
}
|
||||
|
||||
_enableAllExtensions() {
|
||||
- if (this._enabled)
|
||||
- return;
|
||||
-
|
||||
if (!this._initted) {
|
||||
this._loadExtensions();
|
||||
this._initted = true;
|
||||
} else {
|
||||
this._enabledExtensions.forEach(uuid => {
|
||||
this._callExtensionEnable(uuid);
|
||||
});
|
||||
}
|
||||
- this._enabled = true;
|
||||
}
|
||||
|
||||
_disableAllExtensions() {
|
||||
- if (!this._enabled)
|
||||
- return;
|
||||
-
|
||||
if (this._initted) {
|
||||
this._extensionOrder.slice().reverse().forEach(uuid => {
|
||||
this._callExtensionDisable(uuid);
|
||||
});
|
||||
}
|
||||
-
|
||||
- this._enabled = false;
|
||||
}
|
||||
|
||||
_sessionUpdated() {
|
||||
// For now sessionMode.allowExtensions controls extensions from both the
|
||||
// 'enabled-extensions' preference and the sessionMode.enabledExtensions
|
||||
// property; it might make sense to make enabledExtensions independent
|
||||
// from allowExtensions in the future
|
||||
if (Main.sessionMode.allowExtensions) {
|
||||
// Take care of added or removed sessionMode extensions
|
||||
this._onEnabledExtensionsChanged();
|
||||
this._enableAllExtensions();
|
||||
} else {
|
||||
this._disableAllExtensions();
|
||||
}
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(ExtensionManager.prototype);
|
||||
|
||||
class ExtensionUpdateSource extends MessageTray.Source {
|
||||
constructor() {
|
||||
const appSys = Shell.AppSystem.get_default();
|
||||
this._app = appSys.lookup_app('gnome-shell-extension-prefs.desktop');
|
||||
|
||||
super(this._app.get_name());
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
return this._app.app_info.get_icon();
|
||||
}
|
||||
|
||||
--
|
||||
2.27.0
|
||||
|
@ -0,0 +1,267 @@
|
||||
From c3ab03f8721ea96df6ac91c0393ed13ba750ab7e Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 17 Jul 2017 16:48:03 -0400
|
||||
Subject: [PATCH 2/2] gdmUtil: enable support for GDM's ChoiceList PAM
|
||||
extension
|
||||
|
||||
This commit hooks up support for GDM's ChoiceList PAM extension.
|
||||
---
|
||||
js/gdm/authPrompt.js | 74 ++++++++++++++++++++++++++++++++++++++++++-
|
||||
js/gdm/loginDialog.js | 5 +++
|
||||
js/gdm/util.js | 28 ++++++++++++++++
|
||||
js/ui/unlockDialog.js | 9 +++++-
|
||||
4 files changed, 114 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index cf77b3f26..71069e93b 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -4,6 +4,7 @@ const { Clutter, GLib, Pango, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Animation = imports.ui.animation;
|
||||
+const AuthList = imports.gdm.authList;
|
||||
const Batch = imports.gdm.batch;
|
||||
const GdmUtil = imports.gdm.util;
|
||||
const Meta = imports.gi.Meta;
|
||||
@@ -54,6 +55,7 @@ var AuthPrompt = class {
|
||||
|
||||
this._userVerifier.connect('ask-question', this._onAskQuestion.bind(this));
|
||||
this._userVerifier.connect('show-message', this._onShowMessage.bind(this));
|
||||
+ this._userVerifier.connect('show-choice-list', this._onShowChoiceList.bind(this));
|
||||
this._userVerifier.connect('verification-failed', this._onVerificationFailed.bind(this));
|
||||
this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this));
|
||||
this._userVerifier.connect('reset', this._onReset.bind(this));
|
||||
@@ -116,6 +118,28 @@ var AuthPrompt = class {
|
||||
|
||||
this.actor.add(this._timedLoginIndicator);
|
||||
|
||||
+ this._authList = new AuthList.AuthList();
|
||||
+ this._authList.connect('activate', (list, key) => {
|
||||
+ this._authList.actor.reactive = false;
|
||||
+ Tweener.addTween(this._authList.actor,
|
||||
+ { opacity: 0,
|
||||
+ time: MESSAGE_FADE_OUT_ANIMATION_TIME,
|
||||
+ transition: 'easeOutQuad',
|
||||
+ onComplete: () => {
|
||||
+ this._authList.clear();
|
||||
+ this._authList.actor.hide();
|
||||
+ this._userVerifier.selectChoice(this._queryingService, key);
|
||||
+
|
||||
+ }
|
||||
+ });
|
||||
+ });
|
||||
+ this._authList.actor.hide();
|
||||
+ this.actor.add(this._authList.actor,
|
||||
+ { expand: true,
|
||||
+ x_fill: true,
|
||||
+ y_fill: false,
|
||||
+ x_align: St.Align.START });
|
||||
+
|
||||
this._message = new St.Label({ opacity: 0,
|
||||
styleClass: 'login-dialog-message' });
|
||||
this._message.clutter_text.line_wrap = true;
|
||||
@@ -258,6 +282,21 @@ var AuthPrompt = class {
|
||||
this.emit('prompted');
|
||||
}
|
||||
|
||||
+ _onShowChoiceList(userVerifier, serviceName, promptMessage, choiceList) {
|
||||
+ if (this._queryingService)
|
||||
+ this.clear();
|
||||
+
|
||||
+ this._queryingService = serviceName;
|
||||
+
|
||||
+ if (this._preemptiveAnswer)
|
||||
+ this._preemptiveAnswer = null;
|
||||
+
|
||||
+ this.nextButton.label = _("Next");
|
||||
+ this.setChoiceList(promptMessage, choiceList);
|
||||
+ this.updateSensitivity(true);
|
||||
+ this.emit('prompted');
|
||||
+ }
|
||||
+
|
||||
_onOVirtUserAuthenticated() {
|
||||
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
|
||||
this.reset();
|
||||
@@ -386,6 +425,8 @@ var AuthPrompt = class {
|
||||
clear() {
|
||||
this._entry.text = '';
|
||||
this.stopSpinning();
|
||||
+ this._authList.clear();
|
||||
+ this._authList.actor.hide();
|
||||
}
|
||||
|
||||
setPasswordChar(passwordChar) {
|
||||
@@ -401,12 +442,42 @@ var AuthPrompt = class {
|
||||
|
||||
this._label.set_text(question);
|
||||
|
||||
+ this._authList.actor.hide();
|
||||
this._label.show();
|
||||
this._entry.show();
|
||||
|
||||
this._entry.grab_key_focus();
|
||||
}
|
||||
|
||||
+ _fadeInChoiceList() {
|
||||
+ this._authList.actor.opacity = 0;
|
||||
+ this._authList.actor.show();
|
||||
+ this._authList.actor.reactive = false;
|
||||
+ Tweener.addTween(this._authList.actor,
|
||||
+ { opacity: 255,
|
||||
+ time: MESSAGE_FADE_OUT_ANIMATION_TIME,
|
||||
+ transition: 'easeOutQuad',
|
||||
+ onComplete: () => {
|
||||
+ this._authList.actor.reactive = true;
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ setChoiceList(promptMessage, choiceList) {
|
||||
+ this._authList.clear();
|
||||
+ this._authList.label.text = promptMessage;
|
||||
+ for (let key in choiceList) {
|
||||
+ let text = choiceList[key];
|
||||
+ this._authList.addItem(key, text);
|
||||
+ }
|
||||
+
|
||||
+ this._label.hide();
|
||||
+ this._entry.hide();
|
||||
+ if (this._message.text == "")
|
||||
+ this._message.hide();
|
||||
+ this._fadeInChoiceList();
|
||||
+ }
|
||||
+
|
||||
getAnswer() {
|
||||
let text;
|
||||
|
||||
@@ -442,6 +513,7 @@ var AuthPrompt = class {
|
||||
else
|
||||
this._message.remove_style_class_name('login-dialog-message-hint');
|
||||
|
||||
+ this._message.show();
|
||||
if (message) {
|
||||
Tweener.removeTweens(this._message);
|
||||
this._message.text = message;
|
||||
@@ -457,7 +529,7 @@ var AuthPrompt = class {
|
||||
}
|
||||
|
||||
updateSensitivity(sensitive) {
|
||||
- this._updateNextButtonSensitivity(sensitive && (this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING));
|
||||
+ this._updateNextButtonSensitivity(sensitive && !this._authList.actor.visible && (this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING));
|
||||
this._entry.reactive = sensitive;
|
||||
this._entry.clutter_text.editable = sensitive;
|
||||
}
|
||||
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
|
||||
index 9aaa013d8..942f5a0e5 100644
|
||||
--- a/js/gdm/loginDialog.js
|
||||
+++ b/js/gdm/loginDialog.js
|
||||
@@ -406,6 +406,11 @@ var LoginDialog = GObject.registerClass({
|
||||
this._userManager = AccountsService.UserManager.get_default()
|
||||
this._gdmClient = new Gdm.Client();
|
||||
|
||||
+ try {
|
||||
+ this._gdmClient.set_enabled_extensions([Gdm.UserVerifierChoiceList.interface_info().name]);
|
||||
+ } catch(e) {
|
||||
+ }
|
||||
+
|
||||
this._settings = new Gio.Settings({ schema_id: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
||||
|
||||
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
|
||||
diff --git a/js/gdm/util.js b/js/gdm/util.js
|
||||
index 6e940d2ab..9e249139d 100644
|
||||
--- a/js/gdm/util.js
|
||||
+++ b/js/gdm/util.js
|
||||
@@ -192,6 +192,10 @@ var ShellUserVerifier = class {
|
||||
if (this._userVerifier) {
|
||||
this._userVerifier.run_dispose();
|
||||
this._userVerifier = null;
|
||||
+ if (this._userVerifierChoiceList) {
|
||||
+ this._userVerifierChoiceList.run_dispose();
|
||||
+ this._userVerifierChoiceList = null;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,6 +223,10 @@ var ShellUserVerifier = class {
|
||||
this._oVirtCredentialsManager = null;
|
||||
}
|
||||
|
||||
+ selectChoice(serviceName, key) {
|
||||
+ this._userVerifierChoiceList.call_select_choice(serviceName, key, this._cancellable, null);
|
||||
+ }
|
||||
+
|
||||
answerQuery(serviceName, answer) {
|
||||
if (!this.hasPendingMessages) {
|
||||
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
|
||||
@@ -362,6 +370,11 @@ var ShellUserVerifier = class {
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (client.get_user_verifier_choice_list)
|
||||
+ this._userVerifierChoiceList = client.get_user_verifier_choice_list();
|
||||
+ else
|
||||
+ this._userVerifierChoiceList = null;
|
||||
+
|
||||
this.reauthenticating = true;
|
||||
this._connectSignals();
|
||||
this._beginVerification();
|
||||
@@ -379,6 +392,11 @@ var ShellUserVerifier = class {
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (client.get_user_verifier_choice_list)
|
||||
+ this._userVerifierChoiceList = client.get_user_verifier_choice_list();
|
||||
+ else
|
||||
+ this._userVerifierChoiceList = null;
|
||||
+
|
||||
this._connectSignals();
|
||||
this._beginVerification();
|
||||
this._hold.release();
|
||||
@@ -392,6 +410,9 @@ var ShellUserVerifier = class {
|
||||
this._userVerifier.connect('conversation-stopped', this._onConversationStopped.bind(this));
|
||||
this._userVerifier.connect('reset', this._onReset.bind(this));
|
||||
this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this));
|
||||
+
|
||||
+ if (this._userVerifierChoiceList)
|
||||
+ this._userVerifierChoiceList.connect('choice-query', this._onChoiceListQuery.bind(this));
|
||||
}
|
||||
|
||||
_getForegroundService() {
|
||||
@@ -468,6 +489,13 @@ var ShellUserVerifier = class {
|
||||
this._startService(FINGERPRINT_SERVICE_NAME);
|
||||
}
|
||||
|
||||
+ _onChoiceListQuery(client, serviceName, promptMessage, list) {
|
||||
+ if (!this.serviceIsForeground(serviceName))
|
||||
+ return;
|
||||
+
|
||||
+ this.emit('show-choice-list', serviceName, promptMessage, list.deep_unpack());
|
||||
+ }
|
||||
+
|
||||
_onInfo(client, serviceName, info) {
|
||||
if (this.serviceIsForeground(serviceName)) {
|
||||
this._queueMessage(info, MessageType.INFO);
|
||||
diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js
|
||||
index 5c9d46021..4b0470f4b 100644
|
||||
--- a/js/ui/unlockDialog.js
|
||||
+++ b/js/ui/unlockDialog.js
|
||||
@@ -33,7 +33,14 @@ var UnlockDialog = class {
|
||||
y_expand: true });
|
||||
this.actor.add_child(this._promptBox);
|
||||
|
||||
- this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY);
|
||||
+ this._gdmClient = new Gdm.Client();
|
||||
+
|
||||
+ try {
|
||||
+ this._gdmClient.set_enabled_extensions([Gdm.UserVerifierChoiceList.interface_info().name]);
|
||||
+ } catch(e) {
|
||||
+ }
|
||||
+
|
||||
+ this._authPrompt = new AuthPrompt.AuthPrompt(this._gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_ONLY);
|
||||
this._authPrompt.connect('failed', this._fail.bind(this));
|
||||
this._authPrompt.connect('cancelled', this._fail.bind(this));
|
||||
this._authPrompt.connect('reset', this._onReset.bind(this));
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,92 @@
|
||||
From de7df6c7248c39d7cce1c70485df72a398da92a3 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Wed, 21 Aug 2019 15:48:33 -0400
|
||||
Subject: [PATCH 2/4] shellEntry: Give password menu item text when it's
|
||||
created
|
||||
|
||||
At the moment, the "Show Text" menu item is only given its text
|
||||
at the time the menu is opened. This is because the text might
|
||||
be "Hide Text" or "Show Text" depending on state, so the text
|
||||
is set up lazily.
|
||||
|
||||
That behavior means the menu item can't get added after the
|
||||
menu is already shown, which is something we'ree going to need
|
||||
in the future to support lockdown of the "Show Text" item.
|
||||
|
||||
This commit ensures the menu item is given text when it's first
|
||||
created, in addition to when the menu is opened.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/687
|
||||
---
|
||||
js/ui/shellEntry.js | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
|
||||
index cac4ec9c2..603a9c64a 100644
|
||||
--- a/js/ui/shellEntry.js
|
||||
+++ b/js/ui/shellEntry.js
|
||||
@@ -11,60 +11,61 @@ const Tweener = imports.ui.tweener;
|
||||
var EntryMenu = class extends PopupMenu.PopupMenu {
|
||||
constructor(entry) {
|
||||
super(entry, 0, St.Side.TOP);
|
||||
|
||||
this._entry = entry;
|
||||
this._clipboard = St.Clipboard.get_default();
|
||||
|
||||
// Populate menu
|
||||
let item;
|
||||
item = new PopupMenu.PopupMenuItem(_("Copy"));
|
||||
item.connect('activate', this._onCopyActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._copyItem = item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Paste"));
|
||||
item.connect('activate', this._onPasteActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._pasteItem = item;
|
||||
|
||||
this._passwordItem = null;
|
||||
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
this.actor.hide();
|
||||
}
|
||||
|
||||
_makePasswordItem() {
|
||||
let item = new PopupMenu.PopupMenuItem('');
|
||||
item.connect('activate', this._onPasswordActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._passwordItem = item;
|
||||
+ this._updatePasswordItem();
|
||||
}
|
||||
|
||||
get isPassword() {
|
||||
return this._entry.input_purpose == Clutter.InputContentPurpose.PASSWORD;
|
||||
}
|
||||
|
||||
set isPassword(v) {
|
||||
if (v == this.isPassword)
|
||||
return;
|
||||
|
||||
if (v) {
|
||||
this._makePasswordItem();
|
||||
this._entry.input_purpose = Clutter.InputContentPurpose.PASSWORD;
|
||||
} else {
|
||||
this._passwordItem.destroy();
|
||||
this._passwordItem = null;
|
||||
this._entry.input_purpose = Clutter.InputContentPurpose.NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
open(animate) {
|
||||
this._updatePasteItem();
|
||||
this._updateCopyItem();
|
||||
if (this._passwordItem)
|
||||
this._updatePasswordItem();
|
||||
|
||||
super.open(animate);
|
||||
this._entry.add_style_pseudo_class('focus');
|
||||
|
||||
let direction = St.DirectionType.TAB_FORWARD;
|
||||
--
|
||||
2.27.0
|
||||
|
@ -0,0 +1,393 @@
|
||||
From 7300ae2eac743fa06f40f6459ac8fbf739ab28ea Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Tue, 10 Aug 2021 15:03:50 -0400
|
||||
Subject: [PATCH 3/4] extensionSystem: Allow extensions to run on the login
|
||||
screen
|
||||
|
||||
At the moment it's not realy possible to extend the login screen to do
|
||||
things it doesn't have built-in support for. This means in order
|
||||
to support niche use cases, those cases have to change the main
|
||||
code base. For instance, oVirt and Vmware deployments want to be able
|
||||
to automaticaly log in guest VMs when a user pre-authenticates through a
|
||||
console on a management host. To support those use cases, we added
|
||||
code to the login screen directly, even though most machines will never
|
||||
be associated with oVirt or Vmware management hosts.
|
||||
|
||||
We also get requests from e.g. government users that need certain features
|
||||
at the login screen that wouldn't get used much outside of government
|
||||
deployments. For instance, we've gotten requests that a machine contains
|
||||
prominently displays that it has "Top Secret" information.
|
||||
|
||||
All of these use cases seem like they would better handled via
|
||||
extensions that could be installed in the specific deployments. The
|
||||
problem is extensions only run in the user session, and get
|
||||
disabled at the login screen automatically.
|
||||
|
||||
This commit changes that. Now extensions can specify in their metadata
|
||||
via a new sessionModes property, which modes that want to run in. For
|
||||
backward compatibility, if an extension doesn't specify which session
|
||||
modes it works in, its assumed the extension only works in the user
|
||||
session.
|
||||
---
|
||||
js/ui/extensionSystem.js | 43 ++++++++++++++++++++++++++++++++++++----
|
||||
1 file changed, 39 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
|
||||
index 05630ed54..dfe82821e 100644
|
||||
--- a/js/ui/extensionSystem.js
|
||||
+++ b/js/ui/extensionSystem.js
|
||||
@@ -21,119 +21,147 @@ var ExtensionManager = class {
|
||||
constructor() {
|
||||
this._initted = false;
|
||||
this._updateNotified = false;
|
||||
|
||||
this._extensions = new Map();
|
||||
this._enabledExtensions = [];
|
||||
this._extensionOrder = [];
|
||||
|
||||
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
|
||||
}
|
||||
|
||||
init() {
|
||||
this._installExtensionUpdates();
|
||||
this._sessionUpdated();
|
||||
|
||||
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, UPDATE_CHECK_TIMEOUT, () => {
|
||||
ExtensionDownloader.checkForUpdates();
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
});
|
||||
ExtensionDownloader.checkForUpdates();
|
||||
}
|
||||
|
||||
lookup(uuid) {
|
||||
return this._extensions.get(uuid);
|
||||
}
|
||||
|
||||
getUuids() {
|
||||
return [...this._extensions.keys()];
|
||||
}
|
||||
|
||||
+ _extensionSupportsSessionMode(uuid) {
|
||||
+ let extension = this.lookup(uuid);
|
||||
+
|
||||
+ if (!extension)
|
||||
+ return false;
|
||||
+
|
||||
+ if (extension.sessionModes.includes(Main.sessionMode.currentMode))
|
||||
+ return true;
|
||||
+
|
||||
+ if (extension.sessionModes.includes(Main.sessionMode.parentMode))
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ _sessionModeCanUseExtension(uuid) {
|
||||
+ if (!Main.sessionMode.allowExtensions)
|
||||
+ return false;
|
||||
+
|
||||
+ if (!this._extensionSupportsSessionMode(uuid))
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
_callExtensionDisable(uuid) {
|
||||
let extension = this.lookup(uuid);
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
if (extension.state != ExtensionState.ENABLED)
|
||||
return;
|
||||
|
||||
// "Rebase" the extension order by disabling and then enabling extensions
|
||||
// in order to help prevent conflicts.
|
||||
|
||||
// Example:
|
||||
// order = [A, B, C, D, E]
|
||||
// user disables C
|
||||
// this should: disable E, disable D, disable C, enable D, enable E
|
||||
|
||||
let orderIdx = this._extensionOrder.indexOf(uuid);
|
||||
let order = this._extensionOrder.slice(orderIdx + 1);
|
||||
let orderReversed = order.slice().reverse();
|
||||
|
||||
for (let i = 0; i < orderReversed.length; i++) {
|
||||
let uuid = orderReversed[i];
|
||||
try {
|
||||
this.lookup(uuid).stateObj.disable();
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.stylesheet) {
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
theme.unload_stylesheet(extension.stylesheet);
|
||||
delete extension.stylesheet;
|
||||
}
|
||||
|
||||
try {
|
||||
extension.stateObj.disable();
|
||||
} catch(e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
}
|
||||
|
||||
for (let i = 0; i < order.length; i++) {
|
||||
let uuid = order[i];
|
||||
try {
|
||||
this.lookup(uuid).stateObj.enable();
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
}
|
||||
}
|
||||
|
||||
this._extensionOrder.splice(orderIdx, 1);
|
||||
|
||||
if (extension.state != ExtensionState.ERROR) {
|
||||
extension.state = ExtensionState.DISABLED;
|
||||
this.emit('extension-state-changed', extension);
|
||||
}
|
||||
}
|
||||
|
||||
_callExtensionEnable(uuid) {
|
||||
+ if (!this._sessionModeCanUseExtension(uuid))
|
||||
+ return;
|
||||
+
|
||||
let extension = this.lookup(uuid);
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
if (extension.state == ExtensionState.INITIALIZED)
|
||||
this._callExtensionInit(uuid);
|
||||
|
||||
if (extension.state != ExtensionState.DISABLED)
|
||||
return;
|
||||
|
||||
this._extensionOrder.push(uuid);
|
||||
|
||||
let stylesheetNames = [global.session_mode + '.css', 'stylesheet.css'];
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
for (let i = 0; i < stylesheetNames.length; i++) {
|
||||
try {
|
||||
let stylesheetFile = extension.dir.get_child(stylesheetNames[i]);
|
||||
theme.load_stylesheet(stylesheetFile);
|
||||
extension.stylesheet = stylesheetFile;
|
||||
break;
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
|
||||
continue; // not an error
|
||||
log(`Failed to load stylesheet for extension ${uuid}: ${e.message}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
extension.stateObj.enable();
|
||||
@@ -231,61 +259,62 @@ var ExtensionManager = class {
|
||||
throw new Error(`Failed to load metadata.json: ${e}`);
|
||||
}
|
||||
let meta;
|
||||
try {
|
||||
meta = JSON.parse(metadataContents);
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to parse metadata.json: ${e}`);
|
||||
}
|
||||
|
||||
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
|
||||
for (let i = 0; i < requiredProperties.length; i++) {
|
||||
let prop = requiredProperties[i];
|
||||
if (!meta[prop]) {
|
||||
throw new Error(`missing "${prop}" property in metadata.json`);
|
||||
}
|
||||
}
|
||||
|
||||
if (uuid != meta.uuid) {
|
||||
throw new Error(`uuid "${meta.uuid}" from metadata.json does not match directory name "${uuid}"`);
|
||||
}
|
||||
|
||||
let extension = {
|
||||
metadata: meta,
|
||||
uuid: meta.uuid,
|
||||
type,
|
||||
dir,
|
||||
path: dir.get_path(),
|
||||
error: '',
|
||||
hasPrefs: dir.get_child('prefs.js').query_exists(null),
|
||||
hasUpdate: false,
|
||||
- canChange: false
|
||||
+ canChange: false,
|
||||
+ sessionModes: meta['session-modes'] ? meta['session-modes'] : [ 'user' ],
|
||||
};
|
||||
this._extensions.set(uuid, extension);
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
loadExtension(extension) {
|
||||
// Default to error, we set success as the last step
|
||||
extension.state = ExtensionState.ERROR;
|
||||
|
||||
let checkVersion = !global.settings.get_boolean(EXTENSION_DISABLE_VERSION_CHECK_KEY);
|
||||
|
||||
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
|
||||
extension.state = ExtensionState.OUT_OF_DATE;
|
||||
} else {
|
||||
let enabled = this._enabledExtensions.includes(extension.uuid);
|
||||
if (enabled) {
|
||||
if (!this._callExtensionInit(extension.uuid))
|
||||
return;
|
||||
if (extension.state == ExtensionState.DISABLED)
|
||||
this._callExtensionEnable(extension.uuid);
|
||||
} else {
|
||||
extension.state = ExtensionState.INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
this._updateCanChange(extension);
|
||||
this.emit('extension-state-changed', extension);
|
||||
}
|
||||
|
||||
@@ -296,60 +325,63 @@ var ExtensionManager = class {
|
||||
this._callExtensionDisable(extension.uuid);
|
||||
|
||||
extension.state = ExtensionState.UNINSTALLED;
|
||||
this.emit('extension-state-changed', extension);
|
||||
|
||||
this._extensions.delete(extension.uuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
reloadExtension(oldExtension) {
|
||||
// Grab the things we'll need to pass to createExtensionObject
|
||||
// to reload it.
|
||||
let { uuid: uuid, dir: dir, type: type } = oldExtension;
|
||||
|
||||
// Then unload the old extension.
|
||||
this.unloadExtension(oldExtension);
|
||||
|
||||
// Now, recreate the extension and load it.
|
||||
let newExtension;
|
||||
try {
|
||||
newExtension = this.createExtensionObject(uuid, dir, type);
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadExtension(newExtension);
|
||||
}
|
||||
|
||||
_callExtensionInit(uuid) {
|
||||
+ if (!this._sessionModeCanUseExtension(uuid))
|
||||
+ return false;
|
||||
+
|
||||
let extension = this.lookup(uuid);
|
||||
let dir = extension.dir;
|
||||
|
||||
if (!extension)
|
||||
throw new Error("Extension was not properly created. Call loadExtension first");
|
||||
|
||||
let extensionJs = dir.get_child('extension.js');
|
||||
if (!extensionJs.query_exists(null)) {
|
||||
this.logExtensionError(uuid, new Error('Missing extension.js'));
|
||||
return false;
|
||||
}
|
||||
|
||||
let extensionModule;
|
||||
let extensionState = null;
|
||||
|
||||
ExtensionUtils.installImporter(extension);
|
||||
try {
|
||||
extensionModule = extension.imports.extension;
|
||||
} catch(e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extensionModule.init) {
|
||||
try {
|
||||
extensionState = extensionModule.init(extension);
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
return false;
|
||||
}
|
||||
@@ -377,69 +409,72 @@ var ExtensionManager = class {
|
||||
|
||||
let isMode = this._getModeExtensions().includes(extension.uuid);
|
||||
let modeOnly = global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY);
|
||||
|
||||
extension.canChange =
|
||||
!hasError &&
|
||||
global.settings.is_writable(ENABLED_EXTENSIONS_KEY) &&
|
||||
(isMode || !modeOnly);
|
||||
}
|
||||
|
||||
_getEnabledExtensions() {
|
||||
let extensions = this._getModeExtensions();
|
||||
|
||||
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
|
||||
return extensions;
|
||||
|
||||
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
|
||||
}
|
||||
|
||||
_onUserExtensionsEnabledChanged() {
|
||||
this._onEnabledExtensionsChanged();
|
||||
this._onSettingsWritableChanged();
|
||||
}
|
||||
|
||||
_onEnabledExtensionsChanged() {
|
||||
let newEnabledExtensions = this._getEnabledExtensions();
|
||||
|
||||
// Find and enable all the newly enabled extensions: UUIDs found in the
|
||||
// new setting, but not in the old one.
|
||||
newEnabledExtensions.filter(
|
||||
- uuid => !this._enabledExtensions.includes(uuid)
|
||||
+ uuid => !this._enabledExtensions.includes(uuid) &&
|
||||
+ this._extensionSupportsSessionMode(uuid)
|
||||
).forEach(uuid => {
|
||||
this._callExtensionEnable(uuid);
|
||||
});
|
||||
|
||||
// Find and disable all the newly disabled extensions: UUIDs found in the
|
||||
- // old setting, but not in the new one.
|
||||
+ // old setting, but not in the new one, and extensions that don't work with
|
||||
+ // the current session mode.
|
||||
this._enabledExtensions.filter(
|
||||
- item => !newEnabledExtensions.includes(item)
|
||||
+ item => !newEnabledExtensions.includes(item) ||
|
||||
+ !this._extensionSupportsSessionMode(item)
|
||||
).forEach(uuid => {
|
||||
this._callExtensionDisable(uuid);
|
||||
});
|
||||
|
||||
this._enabledExtensions = newEnabledExtensions;
|
||||
}
|
||||
|
||||
_onSettingsWritableChanged() {
|
||||
for (let extension of this._extensions.values()) {
|
||||
this._updateCanChange(extension);
|
||||
this.emit('extension-state-changed', extension);
|
||||
}
|
||||
}
|
||||
|
||||
_onVersionValidationChanged() {
|
||||
// we want to reload all extensions, but only enable
|
||||
// extensions when allowed by the sessionMode, so
|
||||
// temporarily disable them all
|
||||
this._enabledExtensions = [];
|
||||
|
||||
// The loop modifies the extensions map, so iterate over a copy
|
||||
let extensions = [...this._extensions.values()];
|
||||
for (let extension of extensions)
|
||||
this.reloadExtension(extension);
|
||||
this._enabledExtensions = this._getEnabledExtensions();
|
||||
|
||||
if (Main.sessionMode.allowExtensions) {
|
||||
this._enabledExtensions.forEach(uuid => {
|
||||
this._callExtensionEnable(uuid);
|
||||
});
|
||||
--
|
||||
2.27.0
|
||||
|
@ -0,0 +1,152 @@
|
||||
From c9277326055c96185a80b68d4228eee360bb0e7c Mon Sep 17 00:00:00 2001
|
||||
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
|
||||
Date: Thu, 1 Aug 2019 20:58:20 -0300
|
||||
Subject: [PATCH 3/6] shell/app-system: Monitor for icon theme changes
|
||||
|
||||
Whenever an app is installed, the usual routine is
|
||||
to run 'gtk-update-icon-cache' after installing all
|
||||
of the app's files.
|
||||
|
||||
The side effect of that is that the .desktop file of
|
||||
the application is installed before the icon theme
|
||||
is updated. By the time GAppInfoMonitor emits the
|
||||
'changed' signal, the icon theme is not yet updated,
|
||||
leading to StIcon use the fallback icon.
|
||||
|
||||
Under some circumstances (e.g. on very slow spinning
|
||||
disks) the app icon is never actually loaded, and we
|
||||
see the fallback icon forever.
|
||||
|
||||
Monitor the icon theme for changes when an app is
|
||||
installed. Try as many as 6 times before giving up
|
||||
on detecting an icon theme update.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/661
|
||||
---
|
||||
src/shell-app-system.c | 54 +++++++++++++++++++++++++++++++++++++++
|
||||
src/st/st-texture-cache.c | 8 ++++++
|
||||
src/st/st-texture-cache.h | 2 ++
|
||||
3 files changed, 64 insertions(+)
|
||||
|
||||
diff --git a/src/shell-app-system.c b/src/shell-app-system.c
|
||||
index f632cbe54..127f29ef0 100644
|
||||
--- a/src/shell-app-system.c
|
||||
+++ b/src/shell-app-system.c
|
||||
@@ -14,6 +14,14 @@
|
||||
#include "shell-app-system-private.h"
|
||||
#include "shell-global.h"
|
||||
#include "shell-util.h"
|
||||
+#include "st.h"
|
||||
+
|
||||
+/* Rescan for at most RESCAN_TIMEOUT_MS * MAX_RESCAN_RETRIES. That
|
||||
+ * should be plenty of time for even a slow spinning drive to update
|
||||
+ * the icon cache.
|
||||
+ */
|
||||
+#define RESCAN_TIMEOUT_MS 2500
|
||||
+#define MAX_RESCAN_RETRIES 6
|
||||
|
||||
/* Vendor prefixes are something that can be preprended to a .desktop
|
||||
* file name. Undo this.
|
||||
@@ -51,6 +59,9 @@ struct _ShellAppSystemPrivate {
|
||||
GHashTable *id_to_app;
|
||||
GHashTable *startup_wm_class_to_id;
|
||||
GList *installed_apps;
|
||||
+
|
||||
+ guint rescan_icons_timeout_id;
|
||||
+ guint n_rescan_retries;
|
||||
};
|
||||
|
||||
static void shell_app_system_finalize (GObject *object);
|
||||
@@ -157,12 +168,54 @@ stale_app_remove_func (gpointer key,
|
||||
return app_is_stale (value);
|
||||
}
|
||||
|
||||
+static gboolean
|
||||
+rescan_icon_theme_cb (gpointer user_data)
|
||||
+{
|
||||
+ ShellAppSystemPrivate *priv;
|
||||
+ ShellAppSystem *self;
|
||||
+ StTextureCache *texture_cache;
|
||||
+ gboolean rescanned;
|
||||
+
|
||||
+ self = (ShellAppSystem *) user_data;
|
||||
+ priv = self->priv;
|
||||
+
|
||||
+ texture_cache = st_texture_cache_get_default ();
|
||||
+ rescanned = st_texture_cache_rescan_icon_theme (texture_cache);
|
||||
+
|
||||
+ priv->n_rescan_retries++;
|
||||
+
|
||||
+ if (rescanned || priv->n_rescan_retries >= MAX_RESCAN_RETRIES)
|
||||
+ {
|
||||
+ priv->n_rescan_retries = 0;
|
||||
+ priv->rescan_icons_timeout_id = 0;
|
||||
+ return G_SOURCE_REMOVE;
|
||||
+ }
|
||||
+
|
||||
+ return G_SOURCE_CONTINUE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+rescan_icon_theme (ShellAppSystem *self)
|
||||
+{
|
||||
+ ShellAppSystemPrivate *priv = self->priv;
|
||||
+
|
||||
+ priv->n_rescan_retries = 0;
|
||||
+
|
||||
+ if (priv->rescan_icons_timeout_id > 0)
|
||||
+ return;
|
||||
+
|
||||
+ priv->rescan_icons_timeout_id = g_timeout_add (RESCAN_TIMEOUT_MS,
|
||||
+ rescan_icon_theme_cb,
|
||||
+ self);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
installed_changed (GAppInfoMonitor *monitor,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellAppSystem *self = user_data;
|
||||
|
||||
+ rescan_icon_theme (self);
|
||||
scan_startup_wm_class_to_id (self);
|
||||
|
||||
g_hash_table_foreach_remove (self->priv->id_to_app, stale_app_remove_func, NULL);
|
||||
@@ -200,6 +253,7 @@ shell_app_system_finalize (GObject *object)
|
||||
g_hash_table_destroy (priv->id_to_app);
|
||||
g_hash_table_destroy (priv->startup_wm_class_to_id);
|
||||
g_list_free_full (priv->installed_apps, g_object_unref);
|
||||
+ g_clear_handle_id (&priv->rescan_icons_timeout_id, g_source_remove);
|
||||
|
||||
G_OBJECT_CLASS (shell_app_system_parent_class)->finalize (object);
|
||||
}
|
||||
diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c
|
||||
index c1331747f..4d0d617c4 100644
|
||||
--- a/src/st/st-texture-cache.c
|
||||
+++ b/src/st/st-texture-cache.c
|
||||
@@ -1554,3 +1554,11 @@ st_texture_cache_get_default (void)
|
||||
instance = g_object_new (ST_TYPE_TEXTURE_CACHE, NULL);
|
||||
return instance;
|
||||
}
|
||||
+
|
||||
+gboolean
|
||||
+st_texture_cache_rescan_icon_theme (StTextureCache *cache)
|
||||
+{
|
||||
+ StTextureCachePrivate *priv = cache->priv;
|
||||
+
|
||||
+ return gtk_icon_theme_rescan_if_needed (priv->icon_theme);
|
||||
+}
|
||||
diff --git a/src/st/st-texture-cache.h b/src/st/st-texture-cache.h
|
||||
index 11d1c4e64..a99316da8 100644
|
||||
--- a/src/st/st-texture-cache.h
|
||||
+++ b/src/st/st-texture-cache.h
|
||||
@@ -113,4 +113,6 @@ CoglTexture * st_texture_cache_load (StTextureCache *cache,
|
||||
void *data,
|
||||
GError **error);
|
||||
|
||||
+gboolean st_texture_cache_rescan_icon_theme (StTextureCache *cache);
|
||||
+
|
||||
#endif /* __ST_TEXTURE_CACHE_H__ */
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,119 @@
|
||||
From 39cf97176e2a92506081ee151ea546e2c6cf213a Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Wed, 21 Aug 2019 15:06:46 -0400
|
||||
Subject: [PATCH 3/4] shellEntry: Handle password item from dedication function
|
||||
|
||||
At the moment, shellEntry handles creating and destroying its
|
||||
"Show Text" password menu item directly from its isPassword
|
||||
setter function.
|
||||
|
||||
This commit moves that handling to a dedicated _resetPasswordItem
|
||||
function, as prep work for adding lockdown support of the "Show Text"
|
||||
menu item.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/687
|
||||
---
|
||||
js/ui/shellEntry.js | 23 +++++++++++++++++------
|
||||
1 file changed, 17 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
|
||||
index 603a9c64a..765cede06 100644
|
||||
--- a/js/ui/shellEntry.js
|
||||
+++ b/js/ui/shellEntry.js
|
||||
@@ -14,76 +14,87 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
|
||||
|
||||
this._entry = entry;
|
||||
this._clipboard = St.Clipboard.get_default();
|
||||
|
||||
// Populate menu
|
||||
let item;
|
||||
item = new PopupMenu.PopupMenuItem(_("Copy"));
|
||||
item.connect('activate', this._onCopyActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._copyItem = item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Paste"));
|
||||
item.connect('activate', this._onPasteActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._pasteItem = item;
|
||||
|
||||
this._passwordItem = null;
|
||||
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
this.actor.hide();
|
||||
}
|
||||
|
||||
_makePasswordItem() {
|
||||
let item = new PopupMenu.PopupMenuItem('');
|
||||
item.connect('activate', this._onPasswordActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._passwordItem = item;
|
||||
this._updatePasswordItem();
|
||||
}
|
||||
|
||||
+ _resetPasswordItem() {
|
||||
+ if (!this.isPassword) {
|
||||
+ if (this._passwordItem) {
|
||||
+ this._passwordItem.destroy();
|
||||
+ this._passwordItem = null;
|
||||
+ }
|
||||
+ this._entry.clutter_text.set_password_char('\u25cf');
|
||||
+ } else {
|
||||
+ if (!this._passwordItem)
|
||||
+ this._makePasswordItem();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
get isPassword() {
|
||||
return this._entry.input_purpose == Clutter.InputContentPurpose.PASSWORD;
|
||||
}
|
||||
|
||||
set isPassword(v) {
|
||||
if (v == this.isPassword)
|
||||
return;
|
||||
|
||||
- if (v) {
|
||||
- this._makePasswordItem();
|
||||
+ if (v)
|
||||
this._entry.input_purpose = Clutter.InputContentPurpose.PASSWORD;
|
||||
- } else {
|
||||
- this._passwordItem.destroy();
|
||||
- this._passwordItem = null;
|
||||
+ else
|
||||
this._entry.input_purpose = Clutter.InputContentPurpose.NORMAL;
|
||||
- }
|
||||
+
|
||||
+ this._resetPasswordItem();
|
||||
}
|
||||
|
||||
open(animate) {
|
||||
this._updatePasteItem();
|
||||
this._updateCopyItem();
|
||||
if (this._passwordItem)
|
||||
this._updatePasswordItem();
|
||||
|
||||
super.open(animate);
|
||||
this._entry.add_style_pseudo_class('focus');
|
||||
|
||||
let direction = St.DirectionType.TAB_FORWARD;
|
||||
if (!this.actor.navigate_focus(null, direction, false))
|
||||
this.actor.grab_key_focus();
|
||||
}
|
||||
|
||||
_updateCopyItem() {
|
||||
let selection = this._entry.clutter_text.get_selection();
|
||||
this._copyItem.setSensitive(!this._entry.clutter_text.password_char &&
|
||||
selection && selection != '');
|
||||
}
|
||||
|
||||
_updatePasteItem() {
|
||||
this._clipboard.get_text(St.ClipboardType.CLIPBOARD,
|
||||
(clipboard, text) => {
|
||||
this._pasteItem.setSensitive(text && text != '');
|
||||
});
|
||||
}
|
||||
|
||||
_updatePasswordItem() {
|
||||
--
|
||||
2.27.0
|
||||
|
@ -0,0 +1,66 @@
|
||||
From 2ebeda3385fb679df4bc13ba4b80bdeba5e2ad13 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Tue, 15 Jan 2019 12:54:32 -0500
|
||||
Subject: [PATCH 3/4] st-texture-cache: purge on resume
|
||||
|
||||
With the proprietary nvidia driver, textures get garbled on suspend,
|
||||
so the texture cache needs to evict all textures in that situation.
|
||||
---
|
||||
js/ui/main.js | 6 +++++-
|
||||
src/st/st-texture-cache.c | 10 ++++++++++
|
||||
src/st/st-texture-cache.h | 1 +
|
||||
3 files changed, 16 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index 061303cf3..8d1755cf1 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -200,7 +200,11 @@ function _initializeUI() {
|
||||
return true;
|
||||
});
|
||||
|
||||
- global.display.connect('gl-video-memory-purged', loadTheme);
|
||||
+ global.display.connect('gl-video-memory-purged', () => {
|
||||
+ let cache = St.TextureCache.get_default();
|
||||
+ cache.clear();
|
||||
+ loadTheme();
|
||||
+ });
|
||||
|
||||
// Provide the bus object for gnome-session to
|
||||
// initiate logouts.
|
||||
diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c
|
||||
index cbe3afaba..40a11dd6d 100644
|
||||
--- a/src/st/st-texture-cache.c
|
||||
+++ b/src/st/st-texture-cache.c
|
||||
@@ -113,6 +113,16 @@ st_texture_cache_class_init (StTextureCacheClass *klass)
|
||||
G_TYPE_NONE, 1, G_TYPE_FILE);
|
||||
}
|
||||
|
||||
+/* Evicts all cached textures */
|
||||
+void
|
||||
+st_texture_cache_clear (StTextureCache *cache)
|
||||
+{
|
||||
+ g_return_if_fail (ST_IS_TEXTURE_CACHE (cache));
|
||||
+
|
||||
+ g_hash_table_remove_all (cache->priv->keyed_cache);
|
||||
+ g_signal_emit (cache, signals[ICON_THEME_CHANGED], 0);
|
||||
+}
|
||||
+
|
||||
/* Evicts all cached textures for named icons */
|
||||
static void
|
||||
st_texture_cache_evict_icons (StTextureCache *cache)
|
||||
diff --git a/src/st/st-texture-cache.h b/src/st/st-texture-cache.h
|
||||
index 11d1c4e64..9079d1fda 100644
|
||||
--- a/src/st/st-texture-cache.h
|
||||
+++ b/src/st/st-texture-cache.h
|
||||
@@ -53,6 +53,7 @@ typedef enum {
|
||||
} StTextureCachePolicy;
|
||||
|
||||
StTextureCache* st_texture_cache_get_default (void);
|
||||
+void st_texture_cache_clear (StTextureCache *cache);
|
||||
|
||||
ClutterActor *
|
||||
st_texture_cache_load_sliced_image (StTextureCache *cache,
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,115 @@
|
||||
From 055bc14c70af66fe1893dcd4c42c65662ae1f9d0 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 21 Jan 2019 15:07:15 -0500
|
||||
Subject: [PATCH 4/4] background: refresh background on gl-video-memory-purged
|
||||
signal
|
||||
|
||||
Right now we refresh the background when resuming and when NVIDIA.
|
||||
But mutter has a signal to tell us specifically when to refresh,
|
||||
and the signal is only emitted for NVIDIA, so use that instead.
|
||||
---
|
||||
js/ui/background.js | 9 +++++++--
|
||||
js/ui/layout.js | 12 ------------
|
||||
src/shell-util.c | 27 ---------------------------
|
||||
src/shell-util.h | 2 --
|
||||
4 files changed, 7 insertions(+), 43 deletions(-)
|
||||
|
||||
diff --git a/js/ui/background.js b/js/ui/background.js
|
||||
index 75b76a57e..466cc4de7 100644
|
||||
--- a/js/ui/background.js
|
||||
+++ b/js/ui/background.js
|
||||
@@ -527,10 +527,15 @@ var BackgroundSource = class BackgroundSource {
|
||||
let monitorManager = Meta.MonitorManager.get();
|
||||
this._monitorsChangedId =
|
||||
monitorManager.connect('monitors-changed',
|
||||
- this._onMonitorsChanged.bind(this));
|
||||
+ this._refresh.bind(this));
|
||||
+
|
||||
+ global.display.connect('gl-video-memory-purged', () => {
|
||||
+ Meta.Background.refresh_all();
|
||||
+ this._refresh();
|
||||
+ });
|
||||
}
|
||||
|
||||
- _onMonitorsChanged() {
|
||||
+ _refresh() {
|
||||
for (let monitorIndex in this._backgrounds) {
|
||||
let background = this._backgrounds[monitorIndex];
|
||||
|
||||
diff --git a/js/ui/layout.js b/js/ui/layout.js
|
||||
index 30e750dc5..2b3bb7442 100644
|
||||
--- a/js/ui/layout.js
|
||||
+++ b/js/ui/layout.js
|
||||
@@ -282,18 +282,6 @@ var LayoutManager = GObject.registerClass({
|
||||
monitorManager.connect('monitors-changed',
|
||||
this._monitorsChanged.bind(this));
|
||||
this._monitorsChanged();
|
||||
-
|
||||
- // NVIDIA drivers don't preserve FBO contents across
|
||||
- // suspend/resume, see
|
||||
- // https://bugzilla.gnome.org/show_bug.cgi?id=739178
|
||||
- if (Shell.util_need_background_refresh()) {
|
||||
- LoginManager.getLoginManager().connect('prepare-for-sleep',
|
||||
- (lm, suspending) => {
|
||||
- if (suspending)
|
||||
- return;
|
||||
- Meta.Background.refresh_all();
|
||||
- });
|
||||
- }
|
||||
}
|
||||
|
||||
// This is called by Main after everything else is constructed
|
||||
diff --git a/src/shell-util.c b/src/shell-util.c
|
||||
index c6e5abed6..9c25643c6 100644
|
||||
--- a/src/shell-util.c
|
||||
+++ b/src/shell-util.c
|
||||
@@ -374,33 +374,6 @@ shell_util_create_pixbuf_from_data (const guchar *data,
|
||||
(GdkPixbufDestroyNotify) g_free, NULL);
|
||||
}
|
||||
|
||||
-typedef const gchar *(*ShellGLGetString) (GLenum);
|
||||
-
|
||||
-static const gchar *
|
||||
-get_gl_vendor (void)
|
||||
-{
|
||||
- static const gchar *vendor = NULL;
|
||||
-
|
||||
- if (!vendor)
|
||||
- {
|
||||
- ShellGLGetString gl_get_string;
|
||||
- gl_get_string = (ShellGLGetString) cogl_get_proc_address ("glGetString");
|
||||
- if (gl_get_string)
|
||||
- vendor = gl_get_string (GL_VENDOR);
|
||||
- }
|
||||
-
|
||||
- return vendor;
|
||||
-}
|
||||
-
|
||||
-gboolean
|
||||
-shell_util_need_background_refresh (void)
|
||||
-{
|
||||
- if (g_strcmp0 (get_gl_vendor (), "NVIDIA Corporation") == 0)
|
||||
- return TRUE;
|
||||
-
|
||||
- return FALSE;
|
||||
-}
|
||||
-
|
||||
static gboolean
|
||||
canvas_draw_cb (ClutterContent *content,
|
||||
cairo_t *cr,
|
||||
diff --git a/src/shell-util.h b/src/shell-util.h
|
||||
index 6904f43bc..049c3fe18 100644
|
||||
--- a/src/shell-util.h
|
||||
+++ b/src/shell-util.h
|
||||
@@ -44,8 +44,6 @@ GdkPixbuf *shell_util_create_pixbuf_from_data (const guchar *data,
|
||||
int height,
|
||||
int rowstride);
|
||||
|
||||
-gboolean shell_util_need_background_refresh (void);
|
||||
-
|
||||
ClutterContent * shell_util_get_content_for_window_actor (MetaWindowActor *window_actor,
|
||||
MetaRectangle *window_rect);
|
||||
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,124 @@
|
||||
From 2a4f33df723d4b9ce68e5948b568a89675d37411 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hergert <chergert@redhat.com>
|
||||
Date: Wed, 26 Feb 2020 14:46:20 -0800
|
||||
Subject: [PATCH 4/6] global: force fsync() to worker thread when saving state
|
||||
|
||||
The g_file_replace_contents_async() API can potentially call fsync() from
|
||||
the thread calling into it upon completion. This can have disasterous
|
||||
effects when run from the compositor main thread such as complete stalls.
|
||||
|
||||
This is a followup to 86a00b6872375a266449beee1ea6d5e94f1ebbcb which
|
||||
assumed (like the rest of us) that the fsync() would be performed on the
|
||||
thread that was doing the I/O operations.
|
||||
|
||||
You can verify this with an strace -e fsync and cause terminal to display
|
||||
a command completed notification (eg: from a backdrop window).
|
||||
|
||||
This also fixes a lifecycle bug for the variant, as
|
||||
g_file_replace_contents_async() does not copy the data during the operation
|
||||
as that is the responsibility of the caller. Instead, we just use a GBytes
|
||||
variant and reference the variant there.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/1050
|
||||
---
|
||||
src/shell-global.c | 70 +++++++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 63 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/src/shell-global.c b/src/shell-global.c
|
||||
index df84b6b0d..4b33778e0 100644
|
||||
--- a/src/shell-global.c
|
||||
+++ b/src/shell-global.c
|
||||
@@ -1572,6 +1572,55 @@ delete_variant_cb (GObject *object,
|
||||
g_hash_table_remove (global->save_ops, object);
|
||||
}
|
||||
|
||||
+static void
|
||||
+replace_contents_worker (GTask *task,
|
||||
+ gpointer source_object,
|
||||
+ gpointer task_data,
|
||||
+ GCancellable *cancellable)
|
||||
+{
|
||||
+ GFile *file = source_object;
|
||||
+ GBytes *bytes = task_data;
|
||||
+ GError *error = NULL;
|
||||
+ const gchar *data;
|
||||
+ gsize len;
|
||||
+
|
||||
+ data = g_bytes_get_data (bytes, &len);
|
||||
+
|
||||
+ if (!g_file_replace_contents (file, data, len, NULL, FALSE,
|
||||
+ G_FILE_CREATE_REPLACE_DESTINATION,
|
||||
+ NULL, cancellable, &error))
|
||||
+ g_task_return_error (task, g_steal_pointer (&error));
|
||||
+ else
|
||||
+ g_task_return_boolean (task, TRUE);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+replace_contents_async (GFile *path,
|
||||
+ GBytes *bytes,
|
||||
+ GCancellable *cancellable,
|
||||
+ GAsyncReadyCallback callback,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ g_autoptr(GTask) task = NULL;
|
||||
+
|
||||
+ g_assert (G_IS_FILE (path));
|
||||
+ g_assert (bytes != NULL);
|
||||
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
+
|
||||
+ task = g_task_new (path, cancellable, callback, user_data);
|
||||
+ g_task_set_source_tag (task, replace_contents_async);
|
||||
+ g_task_set_task_data (task, g_bytes_ref (bytes), (GDestroyNotify)g_bytes_unref);
|
||||
+ g_task_run_in_thread (task, replace_contents_worker);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+replace_contents_finish (GFile *file,
|
||||
+ GAsyncResult *result,
|
||||
+ GError **error)
|
||||
+{
|
||||
+ return g_task_propagate_boolean (G_TASK (result), error);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
replace_variant_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
@@ -1580,7 +1629,7 @@ replace_variant_cb (GObject *object,
|
||||
ShellGlobal *global = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
- if (!g_file_replace_contents_finish (G_FILE (object), result, NULL, &error))
|
||||
+ if (!replace_contents_finish (G_FILE (object), result, &error))
|
||||
{
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
@@ -1616,12 +1665,19 @@ save_variant (ShellGlobal *global,
|
||||
}
|
||||
else
|
||||
{
|
||||
- g_file_replace_contents_async (path,
|
||||
- g_variant_get_data (variant),
|
||||
- g_variant_get_size (variant),
|
||||
- NULL, FALSE,
|
||||
- G_FILE_CREATE_REPLACE_DESTINATION,
|
||||
- cancellable, replace_variant_cb, global);
|
||||
+ g_autoptr(GBytes) bytes = NULL;
|
||||
+
|
||||
+ bytes = g_bytes_new_with_free_func (g_variant_get_data (variant),
|
||||
+ g_variant_get_size (variant),
|
||||
+ (GDestroyNotify)g_variant_unref,
|
||||
+ g_variant_ref (variant));
|
||||
+ /* g_file_replace_contents_async() can potentially fsync() from the
|
||||
+ * calling thread when completing the asynchronous task. Instead, we
|
||||
+ * want to force that fsync() to a thread to avoid blocking the
|
||||
+ * compository main loop. Using our own replace_contents_async()
|
||||
+ * simply executes the operation synchronously from a thread.
|
||||
+ */
|
||||
+ replace_contents_async (path, bytes, cancellable, replace_variant_cb, global);
|
||||
}
|
||||
|
||||
g_object_unref (path);
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,116 @@
|
||||
From 5fad989ca773f9e0ff6fdbeb0cb7c9cb70cc6148 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Tue, 10 Aug 2021 15:31:00 -0400
|
||||
Subject: [PATCH 4/4] sessionMode: Allow extensions at the login and unlock
|
||||
screens
|
||||
|
||||
Now extensions can specify which session modes they work in,
|
||||
but specifying the login screen or unlock screen session modes in
|
||||
an extensions metadata still won't work, because those session
|
||||
modes disallow extensions.
|
||||
|
||||
This commit fixes that.
|
||||
---
|
||||
js/ui/sessionMode.js | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js
|
||||
index fa7f83416..8d8ce1a64 100644
|
||||
--- a/js/ui/sessionMode.js
|
||||
+++ b/js/ui/sessionMode.js
|
||||
@@ -12,89 +12,92 @@ const Config = imports.misc.config;
|
||||
const DEFAULT_MODE = 'restrictive';
|
||||
|
||||
const _modes = {
|
||||
'restrictive': {
|
||||
parentMode: null,
|
||||
stylesheetName: 'gnome-shell.css',
|
||||
hasOverview: false,
|
||||
showCalendarEvents: false,
|
||||
allowSettings: false,
|
||||
allowExtensions: false,
|
||||
allowScreencast: false,
|
||||
enabledExtensions: [],
|
||||
hasRunDialog: false,
|
||||
hasWorkspaces: false,
|
||||
hasWindows: false,
|
||||
hasNotifications: false,
|
||||
isLocked: false,
|
||||
isGreeter: false,
|
||||
isPrimary: false,
|
||||
unlockDialog: null,
|
||||
components: [],
|
||||
panel: {
|
||||
left: [],
|
||||
center: [],
|
||||
right: []
|
||||
},
|
||||
panelStyle: null
|
||||
},
|
||||
|
||||
'gdm': {
|
||||
+ allowExtensions: true,
|
||||
hasNotifications: true,
|
||||
isGreeter: true,
|
||||
isPrimary: true,
|
||||
unlockDialog: imports.gdm.loginDialog.LoginDialog,
|
||||
components: Config.HAVE_NETWORKMANAGER
|
||||
? ['networkAgent', 'polkitAgent']
|
||||
: ['polkitAgent'],
|
||||
panel: {
|
||||
left: [],
|
||||
center: ['dateMenu'],
|
||||
right: ['a11y', 'keyboard', 'aggregateMenu']
|
||||
},
|
||||
panelStyle: 'login-screen'
|
||||
},
|
||||
|
||||
'lock-screen': {
|
||||
+ allowExtensions: true,
|
||||
isLocked: true,
|
||||
isGreeter: undefined,
|
||||
unlockDialog: undefined,
|
||||
components: ['polkitAgent', 'telepathyClient'],
|
||||
panel: {
|
||||
left: [],
|
||||
center: [],
|
||||
right: ['aggregateMenu']
|
||||
},
|
||||
panelStyle: 'lock-screen'
|
||||
},
|
||||
|
||||
'unlock-dialog': {
|
||||
+ allowExtensions: true,
|
||||
isLocked: true,
|
||||
unlockDialog: undefined,
|
||||
components: ['polkitAgent', 'telepathyClient'],
|
||||
panel: {
|
||||
left: [],
|
||||
center: [],
|
||||
right: ['a11y', 'keyboard', 'aggregateMenu']
|
||||
},
|
||||
panelStyle: 'unlock-screen'
|
||||
},
|
||||
|
||||
'user': {
|
||||
hasOverview: true,
|
||||
showCalendarEvents: true,
|
||||
allowSettings: true,
|
||||
allowExtensions: true,
|
||||
allowScreencast: true,
|
||||
hasRunDialog: true,
|
||||
hasWorkspaces: true,
|
||||
hasWindows: true,
|
||||
hasNotifications: true,
|
||||
isLocked: false,
|
||||
isPrimary: true,
|
||||
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
|
||||
components: Config.HAVE_NETWORKMANAGER ?
|
||||
['networkAgent', 'polkitAgent', 'telepathyClient',
|
||||
'keyring', 'autorunManager', 'automountManager'] :
|
||||
['polkitAgent', 'telepathyClient',
|
||||
'keyring', 'autorunManager', 'automountManager'],
|
||||
|
||||
--
|
||||
2.27.0
|
||||
|
@ -0,0 +1,116 @@
|
||||
From ee64cd773bdeef845d02dc84063f926d77090dec Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Wed, 21 Aug 2019 15:06:46 -0400
|
||||
Subject: [PATCH 4/4] shellEntry: Support lockdown of "Show Text" menu in
|
||||
password entries
|
||||
|
||||
Some deployments require being able to prevent users from showing
|
||||
the password they're currently typing.
|
||||
|
||||
This commit adds support for that kind of lockdown.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/687
|
||||
---
|
||||
js/ui/shellEntry.js | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
|
||||
index 765cede06..c45e4545a 100644
|
||||
--- a/js/ui/shellEntry.js
|
||||
+++ b/js/ui/shellEntry.js
|
||||
@@ -1,81 +1,89 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
-const { Clutter, GObject, Pango, Shell, St } = imports.gi;
|
||||
+const { Clutter, Gio, GObject, Pango, Shell, St } = imports.gi;
|
||||
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
+const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
|
||||
+const DISABLE_SHOW_PASSWORD_KEY = 'disable-show-password';
|
||||
+
|
||||
var EntryMenu = class extends PopupMenu.PopupMenu {
|
||||
constructor(entry) {
|
||||
super(entry, 0, St.Side.TOP);
|
||||
|
||||
+ this._lockdownSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA });
|
||||
+ this._lockdownSettings.connect('changed::' + DISABLE_SHOW_PASSWORD_KEY, this._resetPasswordItem.bind(this));
|
||||
+
|
||||
this._entry = entry;
|
||||
this._clipboard = St.Clipboard.get_default();
|
||||
|
||||
// Populate menu
|
||||
let item;
|
||||
item = new PopupMenu.PopupMenuItem(_("Copy"));
|
||||
item.connect('activate', this._onCopyActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._copyItem = item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Paste"));
|
||||
item.connect('activate', this._onPasteActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._pasteItem = item;
|
||||
|
||||
this._passwordItem = null;
|
||||
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
this.actor.hide();
|
||||
}
|
||||
|
||||
_makePasswordItem() {
|
||||
let item = new PopupMenu.PopupMenuItem('');
|
||||
item.connect('activate', this._onPasswordActivated.bind(this));
|
||||
this.addMenuItem(item);
|
||||
this._passwordItem = item;
|
||||
this._updatePasswordItem();
|
||||
}
|
||||
|
||||
_resetPasswordItem() {
|
||||
- if (!this.isPassword) {
|
||||
+ let passwordDisabled = this._lockdownSettings.get_boolean(DISABLE_SHOW_PASSWORD_KEY);
|
||||
+
|
||||
+ if (!this.isPassword || passwordDisabled) {
|
||||
if (this._passwordItem) {
|
||||
this._passwordItem.destroy();
|
||||
this._passwordItem = null;
|
||||
}
|
||||
this._entry.clutter_text.set_password_char('\u25cf');
|
||||
- } else {
|
||||
+ } else if (this.isPassword && !passwordDisabled) {
|
||||
if (!this._passwordItem)
|
||||
this._makePasswordItem();
|
||||
}
|
||||
}
|
||||
|
||||
get isPassword() {
|
||||
return this._entry.input_purpose == Clutter.InputContentPurpose.PASSWORD;
|
||||
}
|
||||
|
||||
set isPassword(v) {
|
||||
if (v == this.isPassword)
|
||||
return;
|
||||
|
||||
if (v)
|
||||
this._entry.input_purpose = Clutter.InputContentPurpose.PASSWORD;
|
||||
else
|
||||
this._entry.input_purpose = Clutter.InputContentPurpose.NORMAL;
|
||||
|
||||
this._resetPasswordItem();
|
||||
}
|
||||
|
||||
open(animate) {
|
||||
this._updatePasteItem();
|
||||
this._updateCopyItem();
|
||||
if (this._passwordItem)
|
||||
this._updatePasswordItem();
|
||||
|
||||
super.open(animate);
|
||||
this._entry.add_style_pseudo_class('focus');
|
||||
|
||||
--
|
||||
2.27.0
|
||||
|
@ -0,0 +1,674 @@
|
||||
From a3fc35a2b452855d004549afbec57d1b4f36c917 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hergert <chergert@redhat.com>
|
||||
Date: Thu, 27 Feb 2020 19:36:14 -0800
|
||||
Subject: [PATCH 5/6] app-cache: add ShellAppCache for GAppInfo caching
|
||||
|
||||
This caches GAppInfo so that the compositor thread does not have to perform
|
||||
costly disk access to load them. Instead, they are loaded from a worker
|
||||
thread and the ShellAppCache notifies of changes.
|
||||
|
||||
To simplify maintenance, ShellAppCache manages this directly and the
|
||||
existing ShellAppSystem wraps the cache. We may want to graft these
|
||||
together in the future, but now it provides the easiest way to backport
|
||||
changes to older Shell releases.
|
||||
|
||||
Another source of compositor thread disk access was in determining the
|
||||
name for an application directory. Translations are provided via GKeyFile
|
||||
installed in "desktop-directories". Each time we would build the name
|
||||
for a label (or update it) we would have to load all of these files.
|
||||
|
||||
Instead, the ShellAppCache caches that information and updates the cache
|
||||
in bulk when those change. We can reduce this in the future to do less
|
||||
work, but chances are these will come together anyway so that is probably
|
||||
worth fixing if we ever come across it.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/2282
|
||||
---
|
||||
js/ui/appDisplay.js | 12 +-
|
||||
src/meson.build | 5 +-
|
||||
src/shell-app-cache-private.h | 19 ++
|
||||
src/shell-app-cache.c | 404 ++++++++++++++++++++++++++++++++++
|
||||
src/shell-app-system.c | 34 ++-
|
||||
src/shell-util.c | 16 ++
|
||||
src/shell-util.h | 2 +
|
||||
7 files changed, 463 insertions(+), 29 deletions(-)
|
||||
create mode 100644 src/shell-app-cache-private.h
|
||||
create mode 100644 src/shell-app-cache.c
|
||||
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index 7fad02cd0..a2d691085 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -78,15 +78,9 @@ function _getFolderName(folder) {
|
||||
let name = folder.get_string('name');
|
||||
|
||||
if (folder.get_boolean('translate')) {
|
||||
- let keyfile = new GLib.KeyFile();
|
||||
- let path = 'desktop-directories/' + name;
|
||||
-
|
||||
- try {
|
||||
- keyfile.load_from_data_dirs(path, GLib.KeyFileFlags.NONE);
|
||||
- name = keyfile.get_locale_string('Desktop Entry', 'Name', null);
|
||||
- } catch(e) {
|
||||
- return name;
|
||||
- }
|
||||
+ let translated = Shell.util_get_translated_folder_name(name);
|
||||
+ if (translated !== null)
|
||||
+ return translated;
|
||||
}
|
||||
|
||||
return name;
|
||||
diff --git a/src/meson.build b/src/meson.build
|
||||
index 97a5a796c..2b911d347 100644
|
||||
--- a/src/meson.build
|
||||
+++ b/src/meson.build
|
||||
@@ -108,6 +108,7 @@ endif
|
||||
|
||||
libshell_private_headers = [
|
||||
'shell-app-private.h',
|
||||
+ 'shell-app-cache-private.h',
|
||||
'shell-app-system-private.h',
|
||||
'shell-global-private.h',
|
||||
'shell-window-tracker-private.h',
|
||||
@@ -146,7 +147,9 @@ if have_networkmanager
|
||||
libshell_sources += 'shell-network-agent.c'
|
||||
endif
|
||||
|
||||
-libshell_private_sources = []
|
||||
+libshell_private_sources = [
|
||||
+ 'shell-app-cache.c',
|
||||
+]
|
||||
|
||||
if enable_recorder
|
||||
libshell_sources += ['shell-recorder.c']
|
||||
diff --git a/src/shell-app-cache-private.h b/src/shell-app-cache-private.h
|
||||
new file mode 100644
|
||||
index 000000000..b73094ab1
|
||||
--- /dev/null
|
||||
+++ b/src/shell-app-cache-private.h
|
||||
@@ -0,0 +1,19 @@
|
||||
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
+#ifndef __SHELL_APP_CACHE_PRIVATE_H__
|
||||
+#define __SHELL_APP_CACHE_PRIVATE_H__
|
||||
+
|
||||
+#include <gio/gio.h>
|
||||
+#include <gio/gdesktopappinfo.h>
|
||||
+
|
||||
+#define SHELL_TYPE_APP_CACHE (shell_app_cache_get_type())
|
||||
+
|
||||
+G_DECLARE_FINAL_TYPE (ShellAppCache, shell_app_cache, SHELL, APP_CACHE, GObject)
|
||||
+
|
||||
+ShellAppCache *shell_app_cache_get_default (void);
|
||||
+GList *shell_app_cache_get_all (ShellAppCache *cache);
|
||||
+GDesktopAppInfo *shell_app_cache_get_info (ShellAppCache *cache,
|
||||
+ const char *id);
|
||||
+char *shell_app_cache_translate_folder (ShellAppCache *cache,
|
||||
+ const char *name);
|
||||
+
|
||||
+#endif /* __SHELL_APP_CACHE_PRIVATE_H__ */
|
||||
diff --git a/src/shell-app-cache.c b/src/shell-app-cache.c
|
||||
new file mode 100644
|
||||
index 000000000..15d4734d0
|
||||
--- /dev/null
|
||||
+++ b/src/shell-app-cache.c
|
||||
@@ -0,0 +1,404 @@
|
||||
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
+
|
||||
+#include "config.h"
|
||||
+
|
||||
+#include "shell-app-cache-private.h"
|
||||
+
|
||||
+/**
|
||||
+ * SECTION:shell-app-cache
|
||||
+ * @title: ShellAppCache
|
||||
+ * @short_description: application information cache
|
||||
+ *
|
||||
+ * The #ShellAppCache is responsible for caching information about #GAppInfo
|
||||
+ * to ensure that the compositor thread never needs to perform disk reads to
|
||||
+ * access them. All of the work is done off-thread. When the new data has
|
||||
+ * been loaded, a #ShellAppCache::changed signal is emitted.
|
||||
+ *
|
||||
+ * Additionally, the #ShellAppCache caches information about translations for
|
||||
+ * directories. This allows translation provided in [Desktop Entry] GKeyFiles
|
||||
+ * to be available when building StLabel and other elements without performing
|
||||
+ * costly disk reads.
|
||||
+ *
|
||||
+ * Various monitors are used to keep this information up to date while the
|
||||
+ * Shell is running.
|
||||
+ */
|
||||
+
|
||||
+#define DEFAULT_TIMEOUT_SECONDS 5
|
||||
+
|
||||
+struct _ShellAppCache
|
||||
+{
|
||||
+ GObject parent_instance;
|
||||
+
|
||||
+ GAppInfoMonitor *monitor;
|
||||
+ GPtrArray *dir_monitors;
|
||||
+ GHashTable *folders;
|
||||
+ GCancellable *cancellable;
|
||||
+ GList *app_infos;
|
||||
+
|
||||
+ guint queued_update;
|
||||
+};
|
||||
+
|
||||
+typedef struct
|
||||
+{
|
||||
+ GList *app_infos;
|
||||
+ GHashTable *folders;
|
||||
+} CacheState;
|
||||
+
|
||||
+G_DEFINE_TYPE (ShellAppCache, shell_app_cache, G_TYPE_OBJECT)
|
||||
+
|
||||
+enum {
|
||||
+ CHANGED,
|
||||
+ N_SIGNALS
|
||||
+};
|
||||
+
|
||||
+static guint signals [N_SIGNALS];
|
||||
+
|
||||
+static void
|
||||
+cache_state_free (CacheState *state)
|
||||
+{
|
||||
+ g_clear_pointer (&state->folders, g_hash_table_unref);
|
||||
+ g_list_free_full (state->app_infos, g_object_unref);
|
||||
+ g_slice_free (CacheState, state);
|
||||
+}
|
||||
+
|
||||
+static CacheState *
|
||||
+cache_state_new (void)
|
||||
+{
|
||||
+ CacheState *state;
|
||||
+
|
||||
+ state = g_slice_new0 (CacheState);
|
||||
+ state->folders = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
+
|
||||
+ return g_steal_pointer (&state);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * shell_app_cache_get_default:
|
||||
+ *
|
||||
+ * Gets the default #ShellAppCache.
|
||||
+ *
|
||||
+ * Returns: (transfer none): a #ShellAppCache
|
||||
+ */
|
||||
+ShellAppCache *
|
||||
+shell_app_cache_get_default (void)
|
||||
+{
|
||||
+ static ShellAppCache *instance;
|
||||
+
|
||||
+ if (instance == NULL)
|
||||
+ {
|
||||
+ instance = g_object_new (SHELL_TYPE_APP_CACHE, NULL);
|
||||
+ g_object_add_weak_pointer (G_OBJECT (instance), (gpointer *)&instance);
|
||||
+ }
|
||||
+
|
||||
+ return instance;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+load_folder (GHashTable *folders,
|
||||
+ const char *path)
|
||||
+{
|
||||
+ g_autoptr(GDir) dir = NULL;
|
||||
+ const char *name;
|
||||
+
|
||||
+ g_assert (folders != NULL);
|
||||
+ g_assert (path != NULL);
|
||||
+
|
||||
+ dir = g_dir_open (path, 0, NULL);
|
||||
+ if (dir == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ while ((name = g_dir_read_name (dir)))
|
||||
+ {
|
||||
+ g_autofree gchar *filename = NULL;
|
||||
+ g_autoptr(GKeyFile) keyfile = NULL;
|
||||
+
|
||||
+ /* First added wins */
|
||||
+ if (g_hash_table_contains (folders, name))
|
||||
+ continue;
|
||||
+
|
||||
+ filename = g_build_filename (path, name, NULL);
|
||||
+ keyfile = g_key_file_new ();
|
||||
+
|
||||
+ if (g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL))
|
||||
+ {
|
||||
+ gchar *translated;
|
||||
+
|
||||
+ translated = g_key_file_get_locale_string (keyfile,
|
||||
+ "Desktop Entry", "Name",
|
||||
+ NULL, NULL);
|
||||
+
|
||||
+ if (translated != NULL)
|
||||
+ g_hash_table_insert (folders, g_strdup (name), translated);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+load_folders (GHashTable *folders)
|
||||
+{
|
||||
+ const char * const *dirs;
|
||||
+ g_autofree gchar *userdir = NULL;
|
||||
+ guint i;
|
||||
+
|
||||
+ g_assert (folders != NULL);
|
||||
+
|
||||
+ userdir = g_build_filename (g_get_user_data_dir (), "desktop-directories", NULL);
|
||||
+ load_folder (folders, userdir);
|
||||
+
|
||||
+ dirs = g_get_system_data_dirs ();
|
||||
+ for (i = 0; dirs[i] != NULL; i++)
|
||||
+ {
|
||||
+ g_autofree gchar *sysdir = g_build_filename (dirs[i], "desktop-directories", NULL);
|
||||
+ load_folder (folders, sysdir);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+shell_app_cache_worker (GTask *task,
|
||||
+ gpointer source_object,
|
||||
+ gpointer task_data,
|
||||
+ GCancellable *cancellable)
|
||||
+{
|
||||
+ CacheState *state;
|
||||
+
|
||||
+ g_assert (G_IS_TASK (task));
|
||||
+ g_assert (SHELL_IS_APP_CACHE (source_object));
|
||||
+
|
||||
+ state = cache_state_new ();
|
||||
+ state->app_infos = g_app_info_get_all ();
|
||||
+ load_folders (state->folders);
|
||||
+
|
||||
+ g_task_return_pointer (task, state, (GDestroyNotify) cache_state_free);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+apply_update_cb (GObject *object,
|
||||
+ GAsyncResult *result,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ ShellAppCache *cache = (ShellAppCache *)object;
|
||||
+ g_autoptr(GError) error = NULL;
|
||||
+ CacheState *state;
|
||||
+
|
||||
+ g_assert (SHELL_IS_APP_CACHE (cache));
|
||||
+ g_assert (G_IS_TASK (result));
|
||||
+ g_assert (user_data == NULL);
|
||||
+
|
||||
+ state = g_task_propagate_pointer (G_TASK (result), &error);
|
||||
+
|
||||
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
+ return;
|
||||
+
|
||||
+ g_list_free_full (cache->app_infos, g_object_unref);
|
||||
+ cache->app_infos = g_steal_pointer (&state->app_infos);
|
||||
+
|
||||
+ g_clear_pointer (&cache->folders, g_hash_table_unref);
|
||||
+ cache->folders = g_steal_pointer (&state->folders);
|
||||
+
|
||||
+ g_signal_emit (cache, signals[CHANGED], 0);
|
||||
+
|
||||
+ cache_state_free (state);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+shell_app_cache_do_update (gpointer user_data)
|
||||
+{
|
||||
+ ShellAppCache *cache = user_data;
|
||||
+ g_autoptr(GTask) task = NULL;
|
||||
+
|
||||
+ cache->queued_update = 0;
|
||||
+
|
||||
+ /* Reset the cancellable state so we don't race with
|
||||
+ * two updates coming back overlapped and applying the
|
||||
+ * information in the wrong order.
|
||||
+ */
|
||||
+ g_cancellable_cancel (cache->cancellable);
|
||||
+ g_clear_object (&cache->cancellable);
|
||||
+ cache->cancellable = g_cancellable_new ();
|
||||
+
|
||||
+ task = g_task_new (cache, cache->cancellable, apply_update_cb, NULL);
|
||||
+ g_task_set_source_tag (task, shell_app_cache_do_update);
|
||||
+ g_task_run_in_thread (task, shell_app_cache_worker);
|
||||
+
|
||||
+ return G_SOURCE_REMOVE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+shell_app_cache_queue_update (ShellAppCache *self)
|
||||
+{
|
||||
+ g_assert (SHELL_IS_APP_CACHE (self));
|
||||
+
|
||||
+ if (self->queued_update != 0)
|
||||
+ g_source_remove (self->queued_update);
|
||||
+
|
||||
+ self->queued_update = g_timeout_add_seconds (DEFAULT_TIMEOUT_SECONDS,
|
||||
+ shell_app_cache_do_update,
|
||||
+ self);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+monitor_desktop_directories_for_data_dir (ShellAppCache *self,
|
||||
+ const gchar *directory)
|
||||
+{
|
||||
+ g_autofree gchar *subdir = NULL;
|
||||
+ g_autoptr(GFile) file = NULL;
|
||||
+ g_autoptr(GFileMonitor) monitor = NULL;
|
||||
+
|
||||
+ g_assert (SHELL_IS_APP_CACHE (self));
|
||||
+
|
||||
+ if (directory == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ subdir = g_build_filename (directory, "desktop-directories", NULL);
|
||||
+ file = g_file_new_for_path (subdir);
|
||||
+ monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||
+
|
||||
+ if (monitor != NULL)
|
||||
+ {
|
||||
+ g_file_monitor_set_rate_limit (monitor, DEFAULT_TIMEOUT_SECONDS * 1000);
|
||||
+ g_signal_connect_object (monitor,
|
||||
+ "changed",
|
||||
+ G_CALLBACK (shell_app_cache_queue_update),
|
||||
+ self,
|
||||
+ G_CONNECT_SWAPPED);
|
||||
+ g_ptr_array_add (self->dir_monitors, g_steal_pointer (&monitor));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+shell_app_cache_finalize (GObject *object)
|
||||
+{
|
||||
+ ShellAppCache *self = (ShellAppCache *)object;
|
||||
+
|
||||
+ g_clear_object (&self->monitor);
|
||||
+
|
||||
+ if (self->queued_update)
|
||||
+ {
|
||||
+ g_source_remove (self->queued_update);
|
||||
+ self->queued_update = 0;
|
||||
+ }
|
||||
+
|
||||
+ g_clear_pointer (&self->dir_monitors, g_ptr_array_unref);
|
||||
+ g_clear_pointer (&self->folders, g_hash_table_unref);
|
||||
+ g_list_free_full (self->app_infos, g_object_unref);
|
||||
+
|
||||
+ G_OBJECT_CLASS (shell_app_cache_parent_class)->finalize (object);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+shell_app_cache_class_init (ShellAppCacheClass *klass)
|
||||
+{
|
||||
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
+
|
||||
+ object_class->finalize = shell_app_cache_finalize;
|
||||
+
|
||||
+ /**
|
||||
+ * ShellAppCache::changed:
|
||||
+ *
|
||||
+ * The "changed" signal is emitted when the cache has updated
|
||||
+ * information about installed applications.
|
||||
+ */
|
||||
+ signals [CHANGED] =
|
||||
+ g_signal_new ("changed",
|
||||
+ G_TYPE_FROM_CLASS (klass),
|
||||
+ G_SIGNAL_RUN_LAST,
|
||||
+ 0, NULL, NULL, NULL,
|
||||
+ G_TYPE_NONE, 0);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+shell_app_cache_init (ShellAppCache *self)
|
||||
+{
|
||||
+ const gchar * const *sysdirs;
|
||||
+ guint i;
|
||||
+
|
||||
+ /* Monitor directories for translation changes */
|
||||
+ self->dir_monitors = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
+ monitor_desktop_directories_for_data_dir (self, g_get_user_data_dir ());
|
||||
+ sysdirs = g_get_system_data_dirs ();
|
||||
+ for (i = 0; sysdirs[i] != NULL; i++)
|
||||
+ monitor_desktop_directories_for_data_dir (self, sysdirs[i]);
|
||||
+
|
||||
+ /* Load translated directory names immediately */
|
||||
+ self->folders = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
+ load_folders (self->folders);
|
||||
+
|
||||
+ /* Setup AppMonitor to track changes */
|
||||
+ self->monitor = g_app_info_monitor_get ();
|
||||
+ g_signal_connect_object (self->monitor,
|
||||
+ "changed",
|
||||
+ G_CALLBACK (shell_app_cache_queue_update),
|
||||
+ self,
|
||||
+ G_CONNECT_SWAPPED);
|
||||
+ self->app_infos = g_app_info_get_all ();
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * shell_app_cache_get_all:
|
||||
+ * @cache: (nullable): a #ShellAppCache or %NULL
|
||||
+ *
|
||||
+ * Like g_app_info_get_all() but always returns a
|
||||
+ * cached set of application info so the caller can be
|
||||
+ * sure that I/O will not happen on the current thread.
|
||||
+ *
|
||||
+ * Returns: (transfer none) (element-type GAppInfo):
|
||||
+ * a #GList of references to #GAppInfo.
|
||||
+ */
|
||||
+GList *
|
||||
+shell_app_cache_get_all (ShellAppCache *cache)
|
||||
+{
|
||||
+ g_return_val_if_fail (SHELL_IS_APP_CACHE (cache), NULL);
|
||||
+
|
||||
+ return cache->app_infos;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * shell_app_cache_get_info:
|
||||
+ * @cache: (nullable): a #ShellAppCache or %NULL
|
||||
+ * @id: the application id
|
||||
+ *
|
||||
+ * A replacement for g_desktop_app_info_new() that will lookup the
|
||||
+ * information from the cache instead of (re)loading from disk.
|
||||
+ *
|
||||
+ * Returns: (nullable) (transfer none): a #GDesktopAppInfo or %NULL
|
||||
+ */
|
||||
+GDesktopAppInfo *
|
||||
+shell_app_cache_get_info (ShellAppCache *cache,
|
||||
+ const char *id)
|
||||
+{
|
||||
+ const GList *iter;
|
||||
+
|
||||
+ g_return_val_if_fail (SHELL_IS_APP_CACHE (cache), NULL);
|
||||
+
|
||||
+ for (iter = cache->app_infos; iter != NULL; iter = iter->next)
|
||||
+ {
|
||||
+ GAppInfo *info = iter->data;
|
||||
+
|
||||
+ if (g_strcmp0 (id, g_app_info_get_id (info)) == 0)
|
||||
+ return G_DESKTOP_APP_INFO (info);
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * shell_app_cache_translate_folder:
|
||||
+ * @cache: (nullable): a #ShellAppCache or %NULL
|
||||
+ * @name: the folder name
|
||||
+ *
|
||||
+ * Gets the translated folder name for @name if any exists.
|
||||
+ *
|
||||
+ * Returns: (nullable): the translated string or %NULL if there is no
|
||||
+ * translation.
|
||||
+ */
|
||||
+char *
|
||||
+shell_app_cache_translate_folder (ShellAppCache *cache,
|
||||
+ const char *name)
|
||||
+{
|
||||
+ g_return_val_if_fail (SHELL_IS_APP_CACHE (cache), NULL);
|
||||
+
|
||||
+ if (name == NULL)
|
||||
+ return NULL;
|
||||
+
|
||||
+ return g_strdup (g_hash_table_lookup (cache->folders, name));
|
||||
+}
|
||||
diff --git a/src/shell-app-system.c b/src/shell-app-system.c
|
||||
index 127f29ef0..828fa726a 100644
|
||||
--- a/src/shell-app-system.c
|
||||
+++ b/src/shell-app-system.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <gio/gio.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
+#include "shell-app-cache-private.h"
|
||||
#include "shell-app-private.h"
|
||||
#include "shell-window-tracker-private.h"
|
||||
#include "shell-app-system-private.h"
|
||||
@@ -94,14 +95,14 @@ static void
|
||||
scan_startup_wm_class_to_id (ShellAppSystem *self)
|
||||
{
|
||||
ShellAppSystemPrivate *priv = self->priv;
|
||||
- GList *l;
|
||||
+ const GList *l;
|
||||
+ GList *all;
|
||||
|
||||
g_hash_table_remove_all (priv->startup_wm_class_to_id);
|
||||
|
||||
- g_list_free_full (priv->installed_apps, g_object_unref);
|
||||
- priv->installed_apps = g_app_info_get_all ();
|
||||
+ all = shell_app_cache_get_all (shell_app_cache_get_default ());
|
||||
|
||||
- for (l = priv->installed_apps; l != NULL; l = l->next)
|
||||
+ for (l = all; l != NULL; l = l->next)
|
||||
{
|
||||
GAppInfo *info = l->data;
|
||||
const char *startup_wm_class, *id, *old_id;
|
||||
@@ -131,7 +132,8 @@ app_is_stale (ShellApp *app)
|
||||
if (shell_app_is_window_backed (app))
|
||||
return FALSE;
|
||||
|
||||
- info = g_desktop_app_info_new (shell_app_get_id (app));
|
||||
+ info = shell_app_cache_get_info (shell_app_cache_get_default (),
|
||||
+ shell_app_get_id (app));
|
||||
if (!info)
|
||||
return TRUE;
|
||||
|
||||
@@ -156,7 +158,6 @@ app_is_stale (ShellApp *app)
|
||||
g_icon_equal (g_app_info_get_icon (old_info),
|
||||
g_app_info_get_icon (new_info));
|
||||
|
||||
- g_object_unref (info);
|
||||
return !is_unchanged;
|
||||
}
|
||||
|
||||
@@ -210,11 +211,9 @@ rescan_icon_theme (ShellAppSystem *self)
|
||||
}
|
||||
|
||||
static void
|
||||
-installed_changed (GAppInfoMonitor *monitor,
|
||||
- gpointer user_data)
|
||||
+installed_changed (ShellAppCache *cache,
|
||||
+ ShellAppSystem *self)
|
||||
{
|
||||
- ShellAppSystem *self = user_data;
|
||||
-
|
||||
rescan_icon_theme (self);
|
||||
scan_startup_wm_class_to_id (self);
|
||||
|
||||
@@ -227,7 +226,7 @@ static void
|
||||
shell_app_system_init (ShellAppSystem *self)
|
||||
{
|
||||
ShellAppSystemPrivate *priv;
|
||||
- GAppInfoMonitor *monitor;
|
||||
+ ShellAppCache *cache;
|
||||
|
||||
self->priv = priv = shell_app_system_get_instance_private (self);
|
||||
|
||||
@@ -238,9 +237,9 @@ shell_app_system_init (ShellAppSystem *self)
|
||||
|
||||
priv->startup_wm_class_to_id = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
- monitor = g_app_info_monitor_get ();
|
||||
- g_signal_connect (monitor, "changed", G_CALLBACK (installed_changed), self);
|
||||
- installed_changed (monitor, self);
|
||||
+ cache = shell_app_cache_get_default ();
|
||||
+ g_signal_connect (cache, "changed", G_CALLBACK (installed_changed), self);
|
||||
+ installed_changed (cache, self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -293,13 +292,12 @@ shell_app_system_lookup_app (ShellAppSystem *self,
|
||||
if (app)
|
||||
return app;
|
||||
|
||||
- info = g_desktop_app_info_new (id);
|
||||
+ info = shell_app_cache_get_info (shell_app_cache_get_default (), id);
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
app = _shell_app_new (info);
|
||||
g_hash_table_insert (priv->id_to_app, (char *) shell_app_get_id (app), app);
|
||||
- g_object_unref (info);
|
||||
return app;
|
||||
}
|
||||
|
||||
@@ -506,7 +504,5 @@ shell_app_system_search (const char *search_string)
|
||||
GList *
|
||||
shell_app_system_get_installed (ShellAppSystem *self)
|
||||
{
|
||||
- ShellAppSystemPrivate *priv = self->priv;
|
||||
-
|
||||
- return priv->installed_apps;
|
||||
+ return shell_app_cache_get_all (shell_app_cache_get_default ());
|
||||
}
|
||||
diff --git a/src/shell-util.c b/src/shell-util.c
|
||||
index fa3fc08c8..370784523 100644
|
||||
--- a/src/shell-util.c
|
||||
+++ b/src/shell-util.c
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <GL/gl.h>
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
+#include "shell-app-cache-private.h"
|
||||
#include "shell-util.h"
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <gtk/gtk.h>
|
||||
@@ -639,3 +640,18 @@ shell_util_has_x11_display_extension (MetaDisplay *display,
|
||||
xdisplay = meta_x11_display_get_xdisplay (x11_display);
|
||||
return XQueryExtension (xdisplay, extension, &op, &event, &error);
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * shell_util_get_translated_folder_name:
|
||||
+ * @name: the untranslated folder name
|
||||
+ *
|
||||
+ * Attempts to translate the folder @name using translations provided
|
||||
+ * by .directory files.
|
||||
+ *
|
||||
+ * Returns: (nullable): a translated string or %NULL
|
||||
+ */
|
||||
+char *
|
||||
+shell_util_get_translated_folder_name (const char *name)
|
||||
+{
|
||||
+ return shell_app_cache_translate_folder (shell_app_cache_get_default (), name);
|
||||
+}
|
||||
diff --git a/src/shell-util.h b/src/shell-util.h
|
||||
index 02b8404e9..843a1253d 100644
|
||||
--- a/src/shell-util.h
|
||||
+++ b/src/shell-util.h
|
||||
@@ -62,6 +62,8 @@ void shell_util_check_cloexec_fds (void);
|
||||
gboolean shell_util_has_x11_display_extension (MetaDisplay *display,
|
||||
const char *extension);
|
||||
|
||||
+char *shell_util_get_translated_folder_name (const char *name);
|
||||
+
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_UTIL_H__ */
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,36 @@
|
||||
From 7a264550c5f3a98b1786b1a75cff01cde1d084eb Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 29 Jul 2021 17:17:43 +0200
|
||||
Subject: [PATCH 5/5] shellEntry: Only mask text in password entries
|
||||
|
||||
When "Show Text" is locked down, we not only remove the corresponding
|
||||
menu item, but also make sure the password is masked.
|
||||
|
||||
Except that the current code is too eager, and masks the text in
|
||||
any entries.
|
||||
---
|
||||
js/ui/shellEntry.js | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
|
||||
index c45e4545a..64b389050 100644
|
||||
--- a/js/ui/shellEntry.js
|
||||
+++ b/js/ui/shellEntry.js
|
||||
@@ -55,11 +55,13 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
|
||||
this._passwordItem.destroy();
|
||||
this._passwordItem = null;
|
||||
}
|
||||
- this._entry.clutter_text.set_password_char('\u25cf');
|
||||
} else if (this.isPassword && !passwordDisabled) {
|
||||
if (!this._passwordItem)
|
||||
this._makePasswordItem();
|
||||
}
|
||||
+
|
||||
+ if (this.isPassword && passwordDisabled)
|
||||
+ this._entry.clutter_text.set_password_char('\u25cf');
|
||||
}
|
||||
|
||||
get isPassword() {
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,66 @@
|
||||
From a0df79f8de4c13c36ed3b22cfdbb78e324424ef1 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Sat, 14 Mar 2020 14:45:42 +0100
|
||||
Subject: [PATCH 6/6] js: Always use AppSystem to lookup apps
|
||||
|
||||
There is no good reason for bypassing the application cache in
|
||||
AppSystem and loading .desktop files again.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1093
|
||||
---
|
||||
js/ui/appDisplay.js | 4 ++--
|
||||
js/ui/calendar.js | 16 ++++++++++------
|
||||
2 files changed, 12 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index a2d691085..cb2be7d3c 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -1001,8 +1001,8 @@ var AppSearchProvider = class AppSearchProvider {
|
||||
let results = [];
|
||||
groups.forEach(group => {
|
||||
group = group.filter(appID => {
|
||||
- let app = Gio.DesktopAppInfo.new(appID);
|
||||
- return app && app.should_show();
|
||||
+ const app = this._appSys.lookup_app(appID);
|
||||
+ return app && app.app_info.should_show();
|
||||
});
|
||||
results = results.concat(group.sort(
|
||||
(a, b) => usage.compare(a, b)
|
||||
diff --git a/js/ui/calendar.js b/js/ui/calendar.js
|
||||
index cd3e879c4..3ae2e44f8 100644
|
||||
--- a/js/ui/calendar.js
|
||||
+++ b/js/ui/calendar.js
|
||||
@@ -791,8 +791,9 @@ var EventsSection = class EventsSection extends MessageList.MessageListSection {
|
||||
this._title.connect('clicked', this._onTitleClicked.bind(this));
|
||||
this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this));
|
||||
|
||||
- Shell.AppSystem.get_default().connect('installed-changed',
|
||||
- this._appInstalledChanged.bind(this));
|
||||
+ this._appSys = Shell.AppSystem.get_default();
|
||||
+ this._appSys.connect('installed-changed',
|
||||
+ this._appInstalledChanged.bind(this));
|
||||
this._appInstalledChanged();
|
||||
}
|
||||
|
||||
@@ -883,10 +884,13 @@ var EventsSection = class EventsSection extends MessageList.MessageListSection {
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
|
||||
- let app = this._getCalendarApp();
|
||||
- if (app.get_id() == 'evolution.desktop')
|
||||
- app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
|
||||
- app.launch([], global.create_app_launch_context(0, -1));
|
||||
+ let appInfo = this._getCalendarApp();
|
||||
+ if (app.get_id() == 'evolution.desktop') {
|
||||
+ let app = this._appSys.lookup_app('evolution-calendar.desktop');
|
||||
+ if (app)
|
||||
+ appInfo = app.app_info;
|
||||
+ }
|
||||
+ appInfo.launch([], global.create_app_launch_context(0, -1));
|
||||
}
|
||||
|
||||
setDate(date) {
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,159 @@
|
||||
From 3252f05b8745a5d3118986474793fe3ecc2b041c Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Tue, 19 Apr 2016 13:12:46 -0400
|
||||
Subject: [PATCH] loginDialog: allow timed login with disabled user list
|
||||
|
||||
At the moment the timed login feature is implemented in the user list.
|
||||
If there's no user list, we don't show the indicator anywhere and
|
||||
don't proceed with timed login.
|
||||
|
||||
This commit allows timed login to work when the user list is disabled.
|
||||
It accomplishes this by putting the timed login indicator on the
|
||||
auth prompt, in that scenario.
|
||||
---
|
||||
data/theme/gnome-shell-sass/_common.scss | 4 +++
|
||||
js/gdm/authPrompt.js | 41 +++++++++++++++++++++++-
|
||||
js/gdm/loginDialog.js | 25 +++++++++++++--
|
||||
3 files changed, 67 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
|
||||
index a6357baad..c2df28279 100644
|
||||
--- a/data/theme/gnome-shell-sass/_common.scss
|
||||
+++ b/data/theme/gnome-shell-sass/_common.scss
|
||||
@@ -1856,6 +1856,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 {
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index 27eb31a89..cf77b3f26 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -1,6 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
-const { Clutter, Pango, Shell, St } = imports.gi;
|
||||
+const { Clutter, GLib, Pango, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Animation = imports.ui.animation;
|
||||
@@ -111,6 +111,11 @@ var AuthPrompt = class {
|
||||
|
||||
this._entry.grab_key_focus();
|
||||
|
||||
+ this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
|
||||
+ scale_x: 0 });
|
||||
+
|
||||
+ this.actor.add(this._timedLoginIndicator);
|
||||
+
|
||||
this._message = new St.Label({ opacity: 0,
|
||||
styleClass: 'login-dialog-message' });
|
||||
this._message.clutter_text.line_wrap = true;
|
||||
@@ -135,6 +140,40 @@ var AuthPrompt = class {
|
||||
this._defaultButtonWell.add_child(this._spinner.actor);
|
||||
}
|
||||
|
||||
+ showTimedLoginIndicator(time) {
|
||||
+ let hold = new Batch.Hold();
|
||||
+
|
||||
+ this.hideTimedLoginIndicator();
|
||||
+
|
||||
+ let startTime = GLib.get_monotonic_time();
|
||||
+
|
||||
+ this._timedLoginTimeoutId = GLib.timeout_add (GLib.PRIORITY_DEFAULT, 33,
|
||||
+ () => {
|
||||
+ let currentTime = GLib.get_monotonic_time();
|
||||
+ let elapsedTime = (currentTime - startTime) / GLib.USEC_PER_SEC;
|
||||
+ this._timedLoginIndicator.scale_x = elapsedTime / time;
|
||||
+ if (elapsedTime >= time) {
|
||||
+ this._timedLoginTimeoutId = 0;
|
||||
+ hold.release();
|
||||
+ return GLib.SOURCE_REMOVE;
|
||||
+ }
|
||||
+
|
||||
+ return GLib.SOURCE_CONTINUE;
|
||||
+ });
|
||||
+
|
||||
+ GLib.Source.set_name_by_id(this._timedLoginTimeoutId, '[gnome-shell] this._timedLoginTimeoutId');
|
||||
+
|
||||
+ return hold;
|
||||
+ }
|
||||
+
|
||||
+ hideTimedLoginIndicator() {
|
||||
+ if (this._timedLoginTimeoutId) {
|
||||
+ GLib.source_remove(this._timedLoginTimeoutId);
|
||||
+ this._timedLoginTimeoutId = 0;
|
||||
+ }
|
||||
+ this._timedLoginIndicator.scale_x = 0.;
|
||||
+ }
|
||||
+
|
||||
_onDestroy() {
|
||||
if (this._preemptiveAnswerWatchId) {
|
||||
this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
|
||||
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
|
||||
index 6c4d1357d..b4df6e959 100644
|
||||
--- a/js/gdm/loginDialog.js
|
||||
+++ b/js/gdm/loginDialog.js
|
||||
@@ -734,6 +734,9 @@ var LoginDialog = GObject.registerClass({
|
||||
|
||||
if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||
this._authPrompt.reset();
|
||||
+
|
||||
+ if (this._disableUserList && this._timedLoginUserListHold)
|
||||
+ this._timedLoginUserListHold.release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,16 +1023,31 @@ var LoginDialog = GObject.registerClass({
|
||||
let loginItem = null;
|
||||
let animationTime;
|
||||
|
||||
- let tasks = [() => this._waitForItemForUser(userName),
|
||||
+ let tasks = [() => {
|
||||
+ if (this._disableUserList)
|
||||
+ return;
|
||||
+
|
||||
+ this._timedLoginUserListHold = this._waitForItemForUser(userName);
|
||||
+
|
||||
+ return this._timedLoginUserListHold;
|
||||
+ },
|
||||
|
||||
() => {
|
||||
- loginItem = this._userList.getItemFromUserName(userName);
|
||||
+ this._timedLoginUserListHold = null;
|
||||
+
|
||||
+
|
||||
+ loginItem = this._disableUserList
|
||||
+ ? this._authPrompt
|
||||
+ : this._userList.getItemFromUserName(userName);
|
||||
|
||||
// If there is an animation running on the item, reset it.
|
||||
loginItem.hideTimedLoginIndicator();
|
||||
},
|
||||
|
||||
() => {
|
||||
+ if (this._disableUserList)
|
||||
+ return;
|
||||
+
|
||||
// If we're just starting out, start on the right item.
|
||||
if (!this._userManager.is_loaded) {
|
||||
this._userList.jumpToItem(loginItem);
|
||||
@@ -1051,6 +1069,9 @@ var LoginDialog = GObject.registerClass({
|
||||
},
|
||||
|
||||
() => {
|
||||
+ if (this._disableUserList)
|
||||
+ return;
|
||||
+
|
||||
// If idle timeout is done, make sure the timed login indicator is shown
|
||||
if (delay > _TIMED_LOGIN_IDLE_THRESHOLD &&
|
||||
this._authPrompt.actor.visible)
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,145 @@
|
||||
From 7bdd1962213a37f6218fe15ea1a4062dd318672a Mon Sep 17 00:00:00 2001
|
||||
From: Will Thompson <wjt@endlessm.com>
|
||||
Date: Wed, 28 Aug 2019 15:39:44 +0100
|
||||
Subject: [PATCH 1/2] global: Don't trust persistent/runtime state data
|
||||
|
||||
An Endless OS system was found in the wild with a malformed
|
||||
.local/share/gnome-shell/notifications. When deserialized in Python,
|
||||
after passing trusted=True to g_variant_new_from_bytes(), the first
|
||||
element of the first struct in the array looks like this:
|
||||
|
||||
In [41]: _38.get_child_value(0).get_child_value(0)
|
||||
Out[41]: GLib.Variant('s', '\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff')
|
||||
|
||||
When deserialised in GJS, we get:
|
||||
|
||||
gjs> v.get_child_value(0).get_child_value(0)
|
||||
[object variant of type "s"]
|
||||
gjs> v.get_child_value(0).get_child_value(0).get_string()
|
||||
typein:43:1 malformed UTF-8 character sequence at offset 0
|
||||
@typein:43:1
|
||||
@<stdin>:1:34
|
||||
|
||||
While g_variant_new_from_bytes() doesn't have much to say about its
|
||||
'trusted' parameter, g_variant_new_from_data() does:
|
||||
|
||||
> If data is trusted to be serialised data in normal form then trusted
|
||||
> should be TRUE. This applies to serialised data created within this
|
||||
> process or read from a trusted location on the disk (such as a file
|
||||
> installed in /usr/lib alongside your application). You should set
|
||||
> trusted to FALSE if data is read from the network, a file in the
|
||||
> user's home directory, etc.
|
||||
|
||||
Persistent state is read from the user's home directory, so it should
|
||||
not be trusted. With trusted=False, the string value above comes out as
|
||||
"".
|
||||
|
||||
I don't have an explanation for how this file ended up being malformed.
|
||||
I also don't have an explanation for when this started crashing: my
|
||||
guess is that recent GJS became stricter about validating UTF-8 but I
|
||||
could be wrong!
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1552
|
||||
---
|
||||
src/shell-global.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/shell-global.c b/src/shell-global.c
|
||||
index 4b33778e0..33046f614 100644
|
||||
--- a/src/shell-global.c
|
||||
+++ b/src/shell-global.c
|
||||
@@ -1707,7 +1707,7 @@ load_variant (GFile *dir,
|
||||
else
|
||||
{
|
||||
GBytes *bytes = g_mapped_file_get_bytes (mfile);
|
||||
- res = g_variant_new_from_bytes (G_VARIANT_TYPE (property_type), bytes, TRUE);
|
||||
+ res = g_variant_new_from_bytes (G_VARIANT_TYPE (property_type), bytes, FALSE);
|
||||
g_bytes_unref (bytes);
|
||||
g_mapped_file_unref (mfile);
|
||||
}
|
||||
--
|
||||
2.35.1
|
||||
|
||||
|
||||
From 13dcb3e4400b92a0d2f548e88b70b358240d462c Mon Sep 17 00:00:00 2001
|
||||
From: Will Thompson <wjt@endlessm.com>
|
||||
Date: Wed, 28 Aug 2019 15:38:03 +0100
|
||||
Subject: [PATCH 2/2] notificationDaemon: Catch exceptions while loading
|
||||
notifications
|
||||
|
||||
An Endless OS system was found in the wild with a malformed
|
||||
.local/share/gnome-shell/notifications which causes _loadNotifications()
|
||||
to raise an exception. This exception was not previously handled and
|
||||
bubbles all the way out to gnome_shell_plugin_start(), whereupon the
|
||||
shell exit(1)s. The user could no longer log into their computer.
|
||||
|
||||
Handle exceptions from _loadNotifications(), log them, and attempt to
|
||||
continue. Ensure that this._isLoading is set to 'false' even on error,
|
||||
so that future calls to _saveNotifications() can overwrite the (corrupt)
|
||||
state file.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1552
|
||||
---
|
||||
js/ui/notificationDaemon.js | 42 ++++++++++++++++++++-----------------
|
||||
1 file changed, 23 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
|
||||
index 4bdede841..dbe673b88 100644
|
||||
--- a/js/ui/notificationDaemon.js
|
||||
+++ b/js/ui/notificationDaemon.js
|
||||
@@ -749,29 +749,33 @@ var GtkNotificationDaemon = class GtkNotificationDaemon {
|
||||
_loadNotifications() {
|
||||
this._isLoading = true;
|
||||
|
||||
- let value = global.get_persistent_state('a(sa(sv))', 'notifications');
|
||||
- if (value) {
|
||||
- let sources = value.deep_unpack();
|
||||
- sources.forEach(([appId, notifications]) => {
|
||||
- if (notifications.length == 0)
|
||||
- return;
|
||||
-
|
||||
- let source;
|
||||
- try {
|
||||
- source = this._ensureAppSource(appId);
|
||||
- } catch(e) {
|
||||
- if (e instanceof InvalidAppError)
|
||||
+ try {
|
||||
+ let value = global.get_persistent_state('a(sa(sv))', 'notifications');
|
||||
+ if (value) {
|
||||
+ let sources = value.deep_unpack();
|
||||
+ sources.forEach(([appId, notifications]) => {
|
||||
+ if (notifications.length == 0)
|
||||
return;
|
||||
- throw e;
|
||||
- }
|
||||
|
||||
- notifications.forEach(([notificationId, notification]) => {
|
||||
- source.addNotification(notificationId, notification.deep_unpack(), false);
|
||||
+ let source;
|
||||
+ try {
|
||||
+ source = this._ensureAppSource(appId);
|
||||
+ } catch (e) {
|
||||
+ if (e instanceof InvalidAppError)
|
||||
+ return;
|
||||
+ throw e;
|
||||
+ }
|
||||
+
|
||||
+ notifications.forEach(([notificationId, notification]) => {
|
||||
+ source.addNotification(notificationId, notification.deep_unpack(), false);
|
||||
+ });
|
||||
});
|
||||
- });
|
||||
+ }
|
||||
+ } catch (e) {
|
||||
+ logError(e, 'Failed to load saved notifications');
|
||||
+ } finally {
|
||||
+ this._isLoading = false;
|
||||
}
|
||||
-
|
||||
- this._isLoading = false;
|
||||
}
|
||||
|
||||
_saveNotifications() {
|
||||
--
|
||||
2.35.1
|
||||
|
@ -0,0 +1,167 @@
|
||||
From a57132816ac7bd93d6875fee0a6c5b273177ac8d Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Wed, 30 Sep 2015 12:51:24 -0400
|
||||
Subject: [PATCH 1/3] authPrompt: don't fade out auth messages if user types
|
||||
password up front
|
||||
|
||||
Right now we fade out any stale auth messages as soon as the user starts
|
||||
typing. This behavior doesn't really make sense if the user is typing up
|
||||
front, before a password is asked.
|
||||
---
|
||||
js/gdm/authPrompt.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index d7f53a92e..d421a8856 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -169,7 +169,7 @@ var AuthPrompt = class {
|
||||
this._updateNextButtonSensitivity(this._entry.text.length > 0);
|
||||
|
||||
this._entry.clutter_text.connect('text-changed', () => {
|
||||
- if (!this._userVerifier.hasPendingMessages)
|
||||
+ if (!this._userVerifier.hasPendingMessages && this._queryingService && !this._preemptiveAnswer)
|
||||
this._fadeOutMessage();
|
||||
|
||||
this._updateNextButtonSensitivity(this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING);
|
||||
--
|
||||
2.21.0
|
||||
|
||||
|
||||
From 50af703ea95f2b73733c38e66c9c251663a51744 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Wed, 30 Sep 2015 14:36:33 -0400
|
||||
Subject: [PATCH 2/3] authPrompt: don't spin unless answering question
|
||||
|
||||
---
|
||||
js/gdm/authPrompt.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index d421a8856..62c5bd078 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -60,8 +60,8 @@ var AuthPrompt = class {
|
||||
|
||||
this.connect('next', () => {
|
||||
this.updateSensitivity(false);
|
||||
- this.startSpinning();
|
||||
if (this._queryingService) {
|
||||
+ this.startSpinning();
|
||||
this._userVerifier.answerQuery(this._queryingService, this._entry.text);
|
||||
} else {
|
||||
this._preemptiveAnswer = this._entry.text;
|
||||
--
|
||||
2.21.0
|
||||
|
||||
|
||||
From b89be880936ad9dd145eb43890ac72d03c37785d Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 5 Oct 2015 15:26:18 -0400
|
||||
Subject: [PATCH 3/3] authPrompt: stop accepting preemptive answer if user
|
||||
stops typing
|
||||
|
||||
We only want to allow the user to type the preemptive password in
|
||||
one smooth motion. If they start to type, and then stop typing,
|
||||
we should discard their preemptive password as expired.
|
||||
|
||||
Typing ahead the password is just a convenience for users who don't
|
||||
want to manually lift the shift before typing their passwords, after
|
||||
all.
|
||||
---
|
||||
js/gdm/authPrompt.js | 37 +++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 37 insertions(+)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index 62c5bd078..27eb31a89 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -6,6 +6,7 @@ const Signals = imports.signals;
|
||||
const Animation = imports.ui.animation;
|
||||
const Batch = imports.gdm.batch;
|
||||
const GdmUtil = imports.gdm.util;
|
||||
+const Meta = imports.gi.Meta;
|
||||
const Params = imports.misc.params;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const Tweener = imports.ui.tweener;
|
||||
@@ -41,6 +42,8 @@ var AuthPrompt = class {
|
||||
this._gdmClient = gdmClient;
|
||||
this._mode = mode;
|
||||
|
||||
+ this._idleMonitor = Meta.IdleMonitor.get_core();
|
||||
+
|
||||
let reauthenticationOnly;
|
||||
if (this._mode == AuthPromptMode.UNLOCK_ONLY)
|
||||
reauthenticationOnly = true;
|
||||
@@ -65,6 +68,11 @@ var AuthPrompt = class {
|
||||
this._userVerifier.answerQuery(this._queryingService, this._entry.text);
|
||||
} else {
|
||||
this._preemptiveAnswer = this._entry.text;
|
||||
+
|
||||
+ if (this._preemptiveAnswerWatchId) {
|
||||
+ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
|
||||
+ this._preemptiveAnswerWatchId = 0;
|
||||
+ }
|
||||
}
|
||||
});
|
||||
|
||||
@@ -128,6 +136,11 @@ var AuthPrompt = class {
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
+ if (this._preemptiveAnswerWatchId) {
|
||||
+ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
|
||||
+ this._preemptiveAnswerWatchId = 0;
|
||||
+ }
|
||||
+
|
||||
this._userVerifier.destroy();
|
||||
this._userVerifier = null;
|
||||
}
|
||||
@@ -342,6 +355,11 @@ var AuthPrompt = class {
|
||||
}
|
||||
|
||||
setQuestion(question) {
|
||||
+ if (this._preemptiveAnswerWatchId) {
|
||||
+ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
|
||||
+ this._preemptiveAnswerWatchId = 0;
|
||||
+ }
|
||||
+
|
||||
this._label.set_text(question);
|
||||
|
||||
this._label.show();
|
||||
@@ -427,6 +445,19 @@ var AuthPrompt = class {
|
||||
}
|
||||
}
|
||||
|
||||
+ _onUserStoppedTypePreemptiveAnswer() {
|
||||
+ if (!this._preemptiveAnswerWatchId ||
|
||||
+ this._preemptiveAnswer ||
|
||||
+ this._queryingService)
|
||||
+ return;
|
||||
+
|
||||
+ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
|
||||
+ this._preemptiveAnswerWatchId = 0;
|
||||
+
|
||||
+ this._entry.text = '';
|
||||
+ this.updateSensitivity(false);
|
||||
+ }
|
||||
+
|
||||
reset() {
|
||||
let oldStatus = this.verificationStatus;
|
||||
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||
@@ -434,6 +465,12 @@ var AuthPrompt = class {
|
||||
this.nextButton.label = _("Next");
|
||||
this._preemptiveAnswer = null;
|
||||
|
||||
+ if (this._preemptiveAnswerWatchId) {
|
||||
+ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
|
||||
+ }
|
||||
+ this._preemptiveAnswerWatchId = this._idleMonitor.add_idle_watch (500,
|
||||
+ this._onUserStoppedTypePreemptiveAnswer.bind(this));
|
||||
+
|
||||
if (this._userVerifier)
|
||||
this._userVerifier.cancel();
|
||||
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,114 @@
|
||||
From 8ce91c85fe052d1a9f4fed0743bceae7d9654aa0 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 28 Sep 2015 10:57:02 -0400
|
||||
Subject: [PATCH 1/3] smartcardManager: add way to detect if user logged using
|
||||
(any) token
|
||||
|
||||
If a user uses a token at login time, we need to make sure they continue
|
||||
to use the token at unlock time.
|
||||
|
||||
As a prerequisite for addressing that problem we need to know up front
|
||||
if a user logged in with a token at all.
|
||||
|
||||
This commit adds the necessary api to detect that case.
|
||||
---
|
||||
js/misc/smartcardManager.js | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/js/misc/smartcardManager.js b/js/misc/smartcardManager.js
|
||||
index fda782d1e..bb43c96e7 100644
|
||||
--- a/js/misc/smartcardManager.js
|
||||
+++ b/js/misc/smartcardManager.js
|
||||
@@ -112,5 +112,12 @@ var SmartcardManager = class {
|
||||
return true;
|
||||
}
|
||||
|
||||
+ loggedInWithToken() {
|
||||
+ if (this._loginToken)
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
};
|
||||
Signals.addSignalMethods(SmartcardManager.prototype);
|
||||
--
|
||||
2.21.0
|
||||
|
||||
|
||||
From 6decf5560d309579760e10048533d3bd9bc56c3c Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 28 Sep 2015 19:56:53 -0400
|
||||
Subject: [PATCH 2/3] gdm: only unlock with smartcard, if smartcard used for
|
||||
login
|
||||
|
||||
If a smartcard is used for login, we need to make sure the smartcard
|
||||
gets used for unlock, too.
|
||||
---
|
||||
js/gdm/util.js | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/gdm/util.js b/js/gdm/util.js
|
||||
index 2e9935250..2b80e1dd9 100644
|
||||
--- a/js/gdm/util.js
|
||||
+++ b/js/gdm/util.js
|
||||
@@ -126,7 +126,6 @@ var ShellUserVerifier = class {
|
||||
this._settings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA });
|
||||
this._settings.connect('changed',
|
||||
this._updateDefaultService.bind(this));
|
||||
- this._updateDefaultService();
|
||||
|
||||
this._fprintManager = Fprint.FprintManager();
|
||||
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
||||
@@ -138,6 +137,8 @@ var ShellUserVerifier = class {
|
||||
this.smartcardDetected = false;
|
||||
this._checkForSmartcard();
|
||||
|
||||
+ this._updateDefaultService();
|
||||
+
|
||||
this._smartcardInsertedId = this._smartcardManager.connect('smartcard-inserted',
|
||||
this._checkForSmartcard.bind(this));
|
||||
this._smartcardRemovedId = this._smartcardManager.connect('smartcard-removed',
|
||||
@@ -407,7 +408,9 @@ var ShellUserVerifier = class {
|
||||
}
|
||||
|
||||
_updateDefaultService() {
|
||||
- if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
|
||||
+ if (this._smartcardManager.loggedInWithToken())
|
||||
+ this._defaultService = SMARTCARD_SERVICE_NAME;
|
||||
+ else if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
|
||||
this._defaultService = PASSWORD_SERVICE_NAME;
|
||||
else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
|
||||
this._defaultService = SMARTCARD_SERVICE_NAME;
|
||||
--
|
||||
2.21.0
|
||||
|
||||
|
||||
From dd844c98c3450dd1b21bcc580b51162c1b00ed2a Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 28 Sep 2015 19:57:36 -0400
|
||||
Subject: [PATCH 3/3] gdm: update default service when smartcard inserted
|
||||
|
||||
Early on at start up we may not know if a smartcard is
|
||||
available. Make sure we reupdate the default service
|
||||
after we get a smartcard insertion event.
|
||||
---
|
||||
js/gdm/util.js | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/js/gdm/util.js b/js/gdm/util.js
|
||||
index 2b80e1dd9..6e940d2ab 100644
|
||||
--- a/js/gdm/util.js
|
||||
+++ b/js/gdm/util.js
|
||||
@@ -327,6 +327,8 @@ var ShellUserVerifier = class {
|
||||
else if (this._preemptingService == SMARTCARD_SERVICE_NAME)
|
||||
this._preemptingService = null;
|
||||
|
||||
+ this._updateDefaultService();
|
||||
+
|
||||
this.emit('smartcard-status-changed');
|
||||
}
|
||||
}
|
||||
--
|
||||
2.21.0
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,421 @@
|
||||
From a518c9f57e5fe9c6b5ece5c6cb0534a83f0b2f2d Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 15 Jul 2019 13:52:58 -0400
|
||||
Subject: [PATCH 1/8] appDisplay: Don't leak duplicate items in AppView
|
||||
|
||||
If an icon already exists in an app view with the same id, the
|
||||
duplicate is not added on a call to addItem. Unfortunately,
|
||||
since it's not added, the icon actor gets orphaned and leaked.
|
||||
|
||||
This commit address the problem by introducing a new hasItem
|
||||
method and disallowing callers to call addItem with a duplicate
|
||||
in the first place.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
|
||||
---
|
||||
js/ui/appDisplay.js | 15 ++++++++++++---
|
||||
1 file changed, 12 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index a07db6573..fa22f47e0 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -143,10 +143,14 @@ class BaseAppView {
|
||||
return this._allItems;
|
||||
}
|
||||
|
||||
+ hasItem(id) {
|
||||
+ return this._items[id] !== undefined;
|
||||
+ }
|
||||
+
|
||||
addItem(icon) {
|
||||
let id = icon.id;
|
||||
- if (this._items[id] !== undefined)
|
||||
- return;
|
||||
+ if (this.hasItem(id))
|
||||
+ throw new Error(`icon with id ${id} already added to view`)
|
||||
|
||||
this._allItems.push(icon);
|
||||
this._items[id] = icon;
|
||||
@@ -386,6 +390,8 @@ var AllView = class AllView extends BaseAppView {
|
||||
|
||||
let folders = this._folderSettings.get_strv('folder-children');
|
||||
folders.forEach(id => {
|
||||
+ if (this.hasItem(id))
|
||||
+ return;
|
||||
let path = this._folderSettings.path + 'folders/' + id + '/';
|
||||
let icon = new FolderIcon(id, path, this);
|
||||
icon.connect('name-changed', this._itemNameChanged.bind(this));
|
||||
@@ -1165,7 +1171,10 @@ var FolderIcon = class FolderIcon {
|
||||
let excludedApps = this._folder.get_strv('excluded-apps');
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
let addAppId = appId => {
|
||||
- if (excludedApps.indexOf(appId) >= 0)
|
||||
+ if (this.view.hasItem(appId))
|
||||
+ return;
|
||||
+
|
||||
+ if (excludedApps.includes(appId))
|
||||
return;
|
||||
|
||||
let app = appSys.lookup_app(appId);
|
||||
--
|
||||
2.23.0
|
||||
|
||||
|
||||
From 2b6aa9aed98c4854c2ad015879ddcb8d2bf91e9e Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 22 Jul 2019 11:06:30 -0400
|
||||
Subject: [PATCH 2/8] iconGrid: Clear meta_later callback on destruction
|
||||
|
||||
The IconGrid code sometimes sets up a callback to be invoked
|
||||
later right before being destroyed.
|
||||
|
||||
This commit adds a destroy handler to cancel the callback.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
|
||||
---
|
||||
js/ui/iconGrid.js | 16 ++++++++++++++--
|
||||
1 file changed, 14 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
|
||||
index d51a443e8..1f05e67f3 100644
|
||||
--- a/js/ui/iconGrid.js
|
||||
+++ b/js/ui/iconGrid.js
|
||||
@@ -210,6 +210,8 @@ var IconGrid = GObject.registerClass({
|
||||
this.rightPadding = 0;
|
||||
this.leftPadding = 0;
|
||||
|
||||
+ this._updateIconSizesLaterId = 0;
|
||||
+
|
||||
this._items = [];
|
||||
this._clonesAnimating = [];
|
||||
// Pulled from CSS, but hardcode some defaults here
|
||||
@@ -227,6 +229,14 @@ var IconGrid = GObject.registerClass({
|
||||
|
||||
this.connect('actor-added', this._childAdded.bind(this));
|
||||
this.connect('actor-removed', this._childRemoved.bind(this));
|
||||
+ this.connect('destroy', this._onDestroy.bind(this));
|
||||
+ }
|
||||
+
|
||||
+ _onDestroy() {
|
||||
+ if (this._updateIconSizesLaterId) {
|
||||
+ Meta.later_remove (this._updateIconSizesLaterId);
|
||||
+ this._updateIconSizesLaterId = 0;
|
||||
+ }
|
||||
}
|
||||
|
||||
_keyFocusIn(actor) {
|
||||
@@ -757,12 +767,14 @@ var IconGrid = GObject.registerClass({
|
||||
|
||||
this._updateSpacingForSize(availWidth, availHeight);
|
||||
}
|
||||
- Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
- this._updateIconSizes.bind(this));
|
||||
+ if (!this._updateIconSizesLaterId)
|
||||
+ this._updateIconSizesLaterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
+ this._updateIconSizes.bind(this));
|
||||
}
|
||||
|
||||
// Note that this is ICON_SIZE as used by BaseIcon, not elsewhere in IconGrid; it's a bit messed up
|
||||
_updateIconSizes() {
|
||||
+ this._updateIconSizesLaterId = 0;
|
||||
let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, this._vItemSize);
|
||||
let newIconSize = Math.floor(ICON_SIZE * scale);
|
||||
for (let i in this._items) {
|
||||
--
|
||||
2.23.0
|
||||
|
||||
|
||||
From 14a2650548a5104d6a3ec7a1174a23264d79030a Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 22 Jul 2019 11:02:10 -0400
|
||||
Subject: [PATCH 3/8] appDisplay: Add AppFolderPopup destroy handler
|
||||
|
||||
At the moment AppFolderPopup calls popdown on destruction,
|
||||
which leads to open-state-changed getting emitted after
|
||||
the actor associated with the popup is destroyed.
|
||||
|
||||
This commit handles ungrabbing and closing from an
|
||||
actor destroy handler to side-step the open-state-changed
|
||||
signal.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
|
||||
---
|
||||
js/ui/appDisplay.js | 9 +++++++++
|
||||
1 file changed, 9 insertions(+)
|
||||
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index fa22f47e0..b75d095d5 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -1329,6 +1329,15 @@ var AppFolderPopup = class AppFolderPopup {
|
||||
});
|
||||
this._grabHelper.addActor(Main.layoutManager.overviewGroup);
|
||||
this.actor.connect('key-press-event', this._onKeyPress.bind(this));
|
||||
+ this.actor.connect('destroy', this._onDestroy.bind(this));
|
||||
+ }
|
||||
+
|
||||
+ _onDestroy() {
|
||||
+ if (this._isOpen) {
|
||||
+ this._isOpen = false;
|
||||
+ this._grabHelper.ungrab({ actor: this.actor });
|
||||
+ this._grabHelper = null;
|
||||
+ }
|
||||
}
|
||||
|
||||
_onKeyPress(actor, event) {
|
||||
--
|
||||
2.23.0
|
||||
|
||||
|
||||
From c9fcb2d23141694ffa2182df20ba75687b01dacc Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Thu, 18 Jul 2019 10:06:38 -0400
|
||||
Subject: [PATCH 4/8] appDisplay: Clear AllView reference to current popup when
|
||||
destroyed
|
||||
|
||||
AllView contains a reference to the current popup that lingers after
|
||||
the popup is destroyed.
|
||||
|
||||
This commit fixes that, by explicitly nullifying when appropriate.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
|
||||
---
|
||||
js/ui/appDisplay.js | 18 +++++++++++++++++-
|
||||
1 file changed, 17 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index b75d095d5..dabf63bfd 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -300,6 +300,7 @@ var AllView = class AllView extends BaseAppView {
|
||||
this._eventBlocker.add_action(this._clickAction);
|
||||
|
||||
this._displayingPopup = false;
|
||||
+ this._currentPopupDestroyId = 0;
|
||||
|
||||
this._availWidth = 0;
|
||||
this._availHeight = 0;
|
||||
@@ -589,7 +590,22 @@ var AllView = class AllView extends BaseAppView {
|
||||
this._stack.add_actor(popup.actor);
|
||||
popup.connect('open-state-changed', (popup, isOpen) => {
|
||||
this._eventBlocker.reactive = isOpen;
|
||||
- this._currentPopup = isOpen ? popup : null;
|
||||
+
|
||||
+ if (this._currentPopup) {
|
||||
+ this._currentPopup.actor.disconnect(this._currentPopupDestroyId);
|
||||
+ this._currentPopupDestroyId = 0;
|
||||
+ }
|
||||
+
|
||||
+ this._currentPopup = null;
|
||||
+
|
||||
+ if (isOpen) {
|
||||
+ this._currentPopup = popup;
|
||||
+ this._currentPopupDestroyId = popup.actor.connect('destroy', () => {
|
||||
+ this._currentPopup = null;
|
||||
+ this._currentPopupDestroyId = 0;
|
||||
+ this._eventBlocker.reactive = false;
|
||||
+ });
|
||||
+ }
|
||||
this._updateIconOpacities(isOpen);
|
||||
if(!isOpen)
|
||||
this._closeSpaceForPopup();
|
||||
--
|
||||
2.23.0
|
||||
|
||||
|
||||
From b7a3fd7fa4527ba9411dcd18debe6ccf88c34dc0 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 22 Jul 2019 10:57:57 -0400
|
||||
Subject: [PATCH 5/8] appDisplay: Add destroy handler for FolderIcon
|
||||
|
||||
It is important that the FolderView of a FolderIcon always
|
||||
gets destroyed before the AppFolderPopup, since the view
|
||||
may or may not be in the popup, and the view should
|
||||
get cleaned up exactly once in either case.
|
||||
|
||||
This commit adds a destroy handler on FolderIcon to ensure
|
||||
things get taken down in the right order, and to make sure
|
||||
the view isn't leaked if it's not yet part of the popup.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
|
||||
---
|
||||
js/ui/appDisplay.js | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index dabf63bfd..5a8f4f1bf 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -1156,6 +1156,7 @@ var FolderIcon = class FolderIcon {
|
||||
this.view.actor.vscroll.adjustment.value = 0;
|
||||
this._openSpaceForPopup();
|
||||
});
|
||||
+ this.actor.connect('destroy', this.onDestroy.bind(this));
|
||||
this.actor.connect('notify::mapped', () => {
|
||||
if (!this.actor.mapped && this._popup)
|
||||
this._popup.popdown();
|
||||
@@ -1165,6 +1166,13 @@ var FolderIcon = class FolderIcon {
|
||||
this._redisplay();
|
||||
}
|
||||
|
||||
+ onDestroy() {
|
||||
+ this.view.actor.destroy();
|
||||
+
|
||||
+ if (this._popup)
|
||||
+ this._popup.actor.destroy();
|
||||
+ }
|
||||
+
|
||||
getAppIds() {
|
||||
return this.view.getAllItems().map(item => item.id);
|
||||
}
|
||||
--
|
||||
2.23.0
|
||||
|
||||
|
||||
From a90d7a97d21ffa596747cc8ecd0e3f500cb8a77c Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Thu, 18 Jul 2019 14:49:30 -0400
|
||||
Subject: [PATCH 6/8] appDisplay: Stop watching FolderIcon parent view when
|
||||
destroyed
|
||||
|
||||
When a FolderIcon is opened, it asks the parent view to allocate
|
||||
space for it, which takes time. Eventually, the space-ready
|
||||
signal is emitted on the view and the icon can make use of the new
|
||||
space with its popup. If the icon gets destroyed in the
|
||||
interim, though, space-ready signal handler still fires.
|
||||
|
||||
This commit disconnects the signal handler so it doesn't get called
|
||||
on a destroyed icon.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
|
||||
---
|
||||
js/ui/appDisplay.js | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index 5a8f4f1bf..062ff222c 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -1169,6 +1169,11 @@ var FolderIcon = class FolderIcon {
|
||||
onDestroy() {
|
||||
this.view.actor.destroy();
|
||||
|
||||
+ if (this._spaceReadySignalId) {
|
||||
+ this._parentView.disconnect(this._spaceReadySignalId);
|
||||
+ this._spaceReadySignalId = 0;
|
||||
+ }
|
||||
+
|
||||
if (this._popup)
|
||||
this._popup.actor.destroy();
|
||||
}
|
||||
@@ -1240,8 +1245,9 @@ var FolderIcon = class FolderIcon {
|
||||
}
|
||||
|
||||
_openSpaceForPopup() {
|
||||
- let id = this._parentView.connect('space-ready', () => {
|
||||
- this._parentView.disconnect(id);
|
||||
+ this._spaceReadySignalId = this._parentView.connect('space-ready', () => {
|
||||
+ this._parentView.disconnect(this._spaceReadySignalId);
|
||||
+ this._spaceReadySignalId = 0;
|
||||
this._popup.popup();
|
||||
this._updatePopupPosition();
|
||||
});
|
||||
--
|
||||
2.23.0
|
||||
|
||||
|
||||
From b57ab33dadf0f31c5bf2c800806593e94784050c Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Thu, 18 Jul 2019 10:19:13 -0400
|
||||
Subject: [PATCH 7/8] appDisplay: Add open method to FolderIcon
|
||||
|
||||
At the moment the only way to open a folder icon is to click on it;
|
||||
there's no API to open the icon programmatically.
|
||||
|
||||
This commits adds an open method and makes the click handler use
|
||||
it.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
|
||||
---
|
||||
js/ui/appDisplay.js | 12 +++++++-----
|
||||
1 file changed, 7 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index 062ff222c..c0c6e3663 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -1151,11 +1151,7 @@ var FolderIcon = class FolderIcon {
|
||||
|
||||
this.view = new FolderView();
|
||||
|
||||
- this.actor.connect('clicked', () => {
|
||||
- this._ensurePopup();
|
||||
- this.view.actor.vscroll.adjustment.value = 0;
|
||||
- this._openSpaceForPopup();
|
||||
- });
|
||||
+ this.actor.connect('clicked', this.open.bind(this));
|
||||
this.actor.connect('destroy', this.onDestroy.bind(this));
|
||||
this.actor.connect('notify::mapped', () => {
|
||||
if (!this.actor.mapped && this._popup)
|
||||
@@ -1178,6 +1174,12 @@ var FolderIcon = class FolderIcon {
|
||||
this._popup.actor.destroy();
|
||||
}
|
||||
|
||||
+ open() {
|
||||
+ this._ensurePopup();
|
||||
+ this.view.actor.vscroll.adjustment.value = 0;
|
||||
+ this._openSpaceForPopup();
|
||||
+ }
|
||||
+
|
||||
getAppIds() {
|
||||
return this.view.getAllItems().map(item => item.id);
|
||||
}
|
||||
--
|
||||
2.23.0
|
||||
|
||||
|
||||
From baacab7922a56957d041aa59944c419b82e7a7e1 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Thu, 18 Jul 2019 11:13:27 -0400
|
||||
Subject: [PATCH 8/8] appDisplay: Keep popup open on refresh
|
||||
|
||||
If the list of applications is refreshed we currently close
|
||||
the open app folder.
|
||||
|
||||
This commit adds logic to reopen the app folder on reload.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
|
||||
---
|
||||
js/ui/appDisplay.js | 15 +++++++++++++++
|
||||
1 file changed, 15 insertions(+)
|
||||
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index c0c6e3663..7fad02cd0 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -345,6 +345,21 @@ var AllView = class AllView extends BaseAppView {
|
||||
super.removeAll();
|
||||
}
|
||||
|
||||
+ _redisplay() {
|
||||
+ let openFolderId = null;
|
||||
+ if (this._displayingPopup && this._currentPopup)
|
||||
+ openFolderId = this._currentPopup._source.id;
|
||||
+
|
||||
+ super._redisplay();
|
||||
+
|
||||
+ if (openFolderId) {
|
||||
+ let [folderToReopen] = this.folderIcons.filter(folder => folder.id == openFolderId);
|
||||
+
|
||||
+ if (folderToReopen)
|
||||
+ folderToReopen.open();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
_itemNameChanged(item) {
|
||||
// If an item's name changed, we can pluck it out of where it's
|
||||
// supposed to be and reinsert it where it's sorted.
|
||||
--
|
||||
2.23.0
|
||||
|
@ -0,0 +1,101 @@
|
||||
From 49d066234f9f528122bb40c5144b40d8b19a0071 Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Mon, 22 Aug 2022 12:52:19 +0200
|
||||
Subject: [PATCH] Background: Avoid double dispose and actors recreations
|
||||
|
||||
Subject: [PATCH 1/2] background: Use Garbage Collector to dispose background:
|
||||
|
||||
The same Meta.Background could be used by multiple instances of background
|
||||
actors, and so should not be disposed when the actor using it is destroyed.
|
||||
|
||||
Instead of calling `run_dispose` directly on it, just nullify the reference
|
||||
on destroy method, leaving the job of doing the proper disposition to the
|
||||
gabage collector that keeps the proper reference count on the Meta.Background.
|
||||
|
||||
Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/501
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/558
|
||||
|
||||
Subject: [PATCH 2/2] background: Group 'changed' signal emission
|
||||
|
||||
Background is monitoring the whole `org.gnome.desktop.background` gsettings keys
|
||||
for changes connecting to the non-specialized 'changed' signal and re-emitting
|
||||
this as-is.
|
||||
This means that when the background is changed via control-center, we get
|
||||
multiple 'changed' signal events from GSettings, and for each one of this we
|
||||
recreate a Background and a BackgroundActor.
|
||||
|
||||
Avoid this by using an idle to delay the emission of the 'changed' signal
|
||||
grouping the events.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/558
|
||||
---
|
||||
js/ui/background.js | 26 +++++++++++++++++++++-----
|
||||
1 file changed, 21 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/js/ui/background.js b/js/ui/background.js
|
||||
index 06e0388..2a404ae 100644
|
||||
--- a/js/ui/background.js
|
||||
+++ b/js/ui/background.js
|
||||
@@ -257,14 +257,15 @@ var Background = class Background {
|
||||
this._refreshAnimation();
|
||||
});
|
||||
|
||||
- this._settingsChangedSignalId = this._settings.connect('changed', () => {
|
||||
- this.emit('changed');
|
||||
- });
|
||||
+ this._settingsChangedSignalId =
|
||||
+ this._settings.connect('changed', this._emitChangedSignal.bind(this));
|
||||
|
||||
this._load();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
+ this.background = null;
|
||||
+
|
||||
this._cancellable.cancel();
|
||||
this._removeAnimationTimeout();
|
||||
|
||||
@@ -288,6 +289,22 @@ var Background = class Background {
|
||||
if (this._settingsChangedSignalId != 0)
|
||||
this._settings.disconnect(this._settingsChangedSignalId);
|
||||
this._settingsChangedSignalId = 0;
|
||||
+
|
||||
+ if (this._changedIdleId) {
|
||||
+ GLib.source_remove(this._changedIdleId);
|
||||
+ this._changedIdleId = 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ _emitChangedSignal() {
|
||||
+ if (this._changedIdleId)
|
||||
+ return;
|
||||
+
|
||||
+ this._changedIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||
+ this._changedIdleId = 0;
|
||||
+ this.emit('changed');
|
||||
+ return GLib.SOURCE_REMOVE;
|
||||
+ });
|
||||
}
|
||||
|
||||
updateResolution() {
|
||||
@@ -343,7 +360,7 @@ var Background = class Background {
|
||||
if (changedFile.equal(file)) {
|
||||
let imageCache = Meta.BackgroundImageCache.get_default();
|
||||
imageCache.purge(changedFile);
|
||||
- this.emit('changed');
|
||||
+ this._emitChangedSignal();
|
||||
}
|
||||
});
|
||||
this._fileWatches[key] = signalId;
|
||||
@@ -699,7 +716,6 @@ var BackgroundManager = class BackgroundManager {
|
||||
time: FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete() {
|
||||
- oldBackgroundActor.background.run_dispose();
|
||||
oldBackgroundActor.destroy();
|
||||
}
|
||||
});
|
||||
--
|
||||
2.35.3
|
||||
|
@ -0,0 +1,224 @@
|
||||
From 76eebb42ed4c76970a9debfc0cd41537923eccde Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
|
||||
Date: Tue, 5 Dec 2017 02:41:50 +0100
|
||||
Subject: [PATCH 1/2] tweener: Save handlers on target and remove them on
|
||||
destroy
|
||||
|
||||
Saving handlers we had using the wrapper as a property of the object and delete
|
||||
them when resetting the object state.
|
||||
Without doing this an handler could be called on a destroyed target when this
|
||||
happens on the onComplete callback.
|
||||
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=791233
|
||||
---
|
||||
js/ui/tweener.js | 63 ++++++++++++++++++++++++++++++++++++++----------
|
||||
1 file changed, 50 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/js/ui/tweener.js b/js/ui/tweener.js
|
||||
index bb9ea557c..c04cede25 100644
|
||||
--- a/js/ui/tweener.js
|
||||
+++ b/js/ui/tweener.js
|
||||
@@ -63,30 +63,67 @@ function _getTweenState(target) {
|
||||
return target.__ShellTweenerState;
|
||||
}
|
||||
|
||||
+function _ensureHandlers(target) {
|
||||
+ if (!target.__ShellTweenerHandlers)
|
||||
+ target.__ShellTweenerHandlers = {};
|
||||
+ return target.__ShellTweenerHandlers;
|
||||
+}
|
||||
+
|
||||
function _resetTweenState(target) {
|
||||
let state = target.__ShellTweenerState;
|
||||
|
||||
if (state) {
|
||||
- if (state.destroyedId)
|
||||
+ if (state.destroyedId) {
|
||||
state.actor.disconnect(state.destroyedId);
|
||||
+ delete state.destroyedId;
|
||||
+ }
|
||||
}
|
||||
|
||||
+ _removeHandler(target, 'onComplete', _tweenCompleted);
|
||||
target.__ShellTweenerState = {};
|
||||
}
|
||||
|
||||
function _addHandler(target, params, name, handler) {
|
||||
- if (params[name]) {
|
||||
- let oldHandler = params[name];
|
||||
- let oldScope = params[name + 'Scope'];
|
||||
- let oldParams = params[name + 'Params'];
|
||||
- let eventScope = oldScope ? oldScope : target;
|
||||
-
|
||||
- params[name] = () => {
|
||||
- oldHandler.apply(eventScope, oldParams);
|
||||
- handler(target);
|
||||
- };
|
||||
- } else
|
||||
- params[name] = () => { handler(target); };
|
||||
+ let wrapperNeeded = false;
|
||||
+ let tweenerHandlers = _ensureHandlers(target);
|
||||
+
|
||||
+ if (!(name in tweenerHandlers)) {
|
||||
+ tweenerHandlers[name] = [];
|
||||
+ wrapperNeeded = true;
|
||||
+ }
|
||||
+
|
||||
+ let handlers = tweenerHandlers[name];
|
||||
+ handlers.push(handler);
|
||||
+
|
||||
+ if (wrapperNeeded) {
|
||||
+ if (params[name]) {
|
||||
+ let oldHandler = params[name];
|
||||
+ let oldScope = params[name + 'Scope'];
|
||||
+ let oldParams = params[name + 'Params'];
|
||||
+ let eventScope = oldScope ? oldScope : target;
|
||||
+
|
||||
+ params[name] = () => {
|
||||
+ oldHandler.apply(eventScope, oldParams);
|
||||
+ handlers.forEach((h) => h(target));
|
||||
+ };
|
||||
+ } else {
|
||||
+ params[name] = () => { handlers.forEach((h) => h(target)); };
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+function _removeHandler(target, name, handler) {
|
||||
+ let tweenerHandlers = _ensureHandlers(target);
|
||||
+
|
||||
+ if (name in tweenerHandlers) {
|
||||
+ let handlers = tweenerHandlers[name];
|
||||
+ let handlerIndex = handlers.indexOf(handler);
|
||||
+
|
||||
+ while (handlerIndex > -1) {
|
||||
+ handlers.splice(handlerIndex, 1);
|
||||
+ handlerIndex = handlers.indexOf(handler);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
function _actorDestroyed(target) {
|
||||
--
|
||||
2.21.0
|
||||
|
||||
|
||||
From 730f6f7d708a0cbcfcc75e4a1fba8512ac7c4c82 Mon Sep 17 00:00:00 2001
|
||||
From: Cosimo Cecchi <cosimo@endlessm.com>
|
||||
Date: Sun, 26 May 2019 08:31:07 -0700
|
||||
Subject: [PATCH 2/2] windowAttentionHandler: disconnect signals before
|
||||
destruction
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The 'destroy' signal is emitted at the end of the destroy() method.
|
||||
However the implementation of destroy() can end up emitting one of the
|
||||
signals we connect to on the window, causing us to re-enter destroy
|
||||
from its callback.
|
||||
That will in turn lead to some objects getting disposed twice, which
|
||||
produces a stack trace like the following one.
|
||||
|
||||
This commit fixes the issue by overriding the destroy() method instead
|
||||
of connecting to the signal, which allows us to disconnect the signal
|
||||
handlers from the window at an earlier time and avoid re-entrancy.
|
||||
|
||||
--
|
||||
|
||||
gnome-shell[1082]: Object Gio.Settings (0x7f0af8143f00), has been already deallocated — impossible to access it. This might be caused by the object having been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs.
|
||||
org.gnome.Shell.desktop[1082]: == Stack trace for context 0x5627f7d1e220 ==
|
||||
org.gnome.Shell.desktop[1082]: #0 5627f9e801a8 i resource:///org/gnome/shell/ui/messageTray.js:238 (7f0aefa9eca0 @ 22)
|
||||
org.gnome.Shell.desktop[1082]: #1 5627f9e80108 i resource:///org/gnome/shell/ui/messageTray.js:802 (7f0aefaa2ee0 @ 28)
|
||||
org.gnome.Shell.desktop[1082]: #2 5627f9e80070 i resource:///org/gnome/shell/ui/windowAttentionHandler.js:79 (7f0aef7b29d0 @ 62)
|
||||
org.gnome.Shell.desktop[1082]: #3 7fffa69fbfc0 b self-hosted:979 (7f0aefa515e0 @ 440)
|
||||
org.gnome.Shell.desktop[1082]: #4 5627f9e7ffe0 i resource:///org/gnome/shell/ui/messageTray.js:121 (7f0aefa9e1f0 @ 71)
|
||||
org.gnome.Shell.desktop[1082]: #5 5627f9e7ff38 i resource:///org/gnome/shell/ui/messageTray.js:1408 (7f0aefaa58b0 @ 22)
|
||||
org.gnome.Shell.desktop[1082]: #6 5627f9e7fe80 i resource:///org/gnome/shell/ui/messageTray.js:1237 (7f0aefaa51f0 @ 729)
|
||||
org.gnome.Shell.desktop[1082]: #7 5627f9e7fde8 i resource:///org/gnome/shell/ui/messageTray.js:1055 (7f0aefaa3d30 @ 124)
|
||||
org.gnome.Shell.desktop[1082]: #8 7fffa69ff8e0 b self-hosted:979 (7f0aefa515e0 @ 440)
|
||||
org.gnome.Shell.desktop[1082]: #9 7fffa69ff9d0 b resource:///org/gnome/gjs/modules/signals.js:142 (7f0aefccb670 @ 386)
|
||||
org.gnome.Shell.desktop[1082]: #10 5627f9e7fd58 i resource:///org/gnome/shell/ui/messageTray.js:479 (7f0aefaa0940 @ 50)
|
||||
org.gnome.Shell.desktop[1082]: #11 5627f9e7fcb8 i resource:///org/gnome/shell/ui/messageTray.js:808 (7f0aefaa2ee0 @ 99)
|
||||
org.gnome.Shell.desktop[1082]: #12 5627f9e7fc28 i resource:///org/gnome/shell/ui/windowAttentionHandler.js:69 (7f0aef7b28b0 @ 13)
|
||||
org.gnome.Shell.desktop[1082]: #13 5627f9e7fb80 i resource:///org/gnome/shell/ui/main.js:566 (7f0aefcd8820 @ 216)
|
||||
org.gnome.Shell.desktop[1082]: #14 5627f9e7fad0 i resource:///org/gnome/shell/ui/windowAttentionHandler.js:103 (7f0aef7b2c10 @ 27)
|
||||
org.gnome.Shell.desktop[1082]: #15 5627f9e7fa58 i resource:///org/gnome/shell/ui/windowAttentionHandler.js:43 (7f0aef7b2700 @ 17)
|
||||
org.gnome.Shell.desktop[1082]: #16 7fffa6a03350 b resource:///org/gnome/gjs/modules/signals.js:142 (7f0aefccb670 @ 386)
|
||||
org.gnome.Shell.desktop[1082]: #17 5627f9e7f9d0 i resource:///org/gnome/shell/ui/messageTray.js:471 (7f0aefaa08b0 @ 22)
|
||||
org.gnome.Shell.desktop[1082]: #18 5627f9e7f950 i resource:///org/gnome/shell/ui/calendar.js:752 (7f0aefaabdc0 @ 22)
|
||||
org.gnome.Shell.desktop[1082]: #19 7fffa6a048f0 b self-hosted:979 (7f0aefa515e0 @ 440)
|
||||
org.gnome.Shell.desktop[1082]: == Stack trace for context 0x5627f7d1e220 ==
|
||||
org.gnome.Shell.desktop[1082]: #0 5627f9e801a8 i resource:///org/gnome/shell/ui/messageTray.js:239 (7f0aefa9eca0 @ 42)
|
||||
org.gnome.Shell.desktop[1082]: #1 5627f9e80108 i resource:///org/gnome/shell/ui/messageTray.js:802 (7f0aefaa2ee0 @ 28)
|
||||
org.gnome.Shell.desktop[1082]: #2 5627f9e80070 i resource:///org/gnome/shell/ui/windowAttentionHandler.js:79 (7f0aef7b29d0 @ 62)
|
||||
org.gnome.Shell.desktop[1082]: #3 7fffa69fbfc0 b self-hosted:979 (7f0aefa515e0 @ 440)
|
||||
org.gnome.Shell.desktop[1082]: #4 5627f9e7ffe0 i resource:///org/gnome/shell/ui/messageTray.js:121 (7f0aefa9e1f0 @ 71)
|
||||
org.gnome.Shell.desktop[1082]: #5 5627f9e7ff38 i resource:///org/gnome/shell/ui/messageTray.js:1408 (7f0aefaa58b0 @ 22)
|
||||
org.gnome.Shell.desktop[1082]: #6 5627f9e7fe80 i resource:///org/gnome/shell/ui/messageTray.js:1237 (7f0aefaa51f0 @ 729)
|
||||
org.gnome.Shell.desktop[1082]: #7 5627f9e7fde8 i resource:///org/gnome/shell/ui/messageTray.js:1055 (7f0aefaa3d30 @ 124)
|
||||
org.gnome.Shell.desktop[1082]: #8 7fffa69ff8e0 b self-hosted:979 (7f0aefa515e0 @ 440)
|
||||
org.gnome.Shell.desktop[1082]: #9 7fffa69ff9d0 b resource:///org/gnome/gjs/modules/signals.js:142 (7f0aefccb670 @ 386)
|
||||
org.gnome.Shell.desktop[1082]: #10 5627f9e7fd58 i resource:///org/gnome/shell/ui/messageTray.js:479 (7f0aefaa0940 @ 50)
|
||||
org.gnome.Shell.desktop[1082]: #11 5627f9e7fcb8 i resource:///org/gnome/shell/ui/messageTray.js:808 (7f0aefaa2ee0 @ 99)
|
||||
org.gnome.Shell.desktop[1082]: #12 5627f9e7fc28 i resource:///org/gnome/shell/ui/windowAttentionHandler.js:69 (7f0aef7b28b0 @ 13)
|
||||
org.gnome.Shell.desktop[1082]: #13 5627f9e7fb80 i resource:///org/gnome/shell/ui/main.js:566 (7f0aefcd8820 @ 216)
|
||||
org.gnome.Shell.desktop[1082]: #14 5627f9e7fad0 i resource:///org/gnome/shell/ui/windowAttentionHandler.js:103 (7f0aef7b2c10 @ 27)
|
||||
org.gnome.Shell.desktop[1082]: #15 5627f9e7fa58 i resource:///org/gnome/shell/ui/windowAttentionHandler.js:43 (7f0aef7b2700 @ 17)
|
||||
org.gnome.Shell.desktop[1082]: #16 7fffa6a03350 b resource:///org/gnome/gjs/modules/signals.js:142 (7f0aefccb670 @ 386)
|
||||
org.gnome.Shell.desktop[1082]: #17 5627f9e7f9d0 i resource:///org/gnome/shell/ui/messageTray.js:471 (7f0aefaa08b0 @ 22)
|
||||
org.gnome.Shell.desktop[1082]: #18 5627f9e7f950 i resource:///org/gnome/shell/ui/calendar.js:752 (7f0aefaabdc0 @ 22)
|
||||
org.gnome.Shell.desktop[1082]: #19 7fffa6a048f0 b self-hosted:979 (7f0aefa515e0 @ 440)
|
||||
gnome-shell[1082]: g_object_run_dispose: assertion 'G_IS_OBJECT (object)' failed
|
||||
gnome-shell[1082]: Object Gio.Settings (0x7f0af8161750), has been already deallocated — impossible to access it. This might be caused by the object having been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs.
|
||||
gnome-shell[1082]: g_object_run_dispose: assertion 'G_IS_OBJECT (object)' failed
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/555
|
||||
---
|
||||
js/ui/windowAttentionHandler.js | 17 ++++++++---------
|
||||
1 file changed, 8 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/js/ui/windowAttentionHandler.js b/js/ui/windowAttentionHandler.js
|
||||
index abdb8a444..a9a7111ba 100644
|
||||
--- a/js/ui/windowAttentionHandler.js
|
||||
+++ b/js/ui/windowAttentionHandler.js
|
||||
@@ -69,8 +69,6 @@ var Source = class WindowAttentionSource extends MessageTray.Source {
|
||||
() => { this.destroy(); }));
|
||||
this.signalIDs.push(this._window.connect('unmanaged',
|
||||
() => { this.destroy(); }));
|
||||
-
|
||||
- this.connect('destroy', this._onDestroy.bind(this));
|
||||
}
|
||||
|
||||
_sync() {
|
||||
@@ -79,13 +77,6 @@ var Source = class WindowAttentionSource extends MessageTray.Source {
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
- _onDestroy() {
|
||||
- for(let i = 0; i < this.signalIDs.length; i++) {
|
||||
- this._window.disconnect(this.signalIDs[i]);
|
||||
- }
|
||||
- this.signalIDs = [];
|
||||
- }
|
||||
-
|
||||
_createPolicy() {
|
||||
if (this._app && this._app.get_app_info()) {
|
||||
let id = this._app.get_id().replace(/\.desktop$/,'');
|
||||
@@ -99,6 +90,14 @@ var Source = class WindowAttentionSource extends MessageTray.Source {
|
||||
return this._app.create_icon_texture(size);
|
||||
}
|
||||
|
||||
+ destroy(params) {
|
||||
+ for (let i = 0; i < this.signalIDs.length; i++)
|
||||
+ this._window.disconnect(this.signalIDs[i]);
|
||||
+ this.signalIDs = [];
|
||||
+
|
||||
+ super.destroy(params);
|
||||
+ }
|
||||
+
|
||||
open() {
|
||||
Main.activateWindow(this._window);
|
||||
}
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,161 @@
|
||||
From 214c4f390faa40199c03a80594313760ffe9c5a6 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 20 Sep 2019 13:17:40 +0200
|
||||
Subject: [PATCH 1/2] unlockDialog: Use inheritance instead of composition
|
||||
|
||||
The screen shield creates the unlock dialog based on the session mode.
|
||||
|
||||
However since commit 0c0d76f7d6990 turned LoginDialog into an actor
|
||||
subclass (while UnlockDialog kept using the delegate pattern), it is
|
||||
no longer possible to handle both objects the same way without warnings.
|
||||
|
||||
Allow this again by turning UnlockDialog into an actor subclass as well.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/736
|
||||
---
|
||||
js/ui/unlockDialog.js | 46 ++++++++++++++++++++++++-------------------
|
||||
1 file changed, 26 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js
|
||||
index 4b0470f4b..55abb652d 100644
|
||||
--- a/js/ui/unlockDialog.js
|
||||
+++ b/js/ui/unlockDialog.js
|
||||
@@ -1,8 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const { AccountsService, Atk, Clutter,
|
||||
- Gdm, Gio, GLib, Meta, Shell, St } = imports.gi;
|
||||
-const Signals = imports.signals;
|
||||
+ Gdm, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
|
||||
const Layout = imports.ui.layout;
|
||||
const Main = imports.ui.main;
|
||||
@@ -12,15 +11,19 @@ const AuthPrompt = imports.gdm.authPrompt;
|
||||
// The timeout before going back automatically to the lock screen (in seconds)
|
||||
const IDLE_TIMEOUT = 2 * 60;
|
||||
|
||||
-var UnlockDialog = class {
|
||||
- constructor(parentActor) {
|
||||
- this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW,
|
||||
- style_class: 'login-dialog',
|
||||
- layout_manager: new Clutter.BoxLayout(),
|
||||
- visible: false });
|
||||
+var UnlockDialog = GObject.registerClass({
|
||||
+ Signals: { 'failed': {} },
|
||||
+}, class UnlockDialog extends St.Widget {
|
||||
+ _init(parentActor) {
|
||||
+ super._init({
|
||||
+ accessible_role: Atk.Role.WINDOW,
|
||||
+ style_class: 'login-dialog',
|
||||
+ layout_manager: new Clutter.BoxLayout(),
|
||||
+ visible: false,
|
||||
+ });
|
||||
|
||||
- this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
||||
- parentActor.add_child(this.actor);
|
||||
+ this.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
||||
+ parentActor.add_child(this);
|
||||
|
||||
this._userManager = AccountsService.UserManager.get_default();
|
||||
this._userName = GLib.get_user_name();
|
||||
@@ -31,7 +34,7 @@ var UnlockDialog = class {
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
x_expand: true,
|
||||
y_expand: true });
|
||||
- this.actor.add_child(this._promptBox);
|
||||
+ this.add_child(this._promptBox);
|
||||
|
||||
this._gdmClient = new Gdm.Client();
|
||||
|
||||
@@ -70,10 +73,12 @@ var UnlockDialog = class {
|
||||
this._authPrompt.reset();
|
||||
this._updateSensitivity(true);
|
||||
|
||||
- Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic');
|
||||
+ Main.ctrlAltTabManager.addGroup(this, _("Unlock Window"), 'dialog-password-symbolic');
|
||||
|
||||
this._idleMonitor = Meta.IdleMonitor.get_core();
|
||||
this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, this._escape.bind(this));
|
||||
+
|
||||
+ this.connect('destroy', this._onDestroy.bind(this));
|
||||
}
|
||||
|
||||
_updateSensitivity(sensitive) {
|
||||
@@ -112,9 +117,8 @@ var UnlockDialog = class {
|
||||
this._authPrompt.cancel();
|
||||
}
|
||||
|
||||
- destroy() {
|
||||
+ _onDestroy() {
|
||||
this.popModal();
|
||||
- this.actor.destroy();
|
||||
|
||||
if (this._idleWatchId) {
|
||||
this._idleMonitor.remove_watch(this._idleWatchId);
|
||||
@@ -137,13 +141,16 @@ var UnlockDialog = class {
|
||||
}
|
||||
|
||||
open(timestamp) {
|
||||
- this.actor.show();
|
||||
+ this.show();
|
||||
|
||||
if (this._isModal)
|
||||
return true;
|
||||
|
||||
- if (!Main.pushModal(this.actor, { timestamp: timestamp,
|
||||
- actionMode: Shell.ActionMode.UNLOCK_SCREEN }))
|
||||
+ let modalParams = {
|
||||
+ timestamp,
|
||||
+ actionMode: Shell.ActionMode.UNLOCK_SCREEN,
|
||||
+ };
|
||||
+ if (!Main.pushModal(this, modalParams))
|
||||
return false;
|
||||
|
||||
this._isModal = true;
|
||||
@@ -153,9 +160,8 @@ var UnlockDialog = class {
|
||||
|
||||
popModal(timestamp) {
|
||||
if (this._isModal) {
|
||||
- Main.popModal(this.actor, timestamp);
|
||||
+ Main.popModal(this, timestamp);
|
||||
this._isModal = false;
|
||||
}
|
||||
}
|
||||
-};
|
||||
-Signals.addSignalMethods(UnlockDialog.prototype);
|
||||
+});
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
||||
From cddeb2f4e38928e0d5e0f3a852961f639536aff3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 20 Sep 2019 13:14:40 +0200
|
||||
Subject: [PATCH 2/2] screenShield: Stop using deprecated actor property
|
||||
|
||||
Both LoginDialog and UnlockDialog are now actor subclasses, so stop
|
||||
using the deprecated actor delegate that will trigger a warning.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/736
|
||||
---
|
||||
js/ui/screenShield.js | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
|
||||
index 2d0a429be..f97a9288a 100644
|
||||
--- a/js/ui/screenShield.js
|
||||
+++ b/js/ui/screenShield.js
|
||||
@@ -917,8 +917,8 @@ var ScreenShield = class {
|
||||
this._lockScreenGroup.hide();
|
||||
|
||||
if (this._dialog) {
|
||||
- this._dialog.actor.grab_key_focus();
|
||||
- this._dialog.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
|
||||
+ this._dialog.grab_key_focus();
|
||||
+ this._dialog.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,131 @@
|
||||
From e2a1b737156804e2647e5de938c3d170c11b6ba4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 31 Jul 2020 20:40:36 +0200
|
||||
Subject: [PATCH 1/2] status/network: Use D-Bus to launch Settings panels
|
||||
|
||||
For more obscure network configurations, we need to launch the
|
||||
corresponding Settings panel with additional parameters, so we
|
||||
cannot simply launch the .desktop file.
|
||||
|
||||
However we can do better than spawning a command line: Control center
|
||||
exposes an application action we can use instead, so the process is
|
||||
launched with the appropriate activation environment and startup
|
||||
notification support.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1385
|
||||
---
|
||||
js/ui/status/network.js | 33 +++++++++++++++++++++++++++++----
|
||||
1 file changed, 29 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
|
||||
index f8991d02f..0e7e82ce0 100644
|
||||
--- a/js/ui/status/network.js
|
||||
+++ b/js/ui/status/network.js
|
||||
@@ -15,6 +15,8 @@ const Util = imports.misc.util;
|
||||
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
+Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
|
||||
+
|
||||
const NMConnectionCategory = {
|
||||
INVALID: 'invalid',
|
||||
WIRED: 'wired',
|
||||
@@ -75,6 +77,30 @@ function ensureActiveConnectionProps(active, client) {
|
||||
}
|
||||
}
|
||||
|
||||
+function launchSettingsPanel(panel, ...args) {
|
||||
+ const param = new GLib.Variant('(sav)',
|
||||
+ [panel, args.map(s => new GLib.Variant('s', s))]);
|
||||
+ const platformData = {
|
||||
+ 'desktop-startup-id': new GLib.Variant('s',
|
||||
+ '_TIME%s'.format(global.get_current_time())),
|
||||
+ };
|
||||
+ try {
|
||||
+ Gio.DBus.session.call(
|
||||
+ 'org.gnome.ControlCenter',
|
||||
+ '/org/gnome/ControlCenter',
|
||||
+ 'org.freedesktop.Application',
|
||||
+ 'ActivateAction',
|
||||
+ new GLib.Variant('(sava{sv})',
|
||||
+ ['launch-panel', [param], platformData]),
|
||||
+ null,
|
||||
+ Gio.DBusCallFlags.NONE,
|
||||
+ -1,
|
||||
+ null);
|
||||
+ } catch (e) {
|
||||
+ log('Failed to launch Settings panel: %s'.format(e.message));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
var NMConnectionItem = class {
|
||||
constructor(section, connection) {
|
||||
this._section = section;
|
||||
@@ -534,8 +560,7 @@ var NMDeviceModem = class extends NMConnectionDevice {
|
||||
}
|
||||
|
||||
_autoConnect() {
|
||||
- Util.spawn(['gnome-control-center', 'network',
|
||||
- 'connect-3g', this._device.get_path()]);
|
||||
+ launchSettingsPanel('network', 'connect-3g', this._device.get_path());
|
||||
}
|
||||
|
||||
_sessionUpdated() {
|
||||
@@ -920,8 +945,8 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog {
|
||||
|| (accessPoints[0]._secType == NMAccessPointSecurity.WPA_ENT)) {
|
||||
// 802.1x-enabled APs require further configuration, so they're
|
||||
// handled in gnome-control-center
|
||||
- Util.spawn(['gnome-control-center', 'wifi', 'connect-8021x-wifi',
|
||||
- this._device.get_path(), accessPoints[0].get_path()]);
|
||||
+ launchSettingsPanel('wifi', 'connect-8021x-wifi',
|
||||
+ this._device.get_path(), accessPoints[0].get_path());
|
||||
} else {
|
||||
let connection = new NM.SimpleConnection();
|
||||
this._client.add_and_activate_connection_async(connection, this._device, accessPoints[0].get_path(), null, null)
|
||||
--
|
||||
2.38.1
|
||||
|
||||
|
||||
From 9ca1989fcc73157685742470c25f538d01d8df44 Mon Sep 17 00:00:00 2001
|
||||
From: Xiaoguang Wang <xwang@suse.com>
|
||||
Date: Mon, 21 Feb 2022 09:11:23 +0800
|
||||
Subject: [PATCH 2/2] network: Get dbus path from NMDevice
|
||||
|
||||
In the NetworkManager new version the NMDevice.get_path returns pci
|
||||
path, we need to use NM prototype to get device dbus path.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4565
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2194>
|
||||
---
|
||||
js/ui/status/network.js | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
|
||||
index 0e7e82ce0..9d6a83b73 100644
|
||||
--- a/js/ui/status/network.js
|
||||
+++ b/js/ui/status/network.js
|
||||
@@ -946,7 +946,7 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog {
|
||||
// 802.1x-enabled APs require further configuration, so they're
|
||||
// handled in gnome-control-center
|
||||
launchSettingsPanel('wifi', 'connect-8021x-wifi',
|
||||
- this._device.get_path(), accessPoints[0].get_path());
|
||||
+ this._getDeviceDBusPath(), accessPoints[0].get_path());
|
||||
} else {
|
||||
let connection = new NM.SimpleConnection();
|
||||
this._client.add_and_activate_connection_async(connection, this._device, accessPoints[0].get_path(), null, null)
|
||||
@@ -956,6 +956,11 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog {
|
||||
this.close();
|
||||
}
|
||||
|
||||
+ _getDeviceDBusPath() {
|
||||
+ // nm_object_get_path() is shadowed by nm_device_get_path()
|
||||
+ return NM.Object.prototype.get_path.call(this._device);
|
||||
+ }
|
||||
+
|
||||
_notifySsidCb(accessPoint) {
|
||||
if (accessPoint.get_ssid() != null) {
|
||||
accessPoint.disconnect(accessPoint._notifySsidId);
|
||||
--
|
||||
2.38.1
|
||||
|
@ -0,0 +1,223 @@
|
||||
From 530964cc6e5db02633434853debd96069dc2b8d8 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
|
||||
Date: Thu, 23 May 2019 06:12:56 +0200
|
||||
Subject: [PATCH 1/6] realmd: Set login format to null on start and update if
|
||||
invalid
|
||||
|
||||
We were checking an undefined property but that would lead to a a warning.
|
||||
Instead we can consider the login format unset until is null, and in case
|
||||
update it.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/700
|
||||
---
|
||||
js/gdm/realmd.js | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/gdm/realmd.js b/js/gdm/realmd.js
|
||||
index 50f3c5899..04cd99787 100644
|
||||
--- a/js/gdm/realmd.js
|
||||
+++ b/js/gdm/realmd.js
|
||||
@@ -21,6 +21,7 @@ var Manager = class {
|
||||
'/org/freedesktop/realmd',
|
||||
this._reloadRealms.bind(this))
|
||||
this._realms = {};
|
||||
+ this._loginFormat = null;
|
||||
|
||||
this._signalId = this._aggregateProvider.connect('g-properties-changed',
|
||||
(proxy, properties) => {
|
||||
@@ -86,7 +87,7 @@ var Manager = class {
|
||||
}
|
||||
|
||||
get loginFormat() {
|
||||
- if (this._loginFormat !== undefined)
|
||||
+ if (this._loginFormat)
|
||||
return this._loginFormat;
|
||||
|
||||
this._updateLoginFormat();
|
||||
--
|
||||
2.33.1
|
||||
|
||||
|
||||
From 988e4b58d64fbf87f0c497315ff2506b269ff7c9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Tue, 9 Jun 2020 19:42:21 +0200
|
||||
Subject: [PATCH 2/6] popupMenu: Guard against non-menu-item children
|
||||
|
||||
This avoid a harmless but annoying warning.
|
||||
---
|
||||
js/ui/popupMenu.js | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
|
||||
index 44818533a..b5115d7f7 100644
|
||||
--- a/js/ui/popupMenu.js
|
||||
+++ b/js/ui/popupMenu.js
|
||||
@@ -696,7 +696,8 @@ var PopupMenuBase = class {
|
||||
}
|
||||
|
||||
_getMenuItems() {
|
||||
- return this.box.get_children().map(a => a._delegate).filter(item => {
|
||||
+ const children = this.box.get_children().filter(a => a._delegate !== undefined);
|
||||
+ return children.map(a => a._delegate).filter(item => {
|
||||
return item instanceof PopupBaseMenuItem || item instanceof PopupMenuSection;
|
||||
});
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
||||
|
||||
From 609a8e22e67b63da1e35167d8511400f22641368 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Tue, 9 Jun 2020 19:48:06 +0200
|
||||
Subject: [PATCH 3/6] st/shadow: Check pipeline when painting
|
||||
|
||||
We shouldn't simply assume that st_shadow_helper_update() has been
|
||||
called before paint() or that the pipeline was created successfully.
|
||||
---
|
||||
src/st/st-shadow.c | 11 ++++++-----
|
||||
1 file changed, 6 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/st/st-shadow.c b/src/st/st-shadow.c
|
||||
index f3a22f034..7665de755 100644
|
||||
--- a/src/st/st-shadow.c
|
||||
+++ b/src/st/st-shadow.c
|
||||
@@ -289,9 +289,10 @@ st_shadow_helper_paint (StShadowHelper *helper,
|
||||
ClutterActorBox *actor_box,
|
||||
guint8 paint_opacity)
|
||||
{
|
||||
- _st_paint_shadow_with_opacity (helper->shadow,
|
||||
- framebuffer,
|
||||
- helper->pipeline,
|
||||
- actor_box,
|
||||
- paint_opacity);
|
||||
+ if (helper->pipeline != NULL)
|
||||
+ _st_paint_shadow_with_opacity (helper->shadow,
|
||||
+ framebuffer,
|
||||
+ helper->pipeline,
|
||||
+ actor_box,
|
||||
+ paint_opacity);
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
||||
|
||||
From b57d6efccbeb139d6c7c1894f83caa7a26fd6bad Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Tue, 5 Jan 2021 21:42:24 +0100
|
||||
Subject: [PATCH 4/6] viewSelector: Don't set page parent during construction
|
||||
|
||||
gjs now aggressively garbage-collects objects that fall out of scope,
|
||||
sometimes too aggressively:
|
||||
|
||||
- we pass a child as construct property to StBin
|
||||
- as a result, the child's ::parent-set handler runs
|
||||
- when calling clutter_actor_get_parent() from that
|
||||
handler, the returned object is garbage-collected
|
||||
*before* the constructor returns (and thus the
|
||||
assignment that would keep it alive)
|
||||
|
||||
This is a bug on the gjs side that should be fixed, but we can easily
|
||||
work around the issue by setting the child after constructing the
|
||||
parent.
|
||||
---
|
||||
js/ui/viewSelector.js | 12 +++++++-----
|
||||
1 file changed, 7 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/js/ui/viewSelector.js b/js/ui/viewSelector.js
|
||||
index 77146552d..6529ac9a5 100644
|
||||
--- a/js/ui/viewSelector.js
|
||||
+++ b/js/ui/viewSelector.js
|
||||
@@ -301,11 +301,13 @@ var ViewSelector = class {
|
||||
_addPage(actor, name, a11yIcon, params) {
|
||||
params = Params.parse(params, { a11yFocus: null });
|
||||
|
||||
- let page = new St.Bin({ child: actor,
|
||||
- x_align: St.Align.START,
|
||||
- y_align: St.Align.START,
|
||||
- x_fill: true,
|
||||
- y_fill: true });
|
||||
+ let page = new St.Bin({
|
||||
+ x_align: St.Align.START,
|
||||
+ y_align: St.Align.START,
|
||||
+ x_fill: true,
|
||||
+ y_fill: true,
|
||||
+ });
|
||||
+ page.set_child(actor);
|
||||
if (params.a11yFocus)
|
||||
Main.ctrlAltTabManager.addGroup(params.a11yFocus, name, a11yIcon);
|
||||
else
|
||||
--
|
||||
2.33.1
|
||||
|
||||
|
||||
From 0c76c91c3d16c8386a242daf367d66057364a5d1 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 23 Oct 2020 23:44:48 +0200
|
||||
Subject: [PATCH 5/6] workspacesView: Don't set up MetaLater when unparented
|
||||
|
||||
We already do the check in the later handler, but if we got
|
||||
unparented because the actor is destroyed, then the call to
|
||||
get_parent() itself will trigger a (harmless but annoying)
|
||||
warning.
|
||||
---
|
||||
js/ui/workspacesView.js | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
|
||||
index e302296a6..3270900b2 100644
|
||||
--- a/js/ui/workspacesView.js
|
||||
+++ b/js/ui/workspacesView.js
|
||||
@@ -715,6 +715,9 @@ var WorkspacesDisplay = class {
|
||||
oldParent.disconnect(this._notifyOpacityId);
|
||||
this._notifyOpacityId = 0;
|
||||
|
||||
+ if (!this.actor.get_parent())
|
||||
+ return;
|
||||
+
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
|
||||
let newParent = this.actor.get_parent();
|
||||
if (!newParent)
|
||||
--
|
||||
2.33.1
|
||||
|
||||
|
||||
From 4ba01f2fdada7e4b059a0f57a99dc3ff2ddfa8f8 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 26 Nov 2021 17:28:54 +0100
|
||||
Subject: [PATCH 6/6] workspacesView: Remove later on destroy
|
||||
|
||||
We are careful not to schedule the later when the actor is destroyed,
|
||||
however it is possible that one is still pending at that point (namely
|
||||
if the actor was never shown).
|
||||
---
|
||||
js/ui/workspacesView.js | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
|
||||
index 3270900b2..9dc05fca7 100644
|
||||
--- a/js/ui/workspacesView.js
|
||||
+++ b/js/ui/workspacesView.js
|
||||
@@ -449,6 +449,11 @@ var WorkspacesDisplay = class {
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('notify::allocation', this._updateWorkspacesActualGeometry.bind(this));
|
||||
this.actor.connect('parent-set', this._parentSet.bind(this));
|
||||
+ this.actor.connect('destroy', () => {
|
||||
+ if (this._laterId)
|
||||
+ Meta.later_remove(this._laterId);
|
||||
+ this._laterId = 0;
|
||||
+ });
|
||||
|
||||
let clickAction = new Clutter.ClickAction();
|
||||
clickAction.connect('clicked', action => {
|
||||
@@ -718,7 +723,7 @@ var WorkspacesDisplay = class {
|
||||
if (!this.actor.get_parent())
|
||||
return;
|
||||
|
||||
- Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
|
||||
+ this._laterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
|
||||
let newParent = this.actor.get_parent();
|
||||
if (!newParent)
|
||||
return;
|
||||
--
|
||||
2.33.1
|
||||
|
@ -0,0 +1,246 @@
|
||||
From ed0699886f49e5dd8d6ca9ffb60ba17cd76a810f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Mon, 7 Jun 2021 17:49:57 +0200
|
||||
Subject: [PATCH 1/5] status/network: Disable modem connection when windows
|
||||
aren't allowed
|
||||
|
||||
The item launches the corresponding Settings panel when activated, which
|
||||
doesn't work when windows are disabled by the session mode. Rather than
|
||||
failing silently, turn the item insensitive.
|
||||
---
|
||||
js/ui/status/network.js | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
|
||||
index b3bb7589c..3ad7b04dd 100644
|
||||
--- a/js/ui/status/network.js
|
||||
+++ b/js/ui/status/network.js
|
||||
@@ -514,6 +514,10 @@ var NMDeviceModem = class extends NMConnectionDevice {
|
||||
this._iconChanged();
|
||||
});
|
||||
}
|
||||
+
|
||||
+ this._sessionUpdatedId =
|
||||
+ Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
|
||||
+ this._sessionUpdated();
|
||||
}
|
||||
|
||||
get category() {
|
||||
@@ -525,6 +529,10 @@ var NMDeviceModem = class extends NMConnectionDevice {
|
||||
'connect-3g', this._device.get_path()]);
|
||||
}
|
||||
|
||||
+ _sessionUpdated() {
|
||||
+ this._autoConnectItem.sensitive = Main.sessionMode.hasWindows;
|
||||
+ }
|
||||
+
|
||||
destroy() {
|
||||
if (this._operatorNameId) {
|
||||
this._mobileDevice.disconnect(this._operatorNameId);
|
||||
@@ -534,6 +542,10 @@ var NMDeviceModem = class extends NMConnectionDevice {
|
||||
this._mobileDevice.disconnect(this._signalQualityId);
|
||||
this._signalQualityId = 0;
|
||||
}
|
||||
+ if (this._sessionUpdatedId) {
|
||||
+ Main.sessionMode.disconnect(this._sessionUpdatedId);
|
||||
+ this._sessionUpdatedId = 0;
|
||||
+ }
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
||||
From 59d52e1591e1522fff22320c657496ca978a7926 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Mon, 7 Jun 2021 18:28:32 +0200
|
||||
Subject: [PATCH 2/5] status/network: Only list wifi networks that can be
|
||||
activated
|
||||
|
||||
Setting up a connection for an Enterprise WPA(2) encrypted wireless
|
||||
network requires Settings. That's not available when windows are
|
||||
disabled via the session mode, so filter out affected entries.
|
||||
---
|
||||
js/ui/status/network.js | 29 ++++++++++++++++++++++++++++-
|
||||
1 file changed, 28 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
|
||||
index 3ad7b04dd..c023022a7 100644
|
||||
--- a/js/ui/status/network.js
|
||||
+++ b/js/ui/status/network.js
|
||||
@@ -1,5 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
-const { Clutter, Gio, GLib, GObject, NM, St } = imports.gi;
|
||||
+const { Clutter, Gio, GLib, GObject, Meta, NM, St } = imports.gi;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
|
||||
@@ -751,6 +751,11 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog {
|
||||
this._scanTimeoutId = 0;
|
||||
}
|
||||
|
||||
+ if (this._syncVisibilityId) {
|
||||
+ Meta.later_remove(this._syncVisibilityId);
|
||||
+ this._syncVisibilityId = 0;
|
||||
+ }
|
||||
+
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
@@ -1081,9 +1086,31 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog {
|
||||
this._itemBox.insert_child_at_index(network.item.actor, newPos);
|
||||
}
|
||||
|
||||
+ this._queueSyncItemVisibility();
|
||||
this._syncView();
|
||||
}
|
||||
|
||||
+ _queueSyncItemVisibility() {
|
||||
+ if (this._syncVisibilityId)
|
||||
+ return;
|
||||
+
|
||||
+ this._syncVisibilityId = Meta.later_add(
|
||||
+ Meta.LaterType.BEFORE_REDRAW,
|
||||
+ () => {
|
||||
+ const { hasWindows } = Main.sessionMode;
|
||||
+ const { WPA2_ENT, WPA_ENT } = NMAccessPointSecurity;
|
||||
+
|
||||
+ for (const network of this._networks) {
|
||||
+ const [firstAp] = network.accessPoints;
|
||||
+ network.item.visible =
|
||||
+ hasWindows ||
|
||||
+ network.connections.length > 0 ||
|
||||
+ (firstAp._secType !== WPA2_ENT && firstAp._secType !== WPA_ENT);
|
||||
+ }
|
||||
+ return GLib.SOURCE_REMOVE;
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
_accessPointRemoved(device, accessPoint) {
|
||||
let res = this._findExistingNetwork(accessPoint);
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
||||
From 9d204cdb38bcfee214dbe0b0bf9c2073dc50fe93 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Tue, 8 Jun 2021 00:17:48 +0200
|
||||
Subject: [PATCH 3/5] status/network: Consider network-control action
|
||||
|
||||
NetworkManager installs a `network-control` polkit action that can
|
||||
be used to disallow network configuration, except that we happily
|
||||
ignore it. Add it to the conditions that turn a network section
|
||||
insensitive.
|
||||
---
|
||||
js/ui/status/network.js | 20 +++++++++++++++++---
|
||||
1 file changed, 17 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
|
||||
index c023022a7..79729e01b 100644
|
||||
--- a/js/ui/status/network.js
|
||||
+++ b/js/ui/status/network.js
|
||||
@@ -1,5 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
-const { Clutter, Gio, GLib, GObject, Meta, NM, St } = imports.gi;
|
||||
+const { Clutter, Gio, GLib, GObject, Meta, NM, Polkit, St } = imports.gi;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
|
||||
@@ -1683,11 +1683,25 @@ var NMApplet = class extends PanelMenu.SystemIndicator {
|
||||
this._client.connect('connection-removed', this._connectionRemoved.bind(this));
|
||||
|
||||
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
|
||||
- this._sessionUpdated();
|
||||
+
|
||||
+ this._configPermission = null;
|
||||
+ Polkit.Permission.new(
|
||||
+ 'org.freedesktop.NetworkManager.network-control', null, null,
|
||||
+ (o, res) => {
|
||||
+ try {
|
||||
+ this._configPermission = Polkit.Permission.new_finish(res);
|
||||
+ } catch (e) {
|
||||
+ log('No permission to control network connections: %s'.format(e.toString()));
|
||||
+ }
|
||||
+ this._sessionUpdated();
|
||||
+ });
|
||||
}
|
||||
|
||||
_sessionUpdated() {
|
||||
- let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
|
||||
+ const sensitive =
|
||||
+ !Main.sessionMode.isLocked &&
|
||||
+ !Main.sessionMode.isGreeter &&
|
||||
+ this._configPermission && this._configPermission.allowed;
|
||||
this.menu.setSensitive(sensitive);
|
||||
}
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
||||
From 7d2c8aabb86b9942c99ae9b7157dbffb875acde9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 10 Jun 2021 23:12:27 +0200
|
||||
Subject: [PATCH 4/5] sessionMode: Enable networkAgent on login screen
|
||||
|
||||
We will soon enable the network sections in the status menu on the
|
||||
login screen, so enable the network agent to handle authentication
|
||||
requests (like wifi/VPN passwords).
|
||||
---
|
||||
js/ui/sessionMode.js | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js
|
||||
index 25aa75a3d..fa7f83416 100644
|
||||
--- a/js/ui/sessionMode.js
|
||||
+++ b/js/ui/sessionMode.js
|
||||
@@ -43,7 +43,9 @@ const _modes = {
|
||||
isGreeter: true,
|
||||
isPrimary: true,
|
||||
unlockDialog: imports.gdm.loginDialog.LoginDialog,
|
||||
- components: ['polkitAgent'],
|
||||
+ components: Config.HAVE_NETWORKMANAGER
|
||||
+ ? ['networkAgent', 'polkitAgent']
|
||||
+ : ['polkitAgent'],
|
||||
panel: {
|
||||
left: [],
|
||||
center: ['dateMenu'],
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
||||
From 07ce899bcb9d30991262d6c484508e6c5fa14c85 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Tue, 8 Jun 2021 00:19:26 +0200
|
||||
Subject: [PATCH 5/5] status/network: Do not disable on login screen
|
||||
|
||||
We currently disable all network items on both the lock- and login
|
||||
screen. While it makes sense to be very restrictive on the lock screen,
|
||||
there are some (fringe) use cases for being more permissive on the
|
||||
login screen (like remote home directories only accessible via VPN).
|
||||
|
||||
There's precedence with the power-off/restart actions to be less
|
||||
restrictive on the login screen, and since we started respecting
|
||||
the `network-control` polkit action, it's possible to restore the
|
||||
old behavior if desired.
|
||||
---
|
||||
js/ui/status/network.js | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
|
||||
index 79729e01b..914dbbd99 100644
|
||||
--- a/js/ui/status/network.js
|
||||
+++ b/js/ui/status/network.js
|
||||
@@ -1700,7 +1700,6 @@ var NMApplet = class extends PanelMenu.SystemIndicator {
|
||||
_sessionUpdated() {
|
||||
const sensitive =
|
||||
!Main.sessionMode.isLocked &&
|
||||
- !Main.sessionMode.isGreeter &&
|
||||
this._configPermission && this._configPermission.allowed;
|
||||
this.menu.setSensitive(sensitive);
|
||||
}
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,38 @@
|
||||
From 87104647f061892525236a71f304b63609960626 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 9 Mar 2017 14:43:30 +0100
|
||||
Subject: [PATCH] appFavorites: Make firefox the default browser
|
||||
|
||||
---
|
||||
data/org.gnome.shell.gschema.xml.in | 2 +-
|
||||
js/ui/appFavorites.js | 1 +
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
|
||||
index 24e2a75b0..2f50036d0 100644
|
||||
--- a/data/org.gnome.shell.gschema.xml.in
|
||||
+++ b/data/org.gnome.shell.gschema.xml.in
|
||||
@@ -39,7 +39,7 @@
|
||||
</description>
|
||||
</key>
|
||||
<key name="favorite-apps" type="as">
|
||||
- <default>[ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
|
||||
+ <default>[ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
|
||||
<summary>List of desktop file IDs for favorite applications</summary>
|
||||
<description>
|
||||
The applications corresponding to these identifiers
|
||||
diff --git a/js/ui/appFavorites.js b/js/ui/appFavorites.js
|
||||
index 657e15965..1e44a1655 100644
|
||||
--- a/js/ui/appFavorites.js
|
||||
+++ b/js/ui/appFavorites.js
|
||||
@@ -49,6 +49,7 @@ const RENAMED_DESKTOP_IDS = {
|
||||
'gnotski.desktop': 'org.gnome.Klotski.desktop',
|
||||
'gtali.desktop': 'org.gnome.Tali.desktop',
|
||||
'iagno.desktop': 'org.gnome.Reversi.desktop',
|
||||
+ 'mozilla-firefox.desktop': 'firefox.desktop',
|
||||
'nautilus.desktop': 'org.gnome.Nautilus.desktop',
|
||||
'org.gnome.gnome-2048.desktop': 'org.gnome.TwentyFortyEight.desktop',
|
||||
'org.gnome.taquin.desktop': 'org.gnome.Taquin.desktop',
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,25 @@
|
||||
From d15a92aeaa075230f711921f4bcd929c49bfc97d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 9 Mar 2017 14:44:32 +0100
|
||||
Subject: [PATCH] appFavorites: Add terminal
|
||||
|
||||
---
|
||||
data/org.gnome.shell.gschema.xml.in | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
|
||||
index 40526187e..9d7e011fc 100644
|
||||
--- a/data/org.gnome.shell.gschema.xml.in
|
||||
+++ b/data/org.gnome.shell.gschema.xml.in
|
||||
@@ -39,7 +39,7 @@
|
||||
</description>
|
||||
</key>
|
||||
<key name="favorite-apps" type="as">
|
||||
- <default>[ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop' ]</default>
|
||||
+ <default>[ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop', 'gnome-terminal.desktop' ]</default>
|
||||
<summary>List of desktop file IDs for favorite applications</summary>
|
||||
<description>
|
||||
The applications corresponding to these identifiers
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,26 @@
|
||||
From 53eba56c29c2c3f25bdfc4b73d1b9ce74ce2504b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 9 Mar 2017 14:44:03 +0100
|
||||
Subject: [PATCH] Add 'yelp' to default favorites
|
||||
|
||||
Help should be easily available, so add it to the default favorites.
|
||||
---
|
||||
data/org.gnome.shell.gschema.xml.in | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
|
||||
index 2f50036d0..40526187e 100644
|
||||
--- a/data/org.gnome.shell.gschema.xml.in
|
||||
+++ b/data/org.gnome.shell.gschema.xml.in
|
||||
@@ -39,7 +39,7 @@
|
||||
</description>
|
||||
</key>
|
||||
<key name="favorite-apps" type="as">
|
||||
- <default>[ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
|
||||
+ <default>[ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop' ]</default>
|
||||
<summary>List of desktop file IDs for favorite applications</summary>
|
||||
<description>
|
||||
The applications corresponding to these identifiers
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,399 @@
|
||||
From b42dd3f87ad5fb6c7ee139cb0de22e0fbb393ba2 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Tue, 4 Jun 2019 19:22:26 +0000
|
||||
Subject: [PATCH 1/2] workspaceSwitcherPopup: Support horizontal layout
|
||||
|
||||
While mutter supports a variety of different grid layouts (n columns/rows,
|
||||
growing vertically or horizontally from any of the four corners), we
|
||||
hardcode a fixed vertical layout of a single column.
|
||||
|
||||
Now that mutter exposes the actual layout to us, add support for a more
|
||||
traditional horizontal layout as well.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/575
|
||||
---
|
||||
data/theme/gnome-shell-sass/_common.scss | 3 +-
|
||||
js/ui/windowManager.js | 36 ++++++++--
|
||||
js/ui/workspaceSwitcherPopup.js | 86 ++++++++++++++++++------
|
||||
3 files changed, 98 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
|
||||
index 293ea2ab9..b1eeb0ce9 100644
|
||||
--- a/data/theme/gnome-shell-sass/_common.scss
|
||||
+++ b/data/theme/gnome-shell-sass/_common.scss
|
||||
@@ -680,7 +680,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;
|
||||
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
|
||||
index b9f5fef46..dfe1b4460 100644
|
||||
--- a/js/ui/windowManager.js
|
||||
+++ b/js/ui/windowManager.js
|
||||
@@ -2145,6 +2145,8 @@ var WindowManager = class {
|
||||
let [action,,,target] = binding.get_name().split('-');
|
||||
let newWs;
|
||||
let direction;
|
||||
+ let vertical = workspaceManager.layout_rows == -1;
|
||||
+ let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
|
||||
|
||||
if (action == 'move') {
|
||||
// "Moving" a window to another workspace doesn't make sense when
|
||||
@@ -2157,7 +2159,12 @@ var WindowManager = class {
|
||||
}
|
||||
|
||||
if (target == 'last') {
|
||||
- direction = Meta.MotionDirection.DOWN;
|
||||
+ if (vertical)
|
||||
+ direction = Meta.MotionDirection.DOWN;
|
||||
+ else if (rtl)
|
||||
+ direction = Meta.MotionDirection.LEFT;
|
||||
+ else
|
||||
+ direction = Meta.MotionDirection.RIGHT;
|
||||
newWs = workspaceManager.get_workspace_by_index(workspaceManager.n_workspaces - 1);
|
||||
} else if (isNaN(target)) {
|
||||
// Prepend a new workspace dynamically
|
||||
@@ -2173,16 +2180,33 @@ var WindowManager = class {
|
||||
target--;
|
||||
newWs = workspaceManager.get_workspace_by_index(target);
|
||||
|
||||
- if (workspaceManager.get_active_workspace().index() > target)
|
||||
- direction = Meta.MotionDirection.UP;
|
||||
- else
|
||||
- direction = Meta.MotionDirection.DOWN;
|
||||
+ if (workspaceManager.get_active_workspace().index() > target) {
|
||||
+ if (vertical)
|
||||
+ direction = Meta.MotionDirection.UP;
|
||||
+ else if (rtl)
|
||||
+ direction = Meta.MotionDirection.RIGHT;
|
||||
+ else
|
||||
+ direction = Meta.MotionDirection.LEFT;
|
||||
+ } else {
|
||||
+ if (vertical)
|
||||
+ direction = Meta.MotionDirection.DOWN;
|
||||
+ else if (rtl)
|
||||
+ direction = Meta.MotionDirection.LEFT;
|
||||
+ else
|
||||
+ direction = Meta.MotionDirection.RIGHT;
|
||||
+ }
|
||||
}
|
||||
|
||||
- if (direction != Meta.MotionDirection.UP &&
|
||||
+ if (workspaceManager.layout_rows == -1 &&
|
||||
+ direction != Meta.MotionDirection.UP &&
|
||||
direction != Meta.MotionDirection.DOWN)
|
||||
return;
|
||||
|
||||
+ if (workspaceManager.layout_columns == -1 &&
|
||||
+ direction != Meta.MotionDirection.LEFT &&
|
||||
+ direction != Meta.MotionDirection.RIGHT)
|
||||
+ return;
|
||||
+
|
||||
if (action == 'switch')
|
||||
this.actionMoveWorkspace(newWs);
|
||||
else
|
||||
diff --git a/js/ui/workspaceSwitcherPopup.js b/js/ui/workspaceSwitcherPopup.js
|
||||
index 26404eaab..d21c5de4d 100644
|
||||
--- a/js/ui/workspaceSwitcherPopup.js
|
||||
+++ b/js/ui/workspaceSwitcherPopup.js
|
||||
@@ -17,41 +17,75 @@ class WorkspaceSwitcherPopupList extends St.Widget {
|
||||
this._itemSpacing = 0;
|
||||
this._childHeight = 0;
|
||||
this._childWidth = 0;
|
||||
+ this._orientation = global.workspace_manager.layout_rows == -1
|
||||
+ ? Clutter.Orientation.VERTICAL
|
||||
+ : Clutter.Orientation.HORIZONTAL;
|
||||
|
||||
this.connect('style-changed', () => {
|
||||
this._itemSpacing = this.get_theme_node().get_length('spacing');
|
||||
});
|
||||
}
|
||||
|
||||
- vfunc_get_preferred_height(forWidth) {
|
||||
+ _getPreferredSizeForOrientation(forSize) {
|
||||
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
let themeNode = this.get_theme_node();
|
||||
|
||||
- let availHeight = workArea.height;
|
||||
- availHeight -= themeNode.get_vertical_padding();
|
||||
+ let availSize;
|
||||
+ if (this._orientation == Clutter.Orientation.HORIZONTAL)
|
||||
+ availSize = workArea.width - themeNode.get_horizontal_padding();
|
||||
+ else
|
||||
+ availSize = workArea.height - themeNode.get_vertical_padding();
|
||||
|
||||
- let height = 0;
|
||||
+ let size = 0;
|
||||
for (let child of this.get_children()) {
|
||||
let [childMinHeight, childNaturalHeight] = child.get_preferred_height(-1);
|
||||
- let [childMinWidth, childNaturalWidth] = child.get_preferred_width(childNaturalHeight);
|
||||
- height += childNaturalHeight * workArea.width / workArea.height;
|
||||
+ let height = childNaturalHeight * workArea.width / workArea.height;
|
||||
+
|
||||
+ if (this._orientation == Clutter.Orientation.HORIZONTAL) {
|
||||
+ size += height * workArea.width / workArea.height;
|
||||
+ } else {
|
||||
+ size += height;
|
||||
+ }
|
||||
}
|
||||
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let spacing = this._itemSpacing * (workspaceManager.n_workspaces - 1);
|
||||
- height += spacing;
|
||||
- height = Math.min(height, availHeight);
|
||||
+ size += spacing;
|
||||
+ size = Math.min(size, availSize);
|
||||
+
|
||||
+ if (this._orientation == Clutter.Orientation.HORIZONTAL) {
|
||||
+ this._childWidth = (size - spacing) / workspaceManager.n_workspaces;
|
||||
+ return themeNode.adjust_preferred_width(size, size);
|
||||
+ } else {
|
||||
+ this._childHeight = (size - spacing) / workspaceManager.n_workspaces;
|
||||
+ return themeNode.adjust_preferred_height(size, size);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ _getSizeForOppositeOrientation() {
|
||||
+ let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
|
||||
- this._childHeight = (height - spacing) / workspaceManager.n_workspaces;
|
||||
+ if (this._orientation == Clutter.Orientation.HORIZONTAL) {
|
||||
+ this._childHeight = Math.round(this._childWidth * workArea.height / workArea.width);
|
||||
+ return [this._childHeight, this._childHeight];
|
||||
+ } else {
|
||||
+ this._childWidth = Math.round(this._childHeight * workArea.width / workArea.height);
|
||||
+ return [this._childWidth, this._childWidth];
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- return themeNode.adjust_preferred_height(height, height);
|
||||
+ vfunc_get_preferred_height(forWidth) {
|
||||
+ if (this._orientation == Clutter.Orientation.HORIZONTAL)
|
||||
+ return this._getSizeForOppositeOrientation();
|
||||
+ else
|
||||
+ return this._getPreferredSizeForOrientation(forWidth);
|
||||
}
|
||||
|
||||
vfunc_get_preferred_width(forHeight) {
|
||||
- let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
- this._childWidth = Math.round(this._childHeight * workArea.width / workArea.height);
|
||||
-
|
||||
- return [this._childWidth, this._childWidth];
|
||||
+ if (this._orientation == Clutter.Orientation.HORIZONTAL)
|
||||
+ return this._getPreferredSizeForOrientation(forHeight);
|
||||
+ else
|
||||
+ return this._getSizeForOppositeOrientation();
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
@@ -62,15 +96,23 @@ class WorkspaceSwitcherPopupList extends St.Widget {
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
+ let rtl = this.text_direction == Clutter.TextDirection.RTL;
|
||||
+ let x = rtl ? box.x2 - this._childWidth : box.x1;
|
||||
let y = box.y1;
|
||||
- let prevChildBoxY2 = box.y1 - this._itemSpacing;
|
||||
for (let child of this.get_children()) {
|
||||
- childBox.x1 = box.x1;
|
||||
- childBox.x2 = box.x1 + this._childWidth;
|
||||
- childBox.y1 = prevChildBoxY2 + this._itemSpacing;
|
||||
+ childBox.x1 = Math.round(x);
|
||||
+ childBox.x2 = Math.round(x + this._childWidth);
|
||||
+ childBox.y1 = Math.round(y);
|
||||
childBox.y2 = Math.round(y + this._childHeight);
|
||||
- y += this._childHeight + this._itemSpacing;
|
||||
- prevChildBoxY2 = childBox.y2;
|
||||
+
|
||||
+ if (this._orientation == Clutter.Orientation.HORIZONTAL) {
|
||||
+ if (rtl)
|
||||
+ x -= this._childWidth + this._itemSpacing;
|
||||
+ else
|
||||
+ x += this._childWidth + this._itemSpacing;
|
||||
+ } else {
|
||||
+ y += this._childHeight + this._itemSpacing;
|
||||
+ }
|
||||
child.allocate(childBox, flags);
|
||||
}
|
||||
}
|
||||
@@ -123,6 +165,10 @@ class WorkspaceSwitcherPopup extends St.Widget {
|
||||
indicator = new St.Bin({ style_class: 'ws-switcher-active-up' });
|
||||
else if(i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.DOWN)
|
||||
indicator = new St.Bin({ style_class: 'ws-switcher-active-down' });
|
||||
+ else if(i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.LEFT)
|
||||
+ indicator = new St.Bin({ style_class: 'ws-switcher-active-left' });
|
||||
+ else if(i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.RIGHT)
|
||||
+ indicator = new St.Bin({ style_class: 'ws-switcher-active-right' });
|
||||
else
|
||||
indicator = new St.Bin({ style_class: 'ws-switcher-box' });
|
||||
|
||||
--
|
||||
2.21.0
|
||||
|
||||
|
||||
From 813976ff69b15ab884d44f5f6a56ae66f407acfd Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Tue, 4 Jun 2019 19:49:23 +0000
|
||||
Subject: [PATCH 2/2] workspacesView: Support horizontal layout
|
||||
|
||||
Just as we did for the workspace switcher popup, support workspaces
|
||||
being laid out in a single row in the window picker.
|
||||
|
||||
Note that this takes care of the various workspace switch actions in
|
||||
the overview (scrolling, panning, touch(pad) gestures) as well as the
|
||||
switch animation, but not of the overview's workspace switcher component.
|
||||
|
||||
There are currently no plans to support other layouts there, as the
|
||||
component is inherently vertical (in fact, it was the whole reason for
|
||||
switching the layout in the first place).
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/575
|
||||
---
|
||||
js/ui/workspacesView.js | 81 ++++++++++++++++++++++++++++++-----------
|
||||
1 file changed, 60 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
|
||||
index fe06d9dae..069937d5a 100644
|
||||
--- a/js/ui/workspacesView.js
|
||||
+++ b/js/ui/workspacesView.js
|
||||
@@ -181,26 +181,32 @@ var WorkspacesView = class extends WorkspacesViewBase {
|
||||
|
||||
Tweener.removeTweens(workspace.actor);
|
||||
|
||||
- let y = (w - active) * this._fullGeometry.height;
|
||||
+ let params = {};
|
||||
+ if (workspaceManager.layout_rows == -1)
|
||||
+ params.y = (w - active) * this._fullGeometry.height;
|
||||
+ else if (this.actor.text_direction == Clutter.TextDirection.RTL)
|
||||
+ params.x = (active - w) * this._fullGeometry.width;
|
||||
+ else
|
||||
+ params.x = (w - active) * this._fullGeometry.width;
|
||||
|
||||
if (showAnimation) {
|
||||
- let params = { y: y,
|
||||
- time: WORKSPACE_SWITCH_TIME,
|
||||
- transition: 'easeOutQuad'
|
||||
- };
|
||||
+ let tweenParams = Object.assign(params, {
|
||||
+ time: WORKSPACE_SWITCH_TIME,
|
||||
+ transition: 'easeOutQuad'
|
||||
+ });
|
||||
// we have to call _updateVisibility() once before the
|
||||
// animation and once afterwards - it does not really
|
||||
// matter which tween we use, so we pick the first one ...
|
||||
if (w == 0) {
|
||||
this._updateVisibility();
|
||||
- params.onComplete = () => {
|
||||
+ tweenParams.onComplete = () => {
|
||||
this._animating = false;
|
||||
this._updateVisibility();
|
||||
};
|
||||
}
|
||||
- Tweener.addTween(workspace.actor, params);
|
||||
+ Tweener.addTween(workspace.actor, tweenParams);
|
||||
} else {
|
||||
- workspace.actor.set_position(0, y);
|
||||
+ workspace.actor.set(params);
|
||||
if (w == 0)
|
||||
this._updateVisibility();
|
||||
}
|
||||
@@ -338,22 +344,39 @@ var WorkspacesView = class extends WorkspacesViewBase {
|
||||
metaWorkspace.activate(global.get_current_time());
|
||||
}
|
||||
|
||||
- let last = this._workspaces.length - 1;
|
||||
- let firstWorkspaceY = this._workspaces[0].actor.y;
|
||||
- let lastWorkspaceY = this._workspaces[last].actor.y;
|
||||
- let workspacesHeight = lastWorkspaceY - firstWorkspaceY;
|
||||
-
|
||||
if (adj.upper == 1)
|
||||
return;
|
||||
|
||||
- let currentY = firstWorkspaceY;
|
||||
- let newY = - adj.value / (adj.upper - 1) * workspacesHeight;
|
||||
+ let last = this._workspaces.length - 1;
|
||||
+
|
||||
+ if (workspaceManager.layout_rows == -1) {
|
||||
+ let firstWorkspaceY = this._workspaces[0].actor.y;
|
||||
+ let lastWorkspaceY = this._workspaces[last].actor.y;
|
||||
+ let workspacesHeight = lastWorkspaceY - firstWorkspaceY;
|
||||
+
|
||||
+ let currentY = firstWorkspaceY;
|
||||
+ let newY = -adj.value / (adj.upper - 1) * workspacesHeight;
|
||||
|
||||
- let dy = newY - currentY;
|
||||
+ let dy = newY - currentY;
|
||||
+
|
||||
+ for (let i = 0; i < this._workspaces.length; i++) {
|
||||
+ this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
|
||||
+ this._workspaces[i].actor.y += dy;
|
||||
+ }
|
||||
+ } else {
|
||||
+ let firstWorkspaceX = this._workspaces[0].actor.x;
|
||||
+ let lastWorkspaceX = this._workspaces[last].actor.x;
|
||||
+ let workspacesWidth = lastWorkspaceX - firstWorkspaceX;
|
||||
|
||||
- for (let i = 0; i < this._workspaces.length; i++) {
|
||||
- this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
|
||||
- this._workspaces[i].actor.y += dy;
|
||||
+ let currentX = firstWorkspaceX;
|
||||
+ let newX = -adj.value / (adj.upper - 1) * workspacesWidth;
|
||||
+
|
||||
+ let dx = newX - currentX;
|
||||
+
|
||||
+ for (let i = 0; i < this._workspaces.length; i++) {
|
||||
+ this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
|
||||
+ this._workspaces[i].actor.x += dx;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -504,7 +527,12 @@ var WorkspacesDisplay = class {
|
||||
_onPan(action) {
|
||||
let [dist, dx, dy] = action.get_motion_delta(0);
|
||||
let adjustment = this._scrollAdjustment;
|
||||
- adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
|
||||
+ if (global.workspace_manager.layout_rows == -1)
|
||||
+ adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
|
||||
+ else if (this.actor.text_direction == Clutter.TextDirection.RTL)
|
||||
+ adjustment.value += (dx / this.actor.width) * adjustment.page_size;
|
||||
+ else
|
||||
+ adjustment.value -= (dx / this.actor.width) * adjustment.page_size;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -536,7 +564,12 @@ var WorkspacesDisplay = class {
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let active = workspaceManager.get_active_workspace_index();
|
||||
let adjustment = this._scrollAdjustment;
|
||||
- adjustment.value = (active - yRel / this.actor.height) * adjustment.page_size;
|
||||
+ if (workspaceManager.layout_rows == -1)
|
||||
+ adjustment.value = (active - yRel / this.actor.height) * adjustment.page_size;
|
||||
+ else if (this.actor.text_direction == Clutter.TextDirection.RTL)
|
||||
+ adjustment.value = (active + xRel / this.actor.width) * adjustment.page_size;
|
||||
+ else
|
||||
+ adjustment.value = (active - xRel / this.actor.width) * adjustment.page_size;
|
||||
}
|
||||
|
||||
_onSwitchWorkspaceActivated(action, direction) {
|
||||
@@ -755,6 +788,12 @@ var WorkspacesDisplay = class {
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
ws = activeWs.get_neighbor(Meta.MotionDirection.DOWN);
|
||||
break;
|
||||
+ case Clutter.ScrollDirection.LEFT:
|
||||
+ ws = activeWs.get_neighbor(Meta.MotionDirection.LEFT);
|
||||
+ break;
|
||||
+ case Clutter.ScrollDirection.RIGHT:
|
||||
+ ws = activeWs.get_neighbor(Meta.MotionDirection.RIGHT);
|
||||
+ break;
|
||||
default:
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,643 @@
|
||||
From 781dfcf6ce7168c6b116d58df5f1c67291a7b513 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 16 May 2019 00:57:27 +0200
|
||||
Subject: [PATCH 01/11] introspect: Include `sandboxed-app-id` as well
|
||||
|
||||
App IDs in gnome-shell don't match AppStream, Flatpak or Snap IDs. For the
|
||||
desktop portal, the latter two are more relevant, so include it in the
|
||||
returned information.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1289
|
||||
---
|
||||
js/misc/introspect.js | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index f7a7f2fe6..1e8300d0a 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -55,6 +55,11 @@ var IntrospectService = class {
|
||||
return APP_WHITELIST.includes(sender);
|
||||
}
|
||||
|
||||
+ _getSandboxedAppId(app) {
|
||||
+ let ids = app.get_windows().map(w => w.get_sandboxed_app_id());
|
||||
+ return ids.find(id => id != null);
|
||||
+ }
|
||||
+
|
||||
_syncRunningApplications() {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let apps = this._appSystem.get_running();
|
||||
@@ -76,6 +81,10 @@ var IntrospectService = class {
|
||||
newActiveApplication = app.get_id();
|
||||
}
|
||||
|
||||
+ let sandboxedAppId = this._getSandboxedAppId(app);
|
||||
+ if (sandboxedAppId)
|
||||
+ appInfo['sandboxed-app-id'] = new GLib.Variant('s', sandboxedAppId);
|
||||
+
|
||||
newRunningApplications[app.get_id()] = appInfo;
|
||||
}
|
||||
|
||||
@@ -137,6 +146,7 @@ var IntrospectService = class {
|
||||
let frameRect = window.get_frame_rect();
|
||||
let title = window.get_title();
|
||||
let wmClass = window.get_wm_class();
|
||||
+ let sandboxedAppId = window.get_sandboxed_app_id();
|
||||
|
||||
windowsList[windowId] = {
|
||||
'app-id': GLib.Variant.new('s', app.get_id()),
|
||||
@@ -153,6 +163,10 @@ var IntrospectService = class {
|
||||
|
||||
if (wmClass != null)
|
||||
windowsList[windowId]['wm-class'] = GLib.Variant.new('s', wmClass);
|
||||
+
|
||||
+ if (sandboxedAppId != null)
|
||||
+ windowsList[windowId]['sandboxed-app-id'] =
|
||||
+ GLib.Variant.new('s', sandboxedAppId);
|
||||
}
|
||||
}
|
||||
invocation.return_value(new GLib.Variant('(a{ta{sv}})', [windowsList]));
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From b0b4fb82c058722e2171d24902ba3855ffe243f3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Wed, 18 Sep 2019 14:57:48 +0200
|
||||
Subject: [PATCH 02/11] introspect: Check whitelist also for
|
||||
GetRunningWindows()
|
||||
|
||||
Otherwise the xdg-desktop-portal-gtk screen cast widget won't work.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/732
|
||||
---
|
||||
js/misc/introspect.js | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index 1e8300d0a..cee6409a8 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -128,7 +128,8 @@ var IntrospectService = class {
|
||||
let apps = this._appSystem.get_running();
|
||||
let windowsList = {};
|
||||
|
||||
- if (!this._isIntrospectEnabled()) {
|
||||
+ if (!this._isIntrospectEnabled() &&
|
||||
+ !this._isSenderWhitelisted(invocation.get_sender())) {
|
||||
invocation.return_error_literal(Gio.DBusError,
|
||||
Gio.DBusError.ACCESS_DENIED,
|
||||
'App introspection not allowed');
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 23556e03db3743ddf478a3c1bbb64946c687afdf Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Mon, 25 Nov 2019 19:44:10 +0100
|
||||
Subject: [PATCH 03/11] introspect: Fix whitelist check
|
||||
|
||||
The whitelist is a list of well-known D-Bus names, which we then search
|
||||
for the unique name we get from the method invocation - unsuccesfully.
|
||||
|
||||
Fix this by watching the bus for any name in the whitelist in order
|
||||
to maintain a map from wel-known to unique name that we can use for
|
||||
matching.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1916
|
||||
---
|
||||
js/misc/introspect.js | 11 ++++++++++-
|
||||
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index cee6409a8..f14eabfad 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -39,6 +39,15 @@ var IntrospectService = class {
|
||||
});
|
||||
|
||||
this._syncRunningApplications();
|
||||
+
|
||||
+ this._whitelistMap = new Map();
|
||||
+ APP_WHITELIST.forEach(appName => {
|
||||
+ Gio.DBus.watch_name(Gio.BusType.SESSION,
|
||||
+ appName,
|
||||
+ Gio.BusNameWatcherFlags.NONE,
|
||||
+ (conn, name, owner) => this._whitelistMap.set(name, owner),
|
||||
+ (conn, name) => this._whitelistMap.delete(name));
|
||||
+ });
|
||||
}
|
||||
|
||||
_isStandaloneApp(app) {
|
||||
@@ -52,7 +61,7 @@ var IntrospectService = class {
|
||||
}
|
||||
|
||||
_isSenderWhitelisted(sender) {
|
||||
- return APP_WHITELIST.includes(sender);
|
||||
+ return [...this._whitelistMap.values()].includes(sender);
|
||||
}
|
||||
|
||||
_getSandboxedAppId(app) {
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 1a6275add6d214df958ed8a06c097445bef021bc Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Wed, 25 Sep 2019 20:36:28 +0200
|
||||
Subject: [PATCH 04/11] introspect: Add helper to check method call permission
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
js/misc/introspect.js | 16 ++++++++++++----
|
||||
1 file changed, 12 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index f14eabfad..6186754cd 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -120,9 +120,18 @@ var IntrospectService = class {
|
||||
type == Meta.WindowType.UTILITY);
|
||||
}
|
||||
|
||||
+ _isInvocationAllowed(invocation) {
|
||||
+ if (this._isIntrospectEnabled())
|
||||
+ return true;
|
||||
+
|
||||
+ if (this._isSenderWhitelisted(invocation.get_sender()))
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
GetRunningApplicationsAsync(params, invocation) {
|
||||
- if (!this._isIntrospectEnabled() &&
|
||||
- !this._isSenderWhitelisted(invocation.get_sender())) {
|
||||
+ if (!this._isInvocationAllowed(invocation)) {
|
||||
invocation.return_error_literal(Gio.DBusError,
|
||||
Gio.DBusError.ACCESS_DENIED,
|
||||
'App introspection not allowed');
|
||||
@@ -137,8 +146,7 @@ var IntrospectService = class {
|
||||
let apps = this._appSystem.get_running();
|
||||
let windowsList = {};
|
||||
|
||||
- if (!this._isIntrospectEnabled() &&
|
||||
- !this._isSenderWhitelisted(invocation.get_sender())) {
|
||||
+ if (!this._isInvocationAllowed(invocation)) {
|
||||
invocation.return_error_literal(Gio.DBusError,
|
||||
Gio.DBusError.ACCESS_DENIED,
|
||||
'App introspection not allowed');
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From f578dc01cf774faa4504a4d258cc0e82060d988b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 11:55:33 +0200
|
||||
Subject: [PATCH 05/11] shell-util: Add API to check for X11 extensions
|
||||
|
||||
Will be used to disable animations when running inside Xvnc. This was
|
||||
done in gsd-xsettings before.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
src/shell-util.c | 26 ++++++++++++++++++++++++++
|
||||
src/shell-util.h | 3 +++
|
||||
2 files changed, 29 insertions(+)
|
||||
|
||||
diff --git a/src/shell-util.c b/src/shell-util.c
|
||||
index 31bb18e70..fa3fc08c8 100644
|
||||
--- a/src/shell-util.c
|
||||
+++ b/src/shell-util.c
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <meta/meta-shaped-texture.h>
|
||||
+#include <meta/display.h>
|
||||
+#include <meta/meta-x11-display.h>
|
||||
|
||||
#include <locale.h>
|
||||
#ifdef HAVE__NL_TIME_FIRST_WEEKDAY
|
||||
@@ -613,3 +615,27 @@ shell_util_check_cloexec_fds (void)
|
||||
fdwalk (check_cloexec, NULL);
|
||||
g_info ("Open fd CLOEXEC check complete");
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * shell_util_has_x11_display_extension:
|
||||
+ * @display: A #MetaDisplay
|
||||
+ * @extension: An X11 extension
|
||||
+ *
|
||||
+ * If the corresponding X11 display provides the passed extension, return %TRUE,
|
||||
+ * otherwise %FALSE. If there is no X11 display, %FALSE is passed.
|
||||
+ */
|
||||
+gboolean
|
||||
+shell_util_has_x11_display_extension (MetaDisplay *display,
|
||||
+ const char *extension)
|
||||
+{
|
||||
+ MetaX11Display *x11_display;
|
||||
+ Display *xdisplay;
|
||||
+ int op, event, error;
|
||||
+
|
||||
+ x11_display = meta_display_get_x11_display (display);
|
||||
+ if (!x11_display)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ xdisplay = meta_x11_display_get_xdisplay (x11_display);
|
||||
+ return XQueryExtension (xdisplay, extension, &op, &event, &error);
|
||||
+}
|
||||
diff --git a/src/shell-util.h b/src/shell-util.h
|
||||
index 6904f43bc..02b8404e9 100644
|
||||
--- a/src/shell-util.h
|
||||
+++ b/src/shell-util.h
|
||||
@@ -59,6 +59,9 @@ cairo_surface_t * shell_util_composite_capture_images (ClutterCapture *captures
|
||||
|
||||
void shell_util_check_cloexec_fds (void);
|
||||
|
||||
+gboolean shell_util_has_x11_display_extension (MetaDisplay *display,
|
||||
+ const char *extension);
|
||||
+
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_UTIL_H__ */
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 48ee79bb7b48c7e93e77e35629f21bbdbabc253f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 11:56:34 +0200
|
||||
Subject: [PATCH 06/11] st/settings: Add API to inhibit animations
|
||||
|
||||
There may be situations where we shouldn't enable animations. Make it
|
||||
possible for the Shell to decide when there are such situations and in
|
||||
when needed inhibit animations.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
src/st/st-settings.c | 38 +++++++++++++++++++++++++++++++++++++-
|
||||
src/st/st-settings.h | 4 ++++
|
||||
2 files changed, 41 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/st/st-settings.c b/src/st/st-settings.c
|
||||
index 17f2c466e..ebfd28480 100644
|
||||
--- a/src/st/st-settings.c
|
||||
+++ b/src/st/st-settings.c
|
||||
@@ -54,6 +54,7 @@ struct _StSettings
|
||||
|
||||
gchar *gtk_theme;
|
||||
gchar *gtk_icon_theme;
|
||||
+ int inhibit_animations_count;
|
||||
gboolean enable_animations;
|
||||
gboolean primary_paste;
|
||||
gboolean magnifier_active;
|
||||
@@ -62,6 +63,41 @@ struct _StSettings
|
||||
|
||||
G_DEFINE_TYPE (StSettings, st_settings, G_TYPE_OBJECT)
|
||||
|
||||
+static gboolean
|
||||
+get_enable_animations (StSettings *settings)
|
||||
+{
|
||||
+ if (settings->inhibit_animations_count > 0)
|
||||
+ return FALSE;
|
||||
+ else
|
||||
+ return settings->enable_animations;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+st_settings_inhibit_animations (StSettings *settings)
|
||||
+{
|
||||
+ gboolean enable_animations;
|
||||
+
|
||||
+ enable_animations = get_enable_animations (settings);
|
||||
+ settings->inhibit_animations_count++;
|
||||
+
|
||||
+ if (enable_animations != get_enable_animations (settings))
|
||||
+ g_object_notify_by_pspec (G_OBJECT (settings),
|
||||
+ props[PROP_ENABLE_ANIMATIONS]);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+st_settings_uninhibit_animations (StSettings *settings)
|
||||
+{
|
||||
+ gboolean enable_animations;
|
||||
+
|
||||
+ enable_animations = get_enable_animations (settings);
|
||||
+ settings->inhibit_animations_count--;
|
||||
+
|
||||
+ if (enable_animations != get_enable_animations (settings))
|
||||
+ g_object_notify_by_pspec (G_OBJECT (settings),
|
||||
+ props[PROP_ENABLE_ANIMATIONS]);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
st_settings_finalize (GObject *object)
|
||||
{
|
||||
@@ -95,7 +131,7 @@ st_settings_get_property (GObject *object,
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ENABLE_ANIMATIONS:
|
||||
- g_value_set_boolean (value, settings->enable_animations);
|
||||
+ g_value_set_boolean (value, get_enable_animations (settings));
|
||||
break;
|
||||
case PROP_PRIMARY_PASTE:
|
||||
g_value_set_boolean (value, settings->primary_paste);
|
||||
diff --git a/src/st/st-settings.h b/src/st/st-settings.h
|
||||
index c2c4fa23e..8b2549469 100644
|
||||
--- a/src/st/st-settings.h
|
||||
+++ b/src/st/st-settings.h
|
||||
@@ -33,6 +33,10 @@ G_DECLARE_FINAL_TYPE (StSettings, st_settings, ST, SETTINGS, GObject)
|
||||
|
||||
StSettings * st_settings_get (void);
|
||||
|
||||
+void st_settings_inhibit_animations (StSettings *settings);
|
||||
+
|
||||
+void st_settings_uninhibit_animations (StSettings *settings);
|
||||
+
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_SETTINGS_H__ */
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 80025388c44296b629c8f24ea673d77ffc4efc67 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 12:02:31 +0200
|
||||
Subject: [PATCH 07/11] main: Inhibit animations when software rendered
|
||||
|
||||
This was previously decided by gsd-xsettings.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
js/ui/main.js | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index 978f83c3f..c3230ff03 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -147,6 +147,8 @@ function _initializeUI() {
|
||||
_loadOskLayouts();
|
||||
_loadDefaultStylesheet();
|
||||
|
||||
+ new AnimationsSettings();
|
||||
+
|
||||
// Setup the stage hierarchy early
|
||||
layoutManager = new Layout.LayoutManager();
|
||||
|
||||
@@ -723,3 +725,13 @@ function showRestartMessage(message) {
|
||||
let restartMessage = new RestartMessage(message);
|
||||
restartMessage.open();
|
||||
}
|
||||
+
|
||||
+var AnimationsSettings = class {
|
||||
+ constructor() {
|
||||
+ let backend = Meta.get_backend();
|
||||
+ if (!backend.is_rendering_hardware_accelerated()) {
|
||||
+ St.Settings.get().inhibit_animations();
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+};
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 788ecb60e35d8a369f0747813f37e8b1ca27cb87 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 12:03:52 +0200
|
||||
Subject: [PATCH 08/11] main: Inhibit animations if X server advertises
|
||||
VNC-EXTENSION
|
||||
|
||||
This was previously done by gsd-xsettings to disable animations when
|
||||
running in Xvnc.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
js/ui/main.js | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index c3230ff03..ae7c3ffd0 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -733,5 +733,12 @@ var AnimationsSettings = class {
|
||||
St.Settings.get().inhibit_animations();
|
||||
return;
|
||||
}
|
||||
+
|
||||
+ let isXvnc = Shell.util_has_x11_display_extension(
|
||||
+ global.display, 'VNC-EXTENSION');
|
||||
+ if (isXvnc) {
|
||||
+ St.Settings.get().inhibit_animations();
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
};
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 1da5a7ce4cf0b95b96dd50b62ac6c1380fd88cb1 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 12:04:52 +0200
|
||||
Subject: [PATCH 09/11] main: Inhibit animations when there is a remote desktop
|
||||
session
|
||||
|
||||
If a remote desktop session asks for animations to be disabled, inhibit
|
||||
animations while the session is active.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
js/ui/main.js | 26 ++++++++++++++++++++++++++
|
||||
1 file changed, 26 insertions(+)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index ae7c3ffd0..1203b3c39 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -740,5 +740,31 @@ var AnimationsSettings = class {
|
||||
St.Settings.get().inhibit_animations();
|
||||
return;
|
||||
}
|
||||
+
|
||||
+ let remoteAccessController = backend.get_remote_access_controller();
|
||||
+ if (!remoteAccessController)
|
||||
+ return;
|
||||
+
|
||||
+ this._handles = new Set();
|
||||
+ remoteAccessController.connect('new-handle',
|
||||
+ (_, handle) => this._onNewRemoteAccessHandle(handle));
|
||||
+ }
|
||||
+
|
||||
+ _onRemoteAccessHandleStopped(handle) {
|
||||
+ let settings = St.Settings.get();
|
||||
+
|
||||
+ settings.uninhibit_animations();
|
||||
+ this._handles.delete(handle);
|
||||
+ }
|
||||
+
|
||||
+ _onNewRemoteAccessHandle(handle) {
|
||||
+ if (!handle.get_disable_animations())
|
||||
+ return;
|
||||
+
|
||||
+ let settings = St.Settings.get();
|
||||
+
|
||||
+ settings.inhibit_animations();
|
||||
+ this._handles.add(handle);
|
||||
+ handle.connect('stopped', this._onRemoteAccessHandleStopped.bind(this));
|
||||
}
|
||||
};
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From ebfd46341a2d7a6338386e4be4a2807a6bc6e63c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 12:06:13 +0200
|
||||
Subject: [PATCH 10/11] introspect: Rename variable
|
||||
|
||||
It was too generic, and would conflict with a StSettings variable.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
js/misc/introspect.js | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index 6186754cd..8e68a7e4f 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -29,7 +29,9 @@ var IntrospectService = class {
|
||||
this._syncRunningApplications();
|
||||
});
|
||||
|
||||
- this._settings = new Gio.Settings({ schema_id: INTROSPECT_SCHEMA });
|
||||
+ this._introspectSettings = new Gio.Settings({
|
||||
+ schema_id: INTROSPECT_SCHEMA,
|
||||
+ });
|
||||
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
tracker.connect('notify::focus-app',
|
||||
@@ -57,7 +59,7 @@ var IntrospectService = class {
|
||||
}
|
||||
|
||||
_isIntrospectEnabled() {
|
||||
- return this._settings.get_boolean(INTROSPECT_KEY);
|
||||
+ return this._introspectSettings.get_boolean(INTROSPECT_KEY);
|
||||
}
|
||||
|
||||
_isSenderWhitelisted(sender) {
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 343e7792fc84c296b331c3fcb142ed79d2ce9bd5 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 12:07:03 +0200
|
||||
Subject: [PATCH 11/11] introspect: Add AnimationsEnabled property
|
||||
|
||||
While the gsetting is available for all who needs it, the Shell might
|
||||
override it given various hueristics. Expose the decision made by the
|
||||
Shell via a new property.
|
||||
|
||||
Intended to be used by gsd-xsettings as well as xdg-desktop-portal-gtk.
|
||||
|
||||
This also add a version property to the API, so that semi external
|
||||
services (xdg-desktop-portal-gtk) can detect what API is expected to be
|
||||
present.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
.../org.gnome.Shell.Introspect.xml | 14 ++++++++++
|
||||
js/misc/introspect.js | 27 ++++++++++++++++++-
|
||||
2 files changed, 40 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/data/dbus-interfaces/org.gnome.Shell.Introspect.xml b/data/dbus-interfaces/org.gnome.Shell.Introspect.xml
|
||||
index 9508681af..d71f2414b 100644
|
||||
--- a/data/dbus-interfaces/org.gnome.Shell.Introspect.xml
|
||||
+++ b/data/dbus-interfaces/org.gnome.Shell.Introspect.xml
|
||||
@@ -57,5 +57,19 @@
|
||||
<method name="GetWindows">
|
||||
<arg name="windows" direction="out" type="a{ta{sv}}" />
|
||||
</method>
|
||||
+
|
||||
+ <!--
|
||||
+ AnimationsEnabled:
|
||||
+ @short_description: Whether the shell animations are enabled
|
||||
+
|
||||
+ By default determined by the org.gnome.desktop.interface enable-animations
|
||||
+ gsetting, but may be overridden, e.g. if there is an active screen cast or
|
||||
+ remote desktop session that asked for animations to be disabled.
|
||||
+
|
||||
+ Since: 2
|
||||
+ -->
|
||||
+ <property name="AnimationsEnabled" type="b" access="read"/>
|
||||
+
|
||||
+ <property name="version" type="u" access="read"/>
|
||||
</interface>
|
||||
</node>
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index 8e68a7e4f..7c62113e5 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -1,9 +1,11 @@
|
||||
-const { Gio, GLib, Meta, Shell } = imports.gi;
|
||||
+const { Gio, GLib, Meta, Shell, St } = imports.gi;
|
||||
|
||||
const INTROSPECT_SCHEMA = 'org.gnome.shell';
|
||||
const INTROSPECT_KEY = 'introspect';
|
||||
const APP_WHITELIST = ['org.freedesktop.impl.portal.desktop.gtk'];
|
||||
|
||||
+const INTROSPECT_DBUS_API_VERSION = 2;
|
||||
+
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
const IntrospectDBusIface = loadInterfaceXML('org.gnome.Shell.Introspect');
|
||||
@@ -21,6 +23,7 @@ var IntrospectService = class {
|
||||
this._runningApplicationsDirty = true;
|
||||
this._activeApplication = null;
|
||||
this._activeApplicationDirty = true;
|
||||
+ this._animationsEnabled = true;
|
||||
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appSystem.connect('app-state-changed',
|
||||
@@ -50,6 +53,11 @@ var IntrospectService = class {
|
||||
(conn, name, owner) => this._whitelistMap.set(name, owner),
|
||||
(conn, name) => this._whitelistMap.delete(name));
|
||||
});
|
||||
+
|
||||
+ this._settings = St.Settings.get();
|
||||
+ this._settings.connect('notify::enable-animations',
|
||||
+ this._syncAnimationsEnabled.bind(this));
|
||||
+ this._syncAnimationsEnabled();
|
||||
}
|
||||
|
||||
_isStandaloneApp(app) {
|
||||
@@ -191,4 +199,21 @@ var IntrospectService = class {
|
||||
}
|
||||
invocation.return_value(new GLib.Variant('(a{ta{sv}})', [windowsList]));
|
||||
}
|
||||
+
|
||||
+ _syncAnimationsEnabled() {
|
||||
+ let wasAnimationsEnabled = this._animationsEnabled;
|
||||
+ this._animationsEnabled = this._settings.enable_animations;
|
||||
+ if (wasAnimationsEnabled !== this._animationsEnabled) {
|
||||
+ let variant = new GLib.Variant('b', this._animationsEnabled);
|
||||
+ this._dbusImpl.emit_property_changed('AnimationsEnabled', variant);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ get AnimationsEnabled() {
|
||||
+ return this._animationsEnabled;
|
||||
+ }
|
||||
+
|
||||
+ get version() {
|
||||
+ return INTROSPECT_DBUS_API_VERSION;
|
||||
+ }
|
||||
};
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,176 @@
|
||||
From 4926a9b8f958617d67d603622b1382c17fe4037c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
|
||||
Date: Wed, 20 May 2020 12:05:04 +0200
|
||||
Subject: [PATCH 1/2] workspacesView: Avoid setting invalid geometries on views
|
||||
|
||||
The fullGeometry and the actualGeometry of the WorkspacesDisplay are set
|
||||
from the allocation of the overviews ControlsManager and the
|
||||
WorkspacesDisplay, that means they're only valid after those actors got
|
||||
their allocations during Clutters allocation cycle.
|
||||
|
||||
Since WorkspacesDisplay._updateWorkspacesViews() is already called while
|
||||
showing/mapping the WorkspacesDisplay, that allocation cycle didn't
|
||||
happen yet and we end up either setting the geometries of the views to
|
||||
null (in case of the fullGeometry) or to something wrong (a 0-sized
|
||||
allocation in case of the actualGeometry).
|
||||
|
||||
So avoid setting invalid geometries on the views by initializing both
|
||||
the fullGeometry and the actualGeometry to null, and then only updating
|
||||
the geometries of the views after they're set to a correct value.
|
||||
|
||||
Note that this means we won't correctly animate the overview the first
|
||||
time we open it since the animation depends on the geometries being set,
|
||||
but is being started from show(), which means no allocations have
|
||||
happened yet. In practice this introduces no regression though since
|
||||
before this change we simply used incorrect geometries (see the 0-sized
|
||||
allocation mentioned above) on the initial opening and the animation
|
||||
didn't work either.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1119
|
||||
---
|
||||
js/ui/workspacesView.js | 28 +++++++++++++++++-----------
|
||||
1 file changed, 17 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
|
||||
index e302296a6..02baddc6e 100644
|
||||
--- a/js/ui/workspacesView.js
|
||||
+++ b/js/ui/workspacesView.js
|
||||
@@ -521,6 +521,7 @@ var WorkspacesDisplay = class {
|
||||
this._scrollEventId = 0;
|
||||
this._keyPressEventId = 0;
|
||||
|
||||
+ this._actualGeometry = null;
|
||||
this._fullGeometry = null;
|
||||
}
|
||||
|
||||
@@ -675,8 +676,10 @@ var WorkspacesDisplay = class {
|
||||
|
||||
this._workspacesViews.forEach(v => v.actor.show());
|
||||
|
||||
- this._updateWorkspacesFullGeometry();
|
||||
- this._updateWorkspacesActualGeometry();
|
||||
+ if (this._fullGeometry)
|
||||
+ this._syncWorkspacesFullGeometry();
|
||||
+ if (this._actualGeometry)
|
||||
+ this._syncWorkspacesActualGeometry();
|
||||
}
|
||||
|
||||
_scrollValueChanged() {
|
||||
@@ -739,10 +742,10 @@ var WorkspacesDisplay = class {
|
||||
// the sliding controls were never slid in at all.
|
||||
setWorkspacesFullGeometry(geom) {
|
||||
this._fullGeometry = geom;
|
||||
- this._updateWorkspacesFullGeometry();
|
||||
+ this._syncWorkspacesFullGeometry();
|
||||
}
|
||||
|
||||
- _updateWorkspacesFullGeometry() {
|
||||
+ _syncWorkspacesFullGeometry() {
|
||||
if (!this._workspacesViews.length)
|
||||
return;
|
||||
|
||||
@@ -754,18 +757,21 @@ var WorkspacesDisplay = class {
|
||||
}
|
||||
|
||||
_updateWorkspacesActualGeometry() {
|
||||
+ const [x, y] = this.actor.get_transformed_position();
|
||||
+ const width = this.actor.allocation.get_width();
|
||||
+ const height = this.actor.allocation.get_height();
|
||||
+
|
||||
+ this._actualGeometry = { x, y, width, height };
|
||||
+ this._syncWorkspacesActualGeometry();
|
||||
+ }
|
||||
+
|
||||
+ _syncWorkspacesActualGeometry() {
|
||||
if (!this._workspacesViews.length)
|
||||
return;
|
||||
|
||||
- let [x, y] = this.actor.get_transformed_position();
|
||||
- let allocation = this.actor.allocation;
|
||||
- let width = allocation.x2 - allocation.x1;
|
||||
- let height = allocation.y2 - allocation.y1;
|
||||
- let primaryGeometry = { x: x, y: y, width: width, height: height };
|
||||
-
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
- let geometry = (i == this._primaryIndex) ? primaryGeometry : monitors[i];
|
||||
+ let geometry = i === this._primaryIndex ? this._actualGeometry : monitors[i];
|
||||
this._workspacesViews[i].setActualGeometry(geometry);
|
||||
}
|
||||
}
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 4671eebccf4e6afce8c0a869d63095b39aa7e163 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
|
||||
Date: Wed, 20 May 2020 13:39:11 +0200
|
||||
Subject: [PATCH 2/2] workspacesView: Only animate on show() when geometries
|
||||
are already set
|
||||
|
||||
Animating the window clones of the overview requires the fullGeometry
|
||||
and the actualGeometry to be set, which they won't be when showing the
|
||||
overview for the first time. So don't even try to animate the window
|
||||
clones in that case because the geometries will still be null and
|
||||
accessing them in workspace.js will throw errors.
|
||||
|
||||
The workspace views will still get the correct layout as soon as the
|
||||
allocations happen because syncing the geometries will trigger updating
|
||||
the window positions. Since animations are disabled for position changes
|
||||
when syncing the geometry though, we won't get an animation and the
|
||||
clones will jump into place. That's not a regression though since before
|
||||
this change we also didn't animate in that case because the geometries
|
||||
used were simply wrong (the actualGeometry was 0-sized as explained in
|
||||
the last commit).
|
||||
|
||||
If we wanted to fix the initial animation of the overview, we'd have to
|
||||
always enable animations of the window clones when syncing geometries,
|
||||
but that would break the animation of the workspace when hovering the
|
||||
workspaceThumbnail slider, because right now those animations are "glued
|
||||
together" using the actualGeometry, so they would get out of sync.
|
||||
|
||||
The reason there are no errors happening in workspace.js with the
|
||||
existing code is that due to a bug in Clutter the fullGeometry of
|
||||
WorkspacesDisplay gets set very early while mapping the WorkspacesViews
|
||||
(because the overviews ControlsManager gets an allocation during the
|
||||
resource scale calculation of a ClutterClone, see
|
||||
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1181), so it
|
||||
won't be set to null anymore when calling
|
||||
WorkspacesView.animateToOverview().
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1119
|
||||
---
|
||||
js/ui/workspacesView.js | 17 ++++++++++-------
|
||||
1 file changed, 10 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
|
||||
index 02baddc6e..3e9d77655 100644
|
||||
--- a/js/ui/workspacesView.js
|
||||
+++ b/js/ui/workspacesView.js
|
||||
@@ -589,13 +589,16 @@ var WorkspacesDisplay = class {
|
||||
|
||||
show(fadeOnPrimary) {
|
||||
this._updateWorkspacesViews();
|
||||
- for (let i = 0; i < this._workspacesViews.length; i++) {
|
||||
- let animationType;
|
||||
- if (fadeOnPrimary && i == this._primaryIndex)
|
||||
- animationType = AnimationType.FADE;
|
||||
- else
|
||||
- animationType = AnimationType.ZOOM;
|
||||
- this._workspacesViews[i].animateToOverview(animationType);
|
||||
+
|
||||
+ if (this._actualGeometry && this._fullGeometry) {
|
||||
+ for (let i = 0; i < this._workspacesViews.length; i++) {
|
||||
+ let animationType;
|
||||
+ if (fadeOnPrimary && i == this._primaryIndex)
|
||||
+ animationType = AnimationType.FADE;
|
||||
+ else
|
||||
+ animationType = AnimationType.ZOOM;
|
||||
+ this._workspacesViews[i].animateToOverview(animationType);
|
||||
+ }
|
||||
}
|
||||
|
||||
this._restackedNotifyId =
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,117 @@
|
||||
From 96ccb155bbe6ce570832a9f3d27a0a08698127ea Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
|
||||
Date: Sat, 28 Mar 2020 14:15:09 +0100
|
||||
Subject: [PATCH 1/3] keyboard: Don't include keyboard devices when updating
|
||||
lastDevice
|
||||
|
||||
We're dealing with attached keyboards now using the touch_mode property
|
||||
of ClutterSeat: If a device has a keyboard attached, the touch-mode is
|
||||
FALSE and we won't automatically show the OSK on touches, also the
|
||||
touch-mode gets set to FALSE when an external keyboard is being plugged
|
||||
in, so that also hides the OSK automatically.
|
||||
|
||||
With that, we can now ignore keyboard devices when updating the last
|
||||
used device and no longer have to special-case our own virtual devices.
|
||||
|
||||
Because there was no special-case for the virtual device we use on
|
||||
Wayland now, this fixes a bug where the keyboard disappeared after
|
||||
touching keys like Enter or Backspace.
|
||||
|
||||
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2287
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1142
|
||||
---
|
||||
js/ui/keyboard.js | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/js/ui/keyboard.js b/js/ui/keyboard.js
|
||||
index c4ac72d..94b5325 100644
|
||||
--- a/js/ui/keyboard.js
|
||||
+++ b/js/ui/keyboard.js
|
||||
@@ -1075,6 +1075,9 @@ var Keyboard = class Keyboard {
|
||||
let device = manager.get_device(deviceId);
|
||||
|
||||
if (device.get_device_name().indexOf('XTEST') < 0) {
|
||||
+ if (device.device_type == Clutter.InputDeviceType.KEYBOARD_DEVICE)
|
||||
+ return;
|
||||
+
|
||||
this._lastDeviceId = deviceId;
|
||||
this._syncEnabled();
|
||||
}
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 3106746ae424287d8644643a2ef46d565e4cd7ed Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
|
||||
Date: Sat, 28 Mar 2020 14:34:24 +0100
|
||||
Subject: [PATCH 2/3] layout: Use translation_y of 0 to hide keyboard
|
||||
|
||||
Since we show the keyboard using a translation_y of -keyboardHeight, the
|
||||
keyboard will be moved down far enough to be out of sight by setting
|
||||
translation_y to 0.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1142
|
||||
---
|
||||
js/ui/layout.js | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/js/ui/layout.js b/js/ui/layout.js
|
||||
index beb4c0a..4382f6e 100644
|
||||
--- a/js/ui/layout.js
|
||||
+++ b/js/ui/layout.js
|
||||
@@ -719,7 +719,7 @@ var LayoutManager = GObject.registerClass({
|
||||
showKeyboard() {
|
||||
this.keyboardBox.show();
|
||||
Tweener.addTween(this.keyboardBox,
|
||||
- { anchor_y: this.keyboardBox.height,
|
||||
+ { translation_y: -this.keyboardBox.height,
|
||||
opacity: 255,
|
||||
time: KEYBOARD_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
@@ -735,7 +735,7 @@ var LayoutManager = GObject.registerClass({
|
||||
this._updateRegions();
|
||||
|
||||
this._keyboardHeightNotifyId = this.keyboardBox.connect('notify::height', () => {
|
||||
- this.keyboardBox.anchor_y = this.keyboardBox.height;
|
||||
+ this.keyboardBox.translation_y = -this.keyboardBox.height;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -745,7 +745,7 @@ var LayoutManager = GObject.registerClass({
|
||||
this._keyboardHeightNotifyId = 0;
|
||||
}
|
||||
Tweener.addTween(this.keyboardBox,
|
||||
- { anchor_y: 0,
|
||||
+ { translation_y: 0,
|
||||
opacity: 0,
|
||||
time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
|
||||
transition: 'easeInQuad',
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 642822308a72be6a47f4eb285f32539499f0d3e4 Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Wed, 21 Oct 2020 20:29:34 +0200
|
||||
Subject: [PATCH 3/3] layout: queue redraw after hiding keyboard
|
||||
|
||||
---
|
||||
js/ui/layout.js | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/js/ui/layout.js b/js/ui/layout.js
|
||||
index 4382f6e..1824313 100644
|
||||
--- a/js/ui/layout.js
|
||||
+++ b/js/ui/layout.js
|
||||
@@ -759,6 +759,7 @@ var LayoutManager = GObject.registerClass({
|
||||
_hideKeyboardComplete() {
|
||||
this.keyboardBox.hide();
|
||||
this._updateRegions();
|
||||
+ global.stage.queue_redraw();
|
||||
}
|
||||
|
||||
// setDummyCursorGeometry:
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,399 @@
|
||||
From 119ec213b8f9a9e55ca340dbde10b0d19becab41 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 5 Dec 2019 14:12:47 +0100
|
||||
Subject: [PATCH 1/4] perf-helper: Add content for custom drawing
|
||||
|
||||
Drawing windows got a lot more involved with the advent of client-side
|
||||
decorations. Instead of accounting for visible and invisible borders,
|
||||
titlebar and shadows when necessary, just add an empty child for the
|
||||
custom drawing.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/887
|
||||
---
|
||||
src/shell-perf-helper.c | 12 ++++++++----
|
||||
1 file changed, 8 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/shell-perf-helper.c b/src/shell-perf-helper.c
|
||||
index e5eab208b..55bdbef02 100644
|
||||
--- a/src/shell-perf-helper.c
|
||||
+++ b/src/shell-perf-helper.c
|
||||
@@ -120,9 +120,9 @@ on_window_map_event (GtkWidget *window,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
-on_window_draw (GtkWidget *window,
|
||||
- cairo_t *cr,
|
||||
- WindowInfo *info)
|
||||
+on_child_draw (GtkWidget *window,
|
||||
+ cairo_t *cr,
|
||||
+ WindowInfo *info)
|
||||
{
|
||||
cairo_rectangle_int_t allocation;
|
||||
double x_offset, y_offset;
|
||||
@@ -204,6 +204,7 @@ create_window (int width,
|
||||
gboolean redraws)
|
||||
{
|
||||
WindowInfo *info;
|
||||
+ GtkWidget *child;
|
||||
|
||||
info = g_new0 (WindowInfo, 1);
|
||||
info->width = width;
|
||||
@@ -219,10 +220,13 @@ create_window (int width,
|
||||
info->pending = TRUE;
|
||||
info->start_time = -1;
|
||||
|
||||
+ child = g_object_new (GTK_TYPE_BOX, "visible", TRUE, "app-paintable", TRUE, NULL);
|
||||
+ gtk_container_add (GTK_CONTAINER (info->window), child);
|
||||
+
|
||||
gtk_widget_set_size_request (info->window, width, height);
|
||||
gtk_widget_set_app_paintable (info->window, TRUE);
|
||||
g_signal_connect (info->window, "map-event", G_CALLBACK (on_window_map_event), info);
|
||||
- g_signal_connect (info->window, "draw", G_CALLBACK (on_window_draw), info);
|
||||
+ g_signal_connect (child, "draw", G_CALLBACK (on_child_draw), info);
|
||||
gtk_widget_show (info->window);
|
||||
|
||||
if (info->redraws)
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From bb4c2acaef4d8fdea50915030c221e1190f704a4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 5 Dec 2019 13:29:38 +0100
|
||||
Subject: [PATCH 2/4] perf-helper: Remove unused atoms
|
||||
|
||||
Those aren't used for anything, but make the helper dependent on X11.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/887
|
||||
---
|
||||
src/shell-perf-helper.c | 18 ------------------
|
||||
1 file changed, 18 deletions(-)
|
||||
|
||||
diff --git a/src/shell-perf-helper.c b/src/shell-perf-helper.c
|
||||
index 55bdbef02..d3280de96 100644
|
||||
--- a/src/shell-perf-helper.c
|
||||
+++ b/src/shell-perf-helper.c
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <math.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
-#include <gdk/gdkx.h>
|
||||
|
||||
#define BUS_NAME "org.gnome.Shell.PerfHelper"
|
||||
|
||||
@@ -60,12 +59,6 @@ static GOptionEntry opt_entries[] =
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
-static Display *xdisplay;
|
||||
-static Window xroot;
|
||||
-static Atom atom_wm_state;
|
||||
-static Atom atom__net_wm_name;
|
||||
-static Atom atom_utf8_string;
|
||||
-
|
||||
static guint timeout_id;
|
||||
static GList *our_windows;
|
||||
static GList *wait_windows_invocations;
|
||||
@@ -351,8 +344,6 @@ on_name_lost (GDBusConnection *connection,
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
- GdkDisplay *display;
|
||||
- GdkScreen *screen;
|
||||
GOptionContext *context;
|
||||
GError *error = NULL;
|
||||
|
||||
@@ -368,15 +359,6 @@ main (int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
- display = gdk_display_get_default ();
|
||||
- screen = gdk_screen_get_default ();
|
||||
-
|
||||
- xdisplay = gdk_x11_display_get_xdisplay (display);
|
||||
- xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen));
|
||||
- atom_wm_state = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
|
||||
- atom__net_wm_name = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME");
|
||||
- atom_utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING");
|
||||
-
|
||||
g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
BUS_NAME,
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From d8b4d72b89340dab46bdcb92ee54bde18dbb9ba9 Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Fourdan <ofourdan@redhat.com>
|
||||
Date: Fri, 24 Jan 2020 10:59:31 +0100
|
||||
Subject: [PATCH 3/4] perf-tool: Spawn perf-tool-helper from gnome-shell
|
||||
|
||||
On Wayland, the display server is the Wayland compositor, i.e.
|
||||
`gnome-shell` itself.
|
||||
|
||||
As a result, we cannot spawn `gnome-shell-perf-helper` before
|
||||
`gnome-shell` is started, as `gnome-shell-perf-helper` needs to connect
|
||||
to the display server.
|
||||
|
||||
So, instead of spawning `gnome-shell-perf-helper` from the perf tool,
|
||||
start it from `gnome-shell` itself.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/941
|
||||
---
|
||||
js/ui/scripting.js | 51 ++++++++++++++++++++++------------
|
||||
src/gnome-shell-perf-tool.in | 53 ------------------------------------
|
||||
2 files changed, 34 insertions(+), 70 deletions(-)
|
||||
|
||||
diff --git a/js/ui/scripting.js b/js/ui/scripting.js
|
||||
index d227b9ef4..eef8f3887 100644
|
||||
--- a/js/ui/scripting.js
|
||||
+++ b/js/ui/scripting.js
|
||||
@@ -3,8 +3,10 @@
|
||||
const { Gio, GLib, Meta, Shell } = imports.gi;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
+const Config = imports.misc.config;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
+const Util = imports.misc.util;
|
||||
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
@@ -73,6 +75,12 @@ function _getPerfHelper() {
|
||||
return _perfHelper;
|
||||
}
|
||||
|
||||
+function _spawnPerfHelper() {
|
||||
+ let path = Config.LIBEXECDIR;
|
||||
+ let command = `${path}/gnome-shell-perf-helper`;
|
||||
+ Util.trySpawnCommandLine(command);
|
||||
+}
|
||||
+
|
||||
function _callRemote(obj, method, ...args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
args.push((result, excp) => {
|
||||
@@ -270,6 +278,25 @@ function _collect(scriptModule, outputFile) {
|
||||
}
|
||||
}
|
||||
|
||||
+async function _runPerfScript(scriptModule, outputFile) {
|
||||
+ for (let step of scriptModule.run()) {
|
||||
+ try {
|
||||
+ await step; // eslint-disable-line no-await-in-loop
|
||||
+ } catch (err) {
|
||||
+ log(`Script failed: ${err}\n${err.stack}`);
|
||||
+ Meta.exit(Meta.ExitCode.ERROR);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ _collect(scriptModule, outputFile);
|
||||
+ } catch (err) {
|
||||
+ log(`Script failed: ${err}\n${err.stack}`);
|
||||
+ Meta.exit(Meta.ExitCode.ERROR);
|
||||
+ }
|
||||
+ Meta.exit(Meta.ExitCode.SUCCESS);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* runPerfScript
|
||||
* @scriptModule: module object with run and finish functions
|
||||
@@ -310,23 +337,13 @@ function _collect(scriptModule, outputFile) {
|
||||
* After running the script and collecting statistics from the
|
||||
* event log, GNOME Shell will exit.
|
||||
**/
|
||||
-async function runPerfScript(scriptModule, outputFile) {
|
||||
+function runPerfScript(scriptModule, outputFile) {
|
||||
Shell.PerfLog.get_default().set_enabled(true);
|
||||
+ _spawnPerfHelper();
|
||||
|
||||
- for (let step of scriptModule.run()) {
|
||||
- try {
|
||||
- await step;
|
||||
- } catch (err) {
|
||||
- log(`Script failed: ${err}\n${err.stack}`);
|
||||
- Meta.exit(Meta.ExitCode.ERROR);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- try {
|
||||
- _collect(scriptModule, outputFile);
|
||||
- } catch (err) {
|
||||
- log(`Script failed: ${err}\n${err.stack}`);
|
||||
- Meta.exit(Meta.ExitCode.ERROR);
|
||||
- }
|
||||
- Meta.exit(Meta.ExitCode.SUCCESS);
|
||||
+ Gio.bus_watch_name(Gio.BusType.SESSION,
|
||||
+ 'org.gnome.Shell.PerfHelper',
|
||||
+ Gio.BusNameWatcherFlags.NONE,
|
||||
+ () => _runPerfScript(scriptModule, outputFile),
|
||||
+ null);
|
||||
}
|
||||
diff --git a/src/gnome-shell-perf-tool.in b/src/gnome-shell-perf-tool.in
|
||||
index f4b48f730..050c66b30 100755
|
||||
--- a/src/gnome-shell-perf-tool.in
|
||||
+++ b/src/gnome-shell-perf-tool.in
|
||||
@@ -24,52 +24,6 @@ def show_version(option, opt_str, value, parser):
|
||||
print("GNOME Shell Performance Test @VERSION@")
|
||||
sys.exit()
|
||||
|
||||
-def wait_for_dbus_name(wait_name):
|
||||
- loop = GLib.MainLoop()
|
||||
-
|
||||
- def on_name_appeared(connection, name, new_owner, *args):
|
||||
- if not (name == wait_name and new_owner != ''):
|
||||
- return
|
||||
- loop.quit()
|
||||
- return
|
||||
-
|
||||
- watch_id = Gio.bus_watch_name(Gio.BusType.SESSION,
|
||||
- wait_name,
|
||||
- Gio.BusNameWatcherFlags.NONE,
|
||||
- on_name_appeared,
|
||||
- None)
|
||||
-
|
||||
- def on_timeout():
|
||||
- print("\nFailed to start %s: timed out" % (wait_name,))
|
||||
- sys.exit(1)
|
||||
- GLib.timeout_add_seconds(7, on_timeout)
|
||||
-
|
||||
- loop.run()
|
||||
- Gio.bus_unwatch_name(watch_id)
|
||||
-
|
||||
-PERF_HELPER_NAME = "org.gnome.Shell.PerfHelper"
|
||||
-PERF_HELPER_IFACE = "org.gnome.Shell.PerfHelper"
|
||||
-PERF_HELPER_PATH = "/org/gnome/Shell/PerfHelper"
|
||||
-
|
||||
-def start_perf_helper():
|
||||
- self_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||
- perf_helper_path = "@libexecdir@/gnome-shell-perf-helper"
|
||||
-
|
||||
- subprocess.Popen([perf_helper_path])
|
||||
- wait_for_dbus_name (PERF_HELPER_NAME)
|
||||
-
|
||||
-def stop_perf_helper():
|
||||
- bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
|
||||
-
|
||||
- proxy = Gio.DBusProxy.new_sync(bus,
|
||||
- Gio.DBusProxyFlags.NONE,
|
||||
- None,
|
||||
- PERF_HELPER_NAME,
|
||||
- PERF_HELPER_PATH,
|
||||
- PERF_HELPER_IFACE,
|
||||
- None)
|
||||
- proxy.Exit()
|
||||
-
|
||||
def start_shell(perf_output=None):
|
||||
# Set up environment
|
||||
env = dict(os.environ)
|
||||
@@ -204,8 +158,6 @@ def run_performance_test():
|
||||
logs = []
|
||||
metric_summaries = {}
|
||||
|
||||
- start_perf_helper()
|
||||
-
|
||||
for i in range(0, iters):
|
||||
# We create an empty temporary file that the shell will overwrite
|
||||
# with the contents.
|
||||
@@ -217,14 +169,12 @@ def run_performance_test():
|
||||
try:
|
||||
normal_exit = run_shell(perf_output=output_file)
|
||||
except:
|
||||
- stop_perf_helper()
|
||||
raise
|
||||
finally:
|
||||
if not normal_exit:
|
||||
os.remove(output_file)
|
||||
|
||||
if not normal_exit:
|
||||
- stop_perf_helper()
|
||||
return False
|
||||
|
||||
try:
|
||||
@@ -232,7 +182,6 @@ def run_performance_test():
|
||||
output = json.load(f)
|
||||
f.close()
|
||||
except:
|
||||
- stop_perf_helper()
|
||||
raise
|
||||
finally:
|
||||
os.remove(output_file)
|
||||
@@ -260,8 +209,6 @@ def run_performance_test():
|
||||
|
||||
logs.append(output['log'])
|
||||
|
||||
- stop_perf_helper()
|
||||
-
|
||||
if options.perf_output or options.perf_upload:
|
||||
# Write a complete report, formatted as JSON. The Javascript/C code that
|
||||
# generates the individual reports we are summarizing here is very careful
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 8090db0f29dc72e602be341d43b3113373404b21 Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Fourdan <ofourdan@redhat.com>
|
||||
Date: Tue, 21 Jan 2020 11:05:58 +0100
|
||||
Subject: [PATCH 4/4] perf-tool: Allow to run as a Wayland compositor
|
||||
|
||||
`gnome-shell-perf-tool` is initially designed to run on X11, using the
|
||||
`--replace` option which does not work when gnome-shell is a Wayland
|
||||
compositor.
|
||||
|
||||
A solution would be to run `gnome-shell-perf-tool` in place of just
|
||||
`gnome-shell` to run the entire perf session under Wayland, but the
|
||||
script `gnome-shell-perf-tool` does not spawn `gnome-shell` as a Wayladn
|
||||
compositor, so that fails as well.
|
||||
|
||||
Add a `--wayland` option to `gnome-shell-perf-tool` so that it can
|
||||
optionally spawn gnome-shell as a Wayland compositor so the whole perf
|
||||
tool can be starred from a console with:
|
||||
|
||||
```
|
||||
$ dbus-run-session -- gnome-shell-perf-tool --wayland
|
||||
```
|
||||
|
||||
Alternatively, for testing purposes, it can also be started nested with:
|
||||
|
||||
```
|
||||
$ dbus-run-session -- gnome-shell-perf-tool --nested
|
||||
```
|
||||
|
||||
Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/2139
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/941
|
||||
---
|
||||
src/gnome-shell-perf-tool.in | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/src/gnome-shell-perf-tool.in b/src/gnome-shell-perf-tool.in
|
||||
index 050c66b30..04072c4cd 100755
|
||||
--- a/src/gnome-shell-perf-tool.in
|
||||
+++ b/src/gnome-shell-perf-tool.in
|
||||
@@ -45,6 +45,13 @@ def start_shell(perf_output=None):
|
||||
if options.replace:
|
||||
args.append('--replace')
|
||||
|
||||
+ if options.wayland or options.nested:
|
||||
+ args.append('--wayland')
|
||||
+ if options.nested:
|
||||
+ args.append('--nested')
|
||||
+ else:
|
||||
+ args.append('--display-server')
|
||||
+
|
||||
return subprocess.Popen(args, env=env)
|
||||
|
||||
def run_shell(perf_output=None):
|
||||
@@ -284,6 +291,10 @@ parser.add_option("", "--version", action="callback", callback=show_version,
|
||||
|
||||
parser.add_option("-r", "--replace", action="store_true",
|
||||
help="Replace the running window manager")
|
||||
+parser.add_option("-w", "--wayland", action="store_true",
|
||||
+ help="Run as a Wayland compositor")
|
||||
+parser.add_option("-n", "--nested", action="store_true",
|
||||
+ help="Run as a Wayland nested compositor")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,71 @@
|
||||
From 45ddeeaa317fb0ffd045600d9e4b95143c9ca8b8 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Clasen <mclasen@redhat.com>
|
||||
Date: Sat, 8 Jun 2013 13:32:35 -0400
|
||||
Subject: [PATCH 1/2] main: Show a warning when running as root
|
||||
|
||||
gnome-session used to show a dialog in this case, but a
|
||||
notification is more natural nowadays. Doing it in gnome-shell
|
||||
avoids complicated synchronization between gnome-session and
|
||||
gnome-shell.
|
||||
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=701212
|
||||
---
|
||||
js/ui/main.js | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index 8d1755cf1..abf8a8765 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -237,6 +237,12 @@ function _initializeUI() {
|
||||
['MESSAGE_ID=' + GNOMESHELL_STARTED_MESSAGE_ID]);
|
||||
}
|
||||
|
||||
+ let credentials = new Gio.Credentials();
|
||||
+ if (credentials.get_unix_user() === 0) {
|
||||
+ notify(_('Logged in as a privileged user'),
|
||||
+ _('Running a session as a privileged user should be avoided for security reasons. If possible, you should log in as a normal user.'));
|
||||
+ }
|
||||
+
|
||||
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
|
||||
if (perfModuleName) {
|
||||
let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT");
|
||||
--
|
||||
2.23.0
|
||||
|
||||
|
||||
From 8e82907909b6a2e5af5da3f93b087df4b7eb48b5 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Clasen <mclasen@redhat.com>
|
||||
Date: Sat, 8 Jun 2013 13:33:58 -0400
|
||||
Subject: [PATCH 2/2] main: Show a warning when gdm is missing
|
||||
|
||||
If we are not running under gdm, some functionaliy (such as
|
||||
the lock screen) does not work, and we should inform the
|
||||
user about this.
|
||||
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=701212
|
||||
---
|
||||
js/ui/main.js | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index abf8a8765..be49c750e 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -243,6 +243,13 @@ function _initializeUI() {
|
||||
_('Running a session as a privileged user should be avoided for security reasons. If possible, you should log in as a normal user.'));
|
||||
}
|
||||
|
||||
+ if (sessionMode.currentMode !== 'gdm' &&
|
||||
+ sessionMode.currentMode !== 'initial-setup' &&
|
||||
+ screenShield === null) {
|
||||
+ notify(_('Screen Lock disabled'),
|
||||
+ _('Screen Locking requires the GNOME display manager.'));
|
||||
+ }
|
||||
+
|
||||
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
|
||||
if (perfModuleName) {
|
||||
let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT");
|
||||
--
|
||||
2.23.0
|
||||
|
@ -0,0 +1,79 @@
|
||||
From d6ead50fe230df58ddab822966d69760b00ec920 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Wed, 1 Apr 2020 14:48:10 +0200
|
||||
Subject: [PATCH 1/2] screenShield: Switch lightboxes off before unlock
|
||||
transition
|
||||
|
||||
There is no point in animating a transition with fullscreen black
|
||||
rectangles stacked on top, so switch them off before rather than
|
||||
after the transition.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1158
|
||||
---
|
||||
js/ui/screenShield.js | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
|
||||
index cd38f11fc8..282f29fa30 100644
|
||||
--- a/js/ui/screenShield.js
|
||||
+++ b/js/ui/screenShield.js
|
||||
@@ -1221,6 +1221,9 @@ var ScreenShield = class {
|
||||
this._isModal = false;
|
||||
}
|
||||
|
||||
+ this._longLightbox.hide();
|
||||
+ this._shortLightbox.hide();
|
||||
+
|
||||
Tweener.addTween(this._lockDialogGroup, {
|
||||
scale_x: 0,
|
||||
scale_y: 0,
|
||||
@@ -1237,8 +1240,6 @@ var ScreenShield = class {
|
||||
this._dialog = null;
|
||||
}
|
||||
|
||||
- this._longLightbox.hide();
|
||||
- this._shortLightbox.hide();
|
||||
this.actor.hide();
|
||||
|
||||
if (this._becameActiveId != 0) {
|
||||
--
|
||||
2.28.0
|
||||
|
||||
|
||||
From 39ac7cad68d8c00d98c900b35add637b01eddbbf Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Tue, 31 Mar 2020 21:07:59 +0200
|
||||
Subject: [PATCH 2/2] screenShield: Wake up on deactivate()
|
||||
|
||||
Usually the screen is woken up before the shield is deactivated, but
|
||||
it is also possible to unlock the session programmatically via the
|
||||
org.gnome.ScreenSaver D-Bus API.
|
||||
|
||||
The intention is very likely not to unlock a turned off screen in
|
||||
that case. Nor does it seem like a good idea to change the lock
|
||||
state without any indication.
|
||||
|
||||
Waking up the screen is more likely to meet expectations and is
|
||||
more reasonable too, so do that.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1158
|
||||
---
|
||||
js/ui/screenShield.js | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
|
||||
index 282f29fa30..2d0a429bee 100644
|
||||
--- a/js/ui/screenShield.js
|
||||
+++ b/js/ui/screenShield.js
|
||||
@@ -1200,6 +1200,8 @@ var ScreenShield = class {
|
||||
if (Main.sessionMode.currentMode == 'unlock-dialog')
|
||||
Main.sessionMode.popMode('unlock-dialog');
|
||||
|
||||
+ this.emit('wake-up-screen');
|
||||
+
|
||||
if (this._isGreeter) {
|
||||
// We don't want to "deactivate" any more than
|
||||
// this. In particular, we don't want to drop
|
||||
--
|
||||
2.28.0
|
||||
|
@ -0,0 +1,279 @@
|
||||
From 37bbb9175bbd061d4ae14e86c35e4211602dbeaa Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Mon, 23 Mar 2020 17:57:38 +0100
|
||||
Subject: [PATCH 1/4] shell/util: Add touch_file_async() helper
|
||||
|
||||
Add a small helper method to asynchronously "touch" a file and return
|
||||
whether the file was created or not.
|
||||
|
||||
As g_file_make_directory_with_parents() doesn't have an async variant,
|
||||
we need a C helper to make the entire operation non-blocking.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/2432
|
||||
---
|
||||
src/shell-util.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
src/shell-util.h | 7 ++++++
|
||||
2 files changed, 69 insertions(+)
|
||||
|
||||
diff --git a/src/shell-util.c b/src/shell-util.c
|
||||
index fa3fc08c8..eec67f3d7 100644
|
||||
--- a/src/shell-util.c
|
||||
+++ b/src/shell-util.c
|
||||
@@ -323,6 +323,68 @@ shell_get_file_contents_utf8_sync (const char *path,
|
||||
return contents;
|
||||
}
|
||||
|
||||
+static void
|
||||
+touch_file (GTask *task,
|
||||
+ gpointer object,
|
||||
+ gpointer task_data,
|
||||
+ GCancellable *cancellable)
|
||||
+{
|
||||
+ GFile *file = object;
|
||||
+ g_autoptr (GFile) parent = NULL;
|
||||
+ g_autoptr (GFileOutputStream) stream = NULL;
|
||||
+ GError *error = NULL;
|
||||
+
|
||||
+ parent = g_file_get_parent (file);
|
||||
+ g_file_make_directory_with_parents (parent, cancellable, &error);
|
||||
+
|
||||
+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
|
||||
+ {
|
||||
+ g_task_return_error (task, error);
|
||||
+ return;
|
||||
+ }
|
||||
+ g_clear_error (&error);
|
||||
+
|
||||
+ stream = g_file_create (file, G_FILE_CREATE_NONE, cancellable, &error);
|
||||
+
|
||||
+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
|
||||
+ {
|
||||
+ g_task_return_error (task, error);
|
||||
+ return;
|
||||
+ }
|
||||
+ g_clear_error (&error);
|
||||
+
|
||||
+ if (stream)
|
||||
+ g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL);
|
||||
+
|
||||
+ g_task_return_boolean (task, stream != NULL);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+shell_util_touch_file_async (GFile *file,
|
||||
+ GAsyncReadyCallback callback,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ g_autoptr (GTask) task = NULL;
|
||||
+
|
||||
+ g_return_if_fail (G_IS_FILE (file));
|
||||
+
|
||||
+ task = g_task_new (file, NULL, callback, user_data);
|
||||
+ g_task_set_source_tag (task, shell_util_touch_file_async);
|
||||
+
|
||||
+ g_task_run_in_thread (task, touch_file);
|
||||
+}
|
||||
+
|
||||
+gboolean
|
||||
+shell_util_touch_file_finish (GFile *file,
|
||||
+ GAsyncResult *res,
|
||||
+ GError **error)
|
||||
+{
|
||||
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
|
||||
+ g_return_val_if_fail (G_IS_TASK (res), FALSE);
|
||||
+
|
||||
+ return g_task_propagate_boolean (G_TASK (res), error);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* shell_util_wifexited:
|
||||
* @status: the status returned by wait() or waitpid()
|
||||
diff --git a/src/shell-util.h b/src/shell-util.h
|
||||
index 02b8404e9..bedf516ba 100644
|
||||
--- a/src/shell-util.h
|
||||
+++ b/src/shell-util.h
|
||||
@@ -32,6 +32,13 @@ gboolean shell_write_string_to_stream (GOutputStream *stream,
|
||||
char *shell_get_file_contents_utf8_sync (const char *path,
|
||||
GError **error);
|
||||
|
||||
+void shell_util_touch_file_async (GFile *file,
|
||||
+ GAsyncReadyCallback callback,
|
||||
+ gpointer user_data);
|
||||
+gboolean shell_util_touch_file_finish (GFile *file,
|
||||
+ GAsyncResult *res,
|
||||
+ GError **error);
|
||||
+
|
||||
gboolean shell_util_wifexited (int status,
|
||||
int *exit);
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
||||
From 1f75494bea1ef7017d50d77cf5c7ad6b9668d4f5 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Mon, 23 Mar 2020 18:00:27 +0100
|
||||
Subject: [PATCH 2/4] environment: Hook up touch_file to GFile prototype
|
||||
|
||||
We don't usually extend introspected types with our own API, but in
|
||||
this case it's too tempting to make the helper functions usable with
|
||||
Gio._promisify() ...
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/2432
|
||||
---
|
||||
js/ui/environment.js | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/environment.js b/js/ui/environment.js
|
||||
index e22ec7402..9c125d3eb 100644
|
||||
--- a/js/ui/environment.js
|
||||
+++ b/js/ui/environment.js
|
||||
@@ -9,7 +9,7 @@ imports.gi.versions.Gtk = '3.0';
|
||||
imports.gi.versions.TelepathyGLib = '0.12';
|
||||
imports.gi.versions.TelepathyLogger = '0.2';
|
||||
|
||||
-const { Clutter, GLib, Shell, St } = imports.gi;
|
||||
+const { Clutter, Gio, GLib, Shell, St } = imports.gi;
|
||||
const Gettext = imports.gettext;
|
||||
|
||||
// We can't import shell JS modules yet, because they may have
|
||||
@@ -97,6 +97,13 @@ function init() {
|
||||
return St.describe_actor(this);
|
||||
};
|
||||
|
||||
+ Gio._LocalFilePrototype.touch_async = function (callback) {
|
||||
+ Shell.util_touch_file_async(this, callback);
|
||||
+ };
|
||||
+ Gio._LocalFilePrototype.touch_finish = function (result) {
|
||||
+ return Shell.util_touch_file_finish(this, result);
|
||||
+ };
|
||||
+
|
||||
let origToString = Object.prototype.toString;
|
||||
Object.prototype.toString = function() {
|
||||
let base = origToString.call(this);
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
||||
From 4bef23c7176a43f4dcf146e70bbb8aaa701b8cd2 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 20 Mar 2020 12:42:04 +0100
|
||||
Subject: [PATCH 3/4] main: Do not warn about missing GDM on each login
|
||||
|
||||
We now warn on startup if screen locking isn't available, however for
|
||||
users who choose not to use GDM or logind, repeating the warning on
|
||||
each login is more annoying than helpful.
|
||||
|
||||
Instead, limit the warning to the first login on which the screen lock
|
||||
became unavailable. That way the notification will still serve the
|
||||
intended purpose of informing the user, but without being perceived
|
||||
as nagging.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/2432
|
||||
---
|
||||
js/ui/main.js | 36 +++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 31 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index 1203b3c39..a3fad158c 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -81,6 +81,9 @@ let _a11ySettings = null;
|
||||
let _themeResource = null;
|
||||
let _oskResource = null;
|
||||
|
||||
+Gio._promisify(Gio._LocalFilePrototype, 'delete_async', 'delete_finish');
|
||||
+Gio._promisify(Gio._LocalFilePrototype, 'touch_async', 'touch_finish');
|
||||
+
|
||||
function _sessionUpdated() {
|
||||
if (sessionMode.isPrimary)
|
||||
_loadDefaultStylesheet();
|
||||
@@ -242,11 +245,8 @@ function _initializeUI() {
|
||||
}
|
||||
|
||||
if (sessionMode.currentMode !== 'gdm' &&
|
||||
- sessionMode.currentMode !== 'initial-setup' &&
|
||||
- screenShield === null) {
|
||||
- notify(_('Screen Lock disabled'),
|
||||
- _('Screen Locking requires the GNOME display manager.'));
|
||||
- }
|
||||
+ sessionMode.currentMode !== 'initial-setup')
|
||||
+ _handleLockScreenWarning();
|
||||
|
||||
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
|
||||
if (perfModuleName) {
|
||||
@@ -257,6 +257,32 @@ function _initializeUI() {
|
||||
});
|
||||
}
|
||||
|
||||
+async function _handleLockScreenWarning() {
|
||||
+ const path = '%s/lock-warning-shown'.format(global.userdatadir);
|
||||
+ const file = Gio.File.new_for_path(path);
|
||||
+
|
||||
+ const hasLockScreen = screenShield !== null;
|
||||
+ if (hasLockScreen) {
|
||||
+ try {
|
||||
+ await file.delete_async(0, null);
|
||||
+ } catch (e) {
|
||||
+ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
|
||||
+ logError(e);
|
||||
+ }
|
||||
+ } else {
|
||||
+ try {
|
||||
+ if (!await file.touch_async())
|
||||
+ return;
|
||||
+ } catch (e) {
|
||||
+ logError(e);
|
||||
+ }
|
||||
+
|
||||
+ notify(
|
||||
+ _('Screen Lock disabled'),
|
||||
+ _('Screen Locking requires the GNOME display manager.'));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
function _getStylesheet(name) {
|
||||
let stylesheet;
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
||||
From c3f34e786826d0ed1af4150190159fed50d9fb87 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 22 Oct 2020 20:11:14 +0200
|
||||
Subject: [PATCH 4/4] messageTray: Default to generic policy
|
||||
|
||||
How and if notifications are shown is controlled by NotificationPolicy
|
||||
objects. But ever since 098bd45, only notification daemon sources or
|
||||
notifications associated with an app are hooked up to GSettings.
|
||||
|
||||
The hardcoded default policy for built-in notifications (including
|
||||
those provided by extensions) arguably made sense back then, but
|
||||
now that the main setting has been rebranded as "Do Not Disturb"
|
||||
and is exposed prominently in the calendar drop-down, following
|
||||
GSettings is a better default.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3291
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1511>
|
||||
---
|
||||
js/ui/messageTray.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
|
||||
index 8f8130451..f6bdae8e4 100644
|
||||
--- a/js/ui/messageTray.js
|
||||
+++ b/js/ui/messageTray.js
|
||||
@@ -731,7 +731,7 @@ var Source = class Source {
|
||||
}
|
||||
|
||||
_createPolicy() {
|
||||
- return new NotificationPolicy();
|
||||
+ return new NotificationGenericPolicy();
|
||||
}
|
||||
|
||||
get narrowestPrivacyScope() {
|
||||
--
|
||||
2.31.1
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue