Compare commits

..

No commits in common. 'c9' and 'i8c-beta' have entirely different histories.
c9 ... i8c-beta

2
.gitignore vendored

@ -1 +1 @@
SOURCES/gnome-shell-40.10.tar.xz
SOURCES/gnome-shell-3.32.2.tar.xz

@ -1 +1 @@
c955a004fb650a83863d1151e3adbbd6758b1c2e SOURCES/gnome-shell-40.10.tar.xz
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

@ -1,25 +0,0 @@
From a8c8b7ef31f7219157b94148b771f6f663928dea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 19 Apr 2022 19:17:48 +0200
Subject: [PATCH] Revert "dash: Subtract vertical margins from availHeight"
This reverts commit 0de0a1f5940784eb4a7ca9ecf5e92f5277ceb0d8.
---
js/ui/dash.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/js/ui/dash.js b/js/ui/dash.js
index f35cc2e25..0f1ca2c4c 100644
--- a/js/ui/dash.js
+++ b/js/ui/dash.js
@@ -610,7 +610,6 @@ var Dash = GObject.registerClass({
(iconChildren.length - 1) * spacing;
let availHeight = this._maxHeight;
- availHeight -= this.margin_top + this.margin_bottom;
availHeight -= this._background.get_theme_node().get_vertical_padding();
availHeight -= themeNode.get_vertical_padding();
availHeight -= buttonHeight - iconHeight;
--
2.35.1

@ -1,364 +0,0 @@
From 678cdd9e0da851da78527fa827d71a80273510b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@redhat.com>
Date: Tue, 8 Feb 2022 14:18:04 -0500
---
data/theme/gnome-shell-high-contrast.css | 36 ++++++++++++++++++++++++
data/theme/gnome-shell.css | 36 ++++++++++++++++++++++++
2 files changed, 72 insertions(+)
diff --git a/data/theme/gnome-shell-high-contrast.css b/data/theme/gnome-shell-high-contrast.css
index b73f407..90f363c 100644
--- a/data/theme/gnome-shell-high-contrast.css
+++ b/data/theme/gnome-shell-high-contrast.css
@@ -1223,60 +1223,63 @@ StScrollBar {
-panel-corner-border-color: transparent;
-panel-corner-opacity: 1;
transition-duration: 250ms; }
#panel .panel-button {
font-weight: bold;
color: #ddd;
-natural-hpadding: 12px;
-minimum-hpadding: 6px;
transition-duration: 150ms;
border: 3px solid transparent;
border-radius: 99px; }
#panel .panel-button.clock-display .clock {
transition-duration: 150ms;
border: 3px solid transparent;
border-radius: 99px; }
#panel .panel-button:hover, #panel .panel-button:active, #panel .panel-button:overview, #panel .panel-button:focus, #panel .panel-button:checked {
box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.2); }
#panel .panel-button.clock-display:hover, #panel .panel-button.clock-display:active, #panel .panel-button.clock-display:overview, #panel .panel-button.clock-display:focus, #panel .panel-button.clock-display:checked {
box-shadow: none; }
#panel .panel-button.clock-display:hover .clock, #panel .panel-button.clock-display:active .clock, #panel .panel-button.clock-display:overview .clock, #panel .panel-button.clock-display:focus .clock, #panel .panel-button.clock-display:checked .clock {
box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.2); }
#panel .panel-button .system-status-icon {
icon-size: 1.09em;
padding: 5px;
margin: 0 4px; }
#panel .panel-button .panel-status-indicators-box .system-status-icon,
#panel .panel-button .panel-status-menu-box .system-status-icon {
margin: 0; }
#panel .panel-button .app-menu-icon {
-st-icon-style: symbolic; }
+ #panel .panel-button .panel-logo-icon {
+ padding-right: .4em;
+ icon-size: 1em; }
#panel #panelActivities.panel-button {
-natural-hpadding: 18px; }
#panel.unlock-screen .panel-button:hover, #panel.unlock-screen .panel-button:active, #panel.unlock-screen .panel-button:overview, #panel.unlock-screen .panel-button:focus, #panel.unlock-screen .panel-button:checked, #panel.login-screen .panel-button:hover, #panel.login-screen .panel-button:active, #panel.login-screen .panel-button:overview, #panel.login-screen .panel-button:focus, #panel.login-screen .panel-button:checked, #panel:overview .panel-button:hover, #panel:overview .panel-button:active, #panel:overview .panel-button:overview, #panel:overview .panel-button:focus, #panel:overview .panel-button:checked {
box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.15); }
#panel.unlock-screen .panel-button.clock-display:hover, #panel.unlock-screen .panel-button.clock-display:active, #panel.unlock-screen .panel-button.clock-display:overview, #panel.unlock-screen .panel-button.clock-display:focus, #panel.unlock-screen .panel-button.clock-display:checked, #panel.login-screen .panel-button.clock-display:hover, #panel.login-screen .panel-button.clock-display:active, #panel.login-screen .panel-button.clock-display:overview, #panel.login-screen .panel-button.clock-display:focus, #panel.login-screen .panel-button.clock-display:checked, #panel:overview .panel-button.clock-display:hover, #panel:overview .panel-button.clock-display:active, #panel:overview .panel-button.clock-display:overview, #panel:overview .panel-button.clock-display:focus, #panel:overview .panel-button.clock-display:checked {
box-shadow: none; }
#panel.unlock-screen .panel-button.clock-display:hover .clock, #panel.unlock-screen .panel-button.clock-display:active .clock, #panel.unlock-screen .panel-button.clock-display:overview .clock, #panel.unlock-screen .panel-button.clock-display:focus .clock, #panel.unlock-screen .panel-button.clock-display:checked .clock, #panel.login-screen .panel-button.clock-display:hover .clock, #panel.login-screen .panel-button.clock-display:active .clock, #panel.login-screen .panel-button.clock-display:overview .clock, #panel.login-screen .panel-button.clock-display:focus .clock, #panel.login-screen .panel-button.clock-display:checked .clock, #panel:overview .panel-button.clock-display:hover .clock, #panel:overview .panel-button.clock-display:active .clock, #panel:overview .panel-button.clock-display:overview .clock, #panel:overview .panel-button.clock-display:focus .clock, #panel:overview .panel-button.clock-display:checked .clock {
box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.15); }
#panel .panel-status-indicators-box,
#panel .panel-status-menu-box {
spacing: 2px; }
#panel .power-status.panel-status-indicators-box {
spacing: 0; }
#panel .screencast-indicator,
#panel .remote-access-indicator {
color: #f57900; }
#appMenu {
spacing: 6px; }
#appMenu .label-shadow {
color: transparent; }
#appMenu .panel-status-menu-box {
padding: 0 6px;
spacing: 6px; }
/* Activities Ripple */
.ripple-box {
background-color: rgba(158, 196, 235, 0.3);
box-shadow: 0 0 2px 2px #4a90d9;
@@ -2039,74 +2042,107 @@ StScrollBar {
width: 2.18em;
height: 2.18em;
border-color: #202020;
background-color: #202020; }
.login-dialog .cancel-button StIcon,
.login-dialog .switch-user-button StIcon,
.login-dialog .login-dialog-session-list-button StIcon,
.unlock-dialog .cancel-button StIcon,
.unlock-dialog .switch-user-button StIcon,
.unlock-dialog .login-dialog-session-list-button StIcon {
icon-size: 1.09em; }
.login-dialog .caps-lock-warning-label,
.login-dialog .login-dialog-message-warning,
.unlock-dialog .caps-lock-warning-label,
.unlock-dialog .login-dialog-message-warning {
color: #eeeeec; }
.login-dialog-logo-bin {
padding: 24px 0px; }
.login-dialog-banner {
color: #d6d6d1; }
.login-dialog-button-box {
width: 23em;
spacing: 5px; }
.login-dialog-message {
text-align: center; }
+.login-dialog-message-hint, .login-dialog-message {
+ color: #bebeb6;
+ min-height: 2.75em; }
+
.login-dialog-user-selection-box {
padding: 100px 0px; }
.login-dialog-not-listed-label {
padding-left: 2px; }
.login-dialog-not-listed-button:focus .login-dialog-not-listed-label, .login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
color: #eeeeec; }
.login-dialog-not-listed-label {
font-size: 10pt;
font-weight: bold;
color: #a6a69b;
padding-top: 1em; }
+.login-dialog-auth-list-view {
+ -st-vfade-offset: 1em; }
+
+.login-dialog-auth-list {
+ spacing: 6px;
+ margin-left: 2em; }
+
+.login-dialog-auth-list-title {
+ margin-left: 2em; }
+
+.login-dialog-auth-list-item {
+ border-radius: 12px;
+ padding: 6px;
+ color: #a6a69b; }
+ .login-dialog-auth-list-item:focus, .login-dialog-auth-list-item:selected {
+ background-color: #215d9c;
+ color: #ffffff; }
+
+.login-dialog-auth-list-label {
+ font-size: 13pt;
+ font-weight: bold;
+ padding-left: 15px; }
+ .login-dialog-auth-list-label:ltr {
+ padding-left: 14px;
+ text-align: left; }
+ .login-dialog-auth-list-label:rtl {
+ padding-right: 14px;
+ text-align: right; }
+
.login-dialog-user-list-view {
-st-vfade-offset: 1em; }
.login-dialog-user-list {
spacing: 12px;
width: 23em; }
.login-dialog-user-list:expanded .login-dialog-user-list-item:selected {
background-color: #215d9c;
color: #ffffff; }
.login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in {
border-right: 2px solid #215d9c; }
.login-dialog-user-list-item {
border-radius: 12px;
padding: 6px;
color: #a6a69b; }
.login-dialog-user-list-item:ltr .user-widget {
padding-right: 1em; }
.login-dialog-user-list-item:rtl .user-widget {
padding-left: 1em; }
.login-dialog-user-list-item .login-dialog-timed-login-indicator {
height: 2px;
margin-top: 6px;
background-color: #eeeeec; }
.login-dialog-user-list-item:focus .login-dialog-timed-login-indicator {
background-color: #ffffff; }
.user-widget-label {
color: #eeeeec; }
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index f93819b..d3d7fc8 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -1223,60 +1223,63 @@ StScrollBar {
-panel-corner-border-color: transparent;
-panel-corner-opacity: 1;
transition-duration: 250ms; }
#panel .panel-button {
font-weight: bold;
color: #ddd;
-natural-hpadding: 12px;
-minimum-hpadding: 6px;
transition-duration: 150ms;
border: 3px solid transparent;
border-radius: 99px; }
#panel .panel-button.clock-display .clock {
transition-duration: 150ms;
border: 3px solid transparent;
border-radius: 99px; }
#panel .panel-button:hover, #panel .panel-button:active, #panel .panel-button:overview, #panel .panel-button:focus, #panel .panel-button:checked {
box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.2); }
#panel .panel-button.clock-display:hover, #panel .panel-button.clock-display:active, #panel .panel-button.clock-display:overview, #panel .panel-button.clock-display:focus, #panel .panel-button.clock-display:checked {
box-shadow: none; }
#panel .panel-button.clock-display:hover .clock, #panel .panel-button.clock-display:active .clock, #panel .panel-button.clock-display:overview .clock, #panel .panel-button.clock-display:focus .clock, #panel .panel-button.clock-display:checked .clock {
box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.2); }
#panel .panel-button .system-status-icon {
icon-size: 1.09em;
padding: 5px;
margin: 0 4px; }
#panel .panel-button .panel-status-indicators-box .system-status-icon,
#panel .panel-button .panel-status-menu-box .system-status-icon {
margin: 0; }
#panel .panel-button .app-menu-icon {
-st-icon-style: symbolic; }
+ #panel .panel-button .panel-logo-icon {
+ padding-right: .4em;
+ icon-size: 1em; }
#panel #panelActivities.panel-button {
-natural-hpadding: 18px; }
#panel.unlock-screen .panel-button:hover, #panel.unlock-screen .panel-button:active, #panel.unlock-screen .panel-button:overview, #panel.unlock-screen .panel-button:focus, #panel.unlock-screen .panel-button:checked, #panel.login-screen .panel-button:hover, #panel.login-screen .panel-button:active, #panel.login-screen .panel-button:overview, #panel.login-screen .panel-button:focus, #panel.login-screen .panel-button:checked, #panel:overview .panel-button:hover, #panel:overview .panel-button:active, #panel:overview .panel-button:overview, #panel:overview .panel-button:focus, #panel:overview .panel-button:checked {
box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.15); }
#panel.unlock-screen .panel-button.clock-display:hover, #panel.unlock-screen .panel-button.clock-display:active, #panel.unlock-screen .panel-button.clock-display:overview, #panel.unlock-screen .panel-button.clock-display:focus, #panel.unlock-screen .panel-button.clock-display:checked, #panel.login-screen .panel-button.clock-display:hover, #panel.login-screen .panel-button.clock-display:active, #panel.login-screen .panel-button.clock-display:overview, #panel.login-screen .panel-button.clock-display:focus, #panel.login-screen .panel-button.clock-display:checked, #panel:overview .panel-button.clock-display:hover, #panel:overview .panel-button.clock-display:active, #panel:overview .panel-button.clock-display:overview, #panel:overview .panel-button.clock-display:focus, #panel:overview .panel-button.clock-display:checked {
box-shadow: none; }
#panel.unlock-screen .panel-button.clock-display:hover .clock, #panel.unlock-screen .panel-button.clock-display:active .clock, #panel.unlock-screen .panel-button.clock-display:overview .clock, #panel.unlock-screen .panel-button.clock-display:focus .clock, #panel.unlock-screen .panel-button.clock-display:checked .clock, #panel.login-screen .panel-button.clock-display:hover .clock, #panel.login-screen .panel-button.clock-display:active .clock, #panel.login-screen .panel-button.clock-display:overview .clock, #panel.login-screen .panel-button.clock-display:focus .clock, #panel.login-screen .panel-button.clock-display:checked .clock, #panel:overview .panel-button.clock-display:hover .clock, #panel:overview .panel-button.clock-display:active .clock, #panel:overview .panel-button.clock-display:overview .clock, #panel:overview .panel-button.clock-display:focus .clock, #panel:overview .panel-button.clock-display:checked .clock {
box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.15); }
#panel .panel-status-indicators-box,
#panel .panel-status-menu-box {
spacing: 2px; }
#panel .power-status.panel-status-indicators-box {
spacing: 0; }
#panel .screencast-indicator,
#panel .remote-access-indicator {
color: #f57900; }
#appMenu {
spacing: 6px; }
#appMenu .label-shadow {
color: transparent; }
#appMenu .panel-status-menu-box {
padding: 0 6px;
spacing: 6px; }
/* Activities Ripple */
.ripple-box {
background-color: rgba(188, 214, 246, 0.3);
box-shadow: 0 0 2px 2px #629fea;
@@ -2039,74 +2042,107 @@ StScrollBar {
width: 2.18em;
height: 2.18em;
border-color: #202020;
background-color: #202020; }
.login-dialog .cancel-button StIcon,
.login-dialog .switch-user-button StIcon,
.login-dialog .login-dialog-session-list-button StIcon,
.unlock-dialog .cancel-button StIcon,
.unlock-dialog .switch-user-button StIcon,
.unlock-dialog .login-dialog-session-list-button StIcon {
icon-size: 1.09em; }
.login-dialog .caps-lock-warning-label,
.login-dialog .login-dialog-message-warning,
.unlock-dialog .caps-lock-warning-label,
.unlock-dialog .login-dialog-message-warning {
color: #eeeeec; }
.login-dialog-logo-bin {
padding: 24px 0px; }
.login-dialog-banner {
color: #d6d6d1; }
.login-dialog-button-box {
width: 23em;
spacing: 5px; }
.login-dialog-message {
text-align: center; }
+.login-dialog-message-hint, .login-dialog-message {
+ color: #bebeb6;
+ min-height: 2.75em; }
+
.login-dialog-user-selection-box {
padding: 100px 0px; }
.login-dialog-not-listed-label {
padding-left: 2px; }
.login-dialog-not-listed-button:focus .login-dialog-not-listed-label, .login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
color: #eeeeec; }
.login-dialog-not-listed-label {
font-size: 10pt;
font-weight: bold;
color: #a6a69b;
padding-top: 1em; }
+.login-dialog-auth-list-view {
+ -st-vfade-offset: 1em; }
+
+.login-dialog-auth-list {
+ spacing: 6px;
+ margin-left: 2em; }
+
+.login-dialog-auth-list-title {
+ margin-left: 2em; }
+
+.login-dialog-auth-list-item {
+ border-radius: 12px;
+ padding: 6px;
+ color: #a6a69b; }
+ .login-dialog-auth-list-item:focus, .login-dialog-auth-list-item:selected {
+ background-color: #1b6acb;
+ color: #fff; }
+
+.login-dialog-auth-list-label {
+ font-size: 13pt;
+ font-weight: bold;
+ padding-left: 15px; }
+ .login-dialog-auth-list-label:ltr {
+ padding-left: 14px;
+ text-align: left; }
+ .login-dialog-auth-list-label:rtl {
+ padding-right: 14px;
+ text-align: right; }
+
.login-dialog-user-list-view {
-st-vfade-offset: 1em; }
.login-dialog-user-list {
spacing: 12px;
width: 23em; }
.login-dialog-user-list:expanded .login-dialog-user-list-item:selected {
background-color: #1b6acb;
color: #fff; }
.login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in {
border-right: 2px solid #1b6acb; }
.login-dialog-user-list-item {
border-radius: 12px;
padding: 6px;
color: #a6a69b; }
.login-dialog-user-list-item:ltr .user-widget {
padding-right: 1em; }
.login-dialog-user-list-item:rtl .user-widget {
padding-left: 1em; }
.login-dialog-user-list-item .login-dialog-timed-login-indicator {
height: 2px;
margin-top: 6px;
background-color: #eeeeec; }
.login-dialog-user-list-item:focus .login-dialog-timed-login-indicator {
background-color: #fff; }
.user-widget-label {
color: #eeeeec; }
--
2.34.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

@ -1,4 +1,4 @@
From afa3fc7be62cf70c9f6c6954e9cf5b49581269fb Mon Sep 17 00:00:00 2001
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
@ -11,10 +11,10 @@ a .desktop file ...
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shell-app.c b/src/shell-app.c
index 62ba2ec73..dc0e1c732 100644
index 10efa9135..7d40186c9 100644
--- a/src/shell-app.c
+++ b/src/shell-app.c
@@ -293,7 +293,7 @@ shell_app_get_name (ShellApp *app)
@@ -259,7 +259,7 @@ shell_app_get_name (ShellApp *app)
const char *name = NULL;
if (window)
@ -24,5 +24,5 @@ index 62ba2ec73..dc0e1c732 100644
name = C_("program", "Unknown");
return name;
--
2.31.1
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

@ -1,100 +0,0 @@
From ec802e39a5dfb252e2d18b8cb95f713724180565 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 15 May 2023 10:48:15 -0400
Subject: [PATCH] authPrompt: Disregard smartcard status changes events if
VERIFICATION_IN_PROGRESS
commit c8bb45b41c3a13ef161103f649aa18938e028a70 introduced a new
verification state, VERIFICATION_IN_PROGRESS, to detect when the user
has already interacted with the authentication service, so the auth
prompt can rate limit the number of times the user can cancel
authentication attempts with the escape key (without also rate limiting
the number of times they hit escape to go back to the clock without
interacting with the authentication service).
That means there are now two states that represent the
user actively undergoing verification: VERIFYING and
VERIFICATION_IN_PROGRESS.
It's inappropriate to reset the smartcard service if the user is
actively conversing with it. We try to check for that by looking at the
original verification state, VERIFYING, but we unfortunately, neglected
to account for the new VERIFICATION_IN_PROGRESS state.
This commit fixes that oversight, and allows users to again pre-type
their smartcard pin at the clock before inserting their smartcard.
---
js/gdm/authPrompt.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
index 4da91e096..e961f396e 100644
--- a/js/gdm/authPrompt.js
+++ b/js/gdm/authPrompt.js
@@ -327,61 +327,62 @@ var AuthPrompt = GObject.registerClass({
_onShowChoiceList(userVerifier, serviceName, promptMessage, choiceList) {
if (this._queryingService)
this.clear();
this._queryingService = serviceName;
if (this._preemptiveAnswer)
this._preemptiveAnswer = null;
this.setChoiceList(promptMessage, choiceList);
this.updateSensitivity(true);
this.emit('prompted');
}
_onCredentialManagerAuthenticated() {
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
this.reset();
}
_onSmartcardStatusChanged() {
this.smartcardDetected = this._userVerifier.smartcardDetected;
// Most of the time we want to reset if the user inserts or removes
// a smartcard. Smartcard insertion "preempts" what the user was
// doing, and smartcard removal aborts the preemption.
// The exceptions are: 1) Don't reset on smartcard insertion if we're already verifying
// with a smartcard
// 2) Don't reset if we've already succeeded at verification and
// the user is getting logged in.
if (this._userVerifier.serviceIsDefault(GdmUtil.SMARTCARD_SERVICE_NAME) &&
- this.verificationStatus == AuthPromptStatus.VERIFYING &&
+ (this.verificationStatus === AuthPromptStatus.VERIFYING ||
+ this.verificationStatus === AuthPromptStatus.VERIFICATION_IN_PROGRESS) &&
this.smartcardDetected)
return;
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
this.reset();
}
_onShowMessage(_userVerifier, serviceName, message, type) {
this.setMessage(serviceName, message, type);
this.emit('prompted');
}
_onVerificationFailed(userVerifier, serviceName, canRetry) {
const wasQueryingService = this._queryingService === serviceName;
if (wasQueryingService) {
this._queryingService = null;
this.clear();
}
this.updateSensitivity(canRetry);
this.setActorInDefaultButtonWell(null);
if (!canRetry)
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
if (wasQueryingService)
Util.wiggle(this._entry);
}
--
2.39.1

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

@ -1,36 +0,0 @@
From c18b7b7819f17f5d14be1ba2760653f3d93b81b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 1 Feb 2021 18:26:00 +0100
Subject: [PATCH] extensionDownloader: Refuse to override system extensions
The website allows to "update" system extensions by installing the
upstream version into the user's home directory.
Prevent that by refusing to download and install extensions that are
already installed system-wide.
---
js/ui/extensionDownloader.js | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js
index 6a3b2b488..471ddab14 100644
--- a/js/ui/extensionDownloader.js
+++ b/js/ui/extensionDownloader.js
@@ -17,6 +17,14 @@ var REPOSITORY_URL_UPDATE = 'https://extensions.gnome.org/update-info/';
let _httpSession;
function installExtension(uuid, invocation) {
+ const oldExt = Main.extensionManager.lookup(uuid);
+ if (oldExt && oldExt.type === ExtensionUtils.ExtensionType.SYSTEM) {
+ log('extensionDownloader: Trying to replace system extension %s'.format(uuid));
+ invocation.return_dbus_error('org.gnome.Shell.InstallError',
+ 'System extensions cannot be replaced');
+ return;
+ }
+
let params = { uuid,
shell_version: Config.PACKAGE_VERSION };
--
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

@ -1,92 +0,0 @@
From 91449e6a19af63eebaf5f97f85ba44f69259075a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sat, 10 Feb 2024 00:58:27 +0100
Subject: [PATCH] extensionSystem: Support locking down extension installation
Currently extensions can only be locked down completely by
restricting the `enabled-extensions` key via dconf.
This is too restrictive for environments that want to allow users
to customize their system with extensions, while still limiting
the set of possible extensions.
To fill that gap, add a new `allow-extension-installation` setting,
which restricts extensions to system extensions when disabled.
As the setting is mainly intended for locking down by system
administrators, there is no attempt to load/unload extensions
on settings changes.
---
data/org.gnome.shell.gschema.xml.in | 11 +++++++++++
js/ui/extensionDownloader.js | 6 ++++++
js/ui/extensionSystem.js | 8 ++++++--
3 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
index 6f1c424bad..b5921983cd 100644
--- a/data/org.gnome.shell.gschema.xml.in
+++ b/data/org.gnome.shell.gschema.xml.in
@@ -40,6 +40,17 @@
the “enabled-extension” setting.
</description>
</key>
+ <key name="allow-extension-installation" type="b">
+ <default>true</default>
+ <summary>Allow extension installation</summary>
+ <description>
+ Allow users to install extensions in their home folder. If disabled,
+ the InstallRemoteExtension D-Bus method will fail, and extensions
+ are only loaded from system directories on startup.
+ It does not affect extensions that are already loaded, so a change
+ only takes full effect on the next login.
+ </description>
+ </key>
<key name="disable-extension-version-validation" type="b">
<default>false</default>
<summary>Disables the validation of extension version compatibility</summary>
diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js
index 471ddab147..01ed165c01 100644
--- a/js/ui/extensionDownloader.js
+++ b/js/ui/extensionDownloader.js
@@ -17,6 +17,12 @@ var REPOSITORY_URL_UPDATE = 'https://extensions.gnome.org/update-info/';
let _httpSession;
function installExtension(uuid, invocation) {
+ if (!global.settings.get_boolean('allow-extension-installation')) {
+ invocation.return_dbus_error('org.gnome.Shell.InstallError',
+ 'Extension installation is not allowed');
+ return;
+ }
+
const oldExt = Main.extensionManager.lookup(uuid);
if (oldExt && oldExt.type === ExtensionUtils.ExtensionType.SYSTEM) {
log('extensionDownloader: Trying to replace system extension %s'.format(uuid));
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index 937f861994..528d9ea450 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -64,7 +64,10 @@ var ExtensionManager = class {
get updatesSupported() {
const appSys = Shell.AppSystem.get_default();
- return appSys.lookup_app('org.gnome.Extensions.desktop') !== null;
+ const hasUpdatesApp =
+ appSys.lookup_app('org.gnome.Extensions.desktop') !== null;
+ const allowed = global.settings.get_boolean('allow-extension-installation');
+ return allowed && hasUpdatesApp;
}
lookup(uuid) {
@@ -595,7 +598,8 @@ var ExtensionManager = class {
this._enabledExtensions = this._getEnabledExtensions();
let perUserDir = Gio.File.new_for_path(global.userdatadir);
- FileUtils.collectFromDatadirs('extensions', true, (dir, info) => {
+ const includeUserDir = global.settings.get_boolean('allow-extension-installation');
+ FileUtils.collectFromDatadirs('extensions', includeUserDir, (dir, info) => {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
return;
--
2.43.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

@ -1,51 +0,0 @@
From eea9b9a0dac494698a64892bab8d042e7d623c9f Mon Sep 17 00:00:00 2001
From: Cenk Uluisik <cenk.uluisik@googlemail.com>
Date: Sun, 6 Mar 2022 19:32:48 +0100
Subject: [PATCH] introspect: Add WindowsChanged signal
The screencast portal supports recording a single window,
and presents a list of open windows when that option is
selected. To allow updating that list when windows are
opened or closed, add a new "WindowsChanged" signal that
the portal can listen to.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2229>
---
data/dbus-interfaces/org.gnome.Shell.Introspect.xml | 6 ++++++
js/misc/introspect.js | 3 +++
2 files changed, 9 insertions(+)
diff --git a/data/dbus-interfaces/org.gnome.Shell.Introspect.xml b/data/dbus-interfaces/org.gnome.Shell.Introspect.xml
index 47fd7efdc2..cb19cfec56 100644
--- a/data/dbus-interfaces/org.gnome.Shell.Introspect.xml
+++ b/data/dbus-interfaces/org.gnome.Shell.Introspect.xml
@@ -18,6 +18,12 @@
-->
<signal name="RunningApplicationsChanged" />
+ <!--
+ WindowsChanged:
+ @short_description: Notifies when any window opens or closes
+ -->
+ <signal name="WindowsChanged" />
+
<!--
GetRunningApplications:
@short_description: Retrieves the description of all running applications
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
index 45eee81ce3..8916804e7f 100644
--- a/js/misc/introspect.js
+++ b/js/misc/introspect.js
@@ -42,6 +42,9 @@ var IntrospectService = class {
this._syncRunningApplications();
});
+ tracker.connect('tracked-windows-changed',
+ () => this._dbusImpl.emit_signal('WindowsChanged', null));
+
this._syncRunningApplications();
this._senderChecker = new DBusSenderChecker(APP_ALLOWLIST);
--
2.38.1

@ -1,33 +0,0 @@
From b73a07c20a522b3be0e096625c21d5606bcb7d82 Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Mon, 21 Jun 2021 16:32:50 -0300
Subject: [PATCH] introspect: Allowlist GNOME portal
It too implements app listing and introspection, so list it in the
allowlist.
Part-of:
<https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1894>
---
js/misc/introspect.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
index f3c938af9..45eee81ce 100644
--- a/js/misc/introspect.js
+++ b/js/misc/introspect.js
@@ -1,7 +1,10 @@
/* exported IntrospectService */
const { Gio, GLib, Meta, Shell, St } = imports.gi;
-const APP_ALLOWLIST = ['org.freedesktop.impl.portal.desktop.gtk'];
+const APP_ALLOWLIST = [
+ 'org.freedesktop.impl.portal.desktop.gtk',
+ 'org.freedesktop.impl.portal.desktop.gnome',
+];
const INTROSPECT_DBUS_API_VERSION = 3;
--
2.38.1

@ -1,51 +0,0 @@
From bd4fef8354ff0730c1e96a47d77adbb4a4d7beaa Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Tue, 14 Jun 2022 16:38:27 +0200
Subject: [PATCH] kbdA11yDialog: Use MetaKeyboardA11yFlags
The change in mutter to move keyboard accessibility into backends needs
to be applied in gnome-shell as well, otherwise the keyboard
accessibility dialog cannot work.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2306
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2334>
---
js/ui/kbdA11yDialog.js | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/js/ui/kbdA11yDialog.js b/js/ui/kbdA11yDialog.js
index a45e02443..60ec161a6 100644
--- a/js/ui/kbdA11yDialog.js
+++ b/js/ui/kbdA11yDialog.js
@@ -1,5 +1,5 @@
/* exported KbdA11yDialog */
-const { Clutter, Gio, GObject } = imports.gi;
+const { Clutter, Gio, GObject, Meta } = imports.gi;
const Dialog = imports.ui.dialog;
const ModalDialog = imports.ui.modalDialog;
@@ -25,17 +25,17 @@ class KbdA11yDialog extends GObject.Object {
let title, description;
let key, enabled;
- if (whatChanged & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) {
+ if (whatChanged & Meta.KeyboardA11yFlags.SLOW_KEYS_ENABLED) {
key = KEY_SLOW_KEYS_ENABLED;
- enabled = (newFlags & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) > 0;
+ enabled = (newFlags & Meta.KeyboardA11yFlags.SLOW_KEYS_ENABLED) > 0;
title = enabled
? _("Slow Keys Turned On")
: _("Slow Keys Turned Off");
description = _('You just held down the Shift key for 8 seconds. This is the shortcut ' +
'for the Slow Keys feature, which affects the way your keyboard works.');
- } else if (whatChanged & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) {
+ } else if (whatChanged & Meta.KeyboardA11yFlags.STICKY_KEYS_ENABLED) {
key = KEY_STICKY_KEYS_ENABLED;
- enabled = (newFlags & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) > 0;
+ enabled = (newFlags & Meta.KeyboardA11yFlags.STICKY_KEYS_ENABLED) > 0;
title = enabled
? _("Sticky Keys Turned On")
: _("Sticky Keys Turned Off");
--
2.36.1

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

@ -1,4 +1,4 @@
From 5aeb97faee1aba8f6d4cc2c613691a7e2c880ccc Mon Sep 17 00:00:00 2001
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
@ -8,16 +8,17 @@ 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>
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 70ece6cab..c6712459a 100644
index beb4c0a5d..bb51946b7 100644
--- a/js/ui/layout.js
+++ b/js/ui/layout.js
@@ -649,18 +649,17 @@ var LayoutManager = GObject.registerClass({
@@ -624,20 +624,19 @@ var LayoutManager = GObject.registerClass({
reactive: true });
this.addChrome(this._coverPane);
@ -36,6 +37,8 @@ index 70ece6cab..c6712459a 100644
} 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();

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

@ -1,4 +1,4 @@
From 4ad30b5c506ab043c2091441021b6cf334e2412f Mon Sep 17 00:00:00 2001
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
@ -6,78 +6,27 @@ Subject: [PATCH] loginDialog: make info messages themed
They were lacking a definition before leading them to
show up invisible.
---
data/theme/gnome-shell-sass/widgets/_login-dialog.scss | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss
index 1789beca9..84539342d 100644
--- a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss
+++ b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss
@@ -66,60 +66,64 @@
border-color: darken($selected_bg_color, 10%);
background-color: darken($selected_bg_color, 10%);
color: transparentize($selected_fg_color, 0.3);
}
}
}
.cancel-button,
.switch-user-button,
.login-dialog-session-list-button {
padding: 0;
border-radius: 99px;
width: $base_icon_size * 2;
height: $base_icon_size * 2;
border-color: darken($system_bg_color, 3%);
background-color: darken($system_bg_color, 3%);
StIcon { icon-size: $base_icon_size; }
}
.caps-lock-warning-label,
.login-dialog-message-warning {
color: $osd_fg_color;
}
}
.login-dialog-logo-bin { padding: 24px 0px; }
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 { width: 23em; spacing: 5px; }
.login-dialog-message { text-align: center; }
+.login-dialog-message-hint, .login-dialog-message {
.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;
.login-dialog-not-listed-button:focus &,
.login-dialog-not-listed-button:hover & {
color: $osd_fg_color;
}
}
.login-dialog-not-listed-label {
@include fontsize($base_font_size - 1);
font-weight: bold;
color: darken($osd_fg_color,30%);
padding-top: 1em;
}
.login-dialog-user-list-view { -st-vfade-offset: 1em; }
.login-dialog-user-list {
spacing: 12px;
width: 23em;
&:expanded .login-dialog-user-list-item:selected { background-color: $selected_bg_color; color: $selected_fg_color; }
&:expanded .login-dialog-user-list-item:logged-in { border-right: 2px solid $selected_bg_color; }
}
.login-dialog-user-list-item {
border-radius: $base_border_radius + 4px;
padding: 6px;
color: darken($osd_fg_color,30%);
&:ltr .user-widget { padding-right: 1em; }
&:rtl .user-widget { padding-left: 1em; }
--
2.34.1
2.21.0

@ -1,148 +0,0 @@
From ea7e7acd45e428cc17306de2bf65730c90d7e118 Mon Sep 17 00:00:00 2001
From: Sebastian Keller <skeller@gnome.org>
Date: Mon, 23 May 2022 23:01:23 +0200
Subject: [PATCH] magnifier: Request window-relative coordinates for
focus/caret events
Absolute screen coordinates are impossible for Wayland clients to
provide, because the clients don't know where the window is positioned.
Some clients, such as the ones using GTK 3 were providing window
relative coordinates even when screen coordinates were requested,
while others, such as GTK 4 clients, were just returning an error for
caret events or also window-relative coordinates for focus events.
So for this to work on Wayland we have to request window-relative
coordinates and translate them to the current focus window.
To ensure the correct coordinates, we have to only consider events
coming from the current focus window. All other events are filtered out
now. As a side effect this also fixes the magnifier always jumping
to a terminal cursor whenever there was some output, even if the window
was not focused.
This also needs some special handling for events coming from the shell
itself, which should not be translated to the focus window either. As
another side effect this fixes another bug that was caused by these
events already including scaling and getting scaled again.
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5509
Part-of:
<https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2301>
---
js/ui/magnifier.js | 77 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 70 insertions(+), 7 deletions(-)
diff --git a/js/ui/magnifier.js b/js/ui/magnifier.js
index 4c2e88f1a..9813664be 100644
--- a/js/ui/magnifier.js
+++ b/js/ui/magnifier.js
@@ -789,21 +789,81 @@ var ZoomRegion = class ZoomRegion {
}
}
+ _convertExtentsToScreenSpace(accessible, extents) {
+ const toplevelWindowTypes = new Set([
+ Atspi.Role.FRAME,
+ Atspi.Role.DIALOG,
+ Atspi.Role.WINDOW,
+ ]);
+
+ try {
+ let app = null;
+ let parentWindow = null;
+ let iter = accessible;
+ while (iter) {
+ if (iter.get_role() === Atspi.Role.APPLICATION) {
+ app = iter;
+ /* This is the last Accessible we are interested in */
+ break;
+ } else if (toplevelWindowTypes.has(iter.get_role())) {
+ parentWindow = iter;
+ }
+ iter = iter.get_parent();
+ }
+
+ /* We don't want to translate our own events to the focus window.
+ * They are also already scaled by clutter before being sent, so
+ * we don't need to do that here either. */
+ if (app && app.get_name() === 'gnome-shell')
+ return extents;
+
+ /* Only events from the focused widget of the focused window. Some
+ * widgets seem to claim to have focus when the window does not so
+ * check both. */
+ const windowActive = parentWindow &&
+ parentWindow.get_state_set().contains(Atspi.StateType.ACTIVE);
+ const accessibleFocused =
+ accessible.get_state_set().contains(Atspi.StateType.FOCUSED);
+ if (!windowActive || !accessibleFocused)
+ return null;
+ } catch (e) {
+ throw new Error(`Failed to validate parent window: ${e}`);
+ }
+
+ const focusWindowRect = global.display.focus_window?.get_frame_rect();
+ if (!focusWindowRect)
+ return null;
+
+ const scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
+ const screenSpaceExtents = new Atspi.Rect({
+ x: focusWindowRect.x + (scaleFactor * extents.x),
+ y: focusWindowRect.y + (scaleFactor * extents.y),
+ width: scaleFactor * extents.width,
+ height: scaleFactor * extents.height,
+ });
+
+ return screenSpaceExtents;
+ }
+
_updateFocus(caller, event) {
let component = event.source.get_component_iface();
if (!component || event.detail1 != 1)
return;
let extents;
try {
- extents = component.get_extents(Atspi.CoordType.SCREEN);
+ extents = component.get_extents(Atspi.CoordType.WINDOW);
+ extents = this._convertExtentsToScreenSpace(event.source, extents);
+ if (!extents)
+ return;
} catch (e) {
log(`Failed to read extents of focused component: ${e.message}`);
return;
}
- let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
- let [xFocus, yFocus] = [(extents.x + (extents.width / 2)) * scaleFactor,
- (extents.y + (extents.height / 2)) * scaleFactor];
+ const [xFocus, yFocus] = [
+ extents.x + (extents.width / 2),
+ extents.y + (extents.height / 2),
+ ];
if (this._xFocus !== xFocus || this._yFocus !== yFocus) {
[this._xFocus, this._yFocus] = [xFocus, yFocus];
@@ -817,14 +877,17 @@ var ZoomRegion = class ZoomRegion {
return;
let extents;
try {
- extents = text.get_character_extents(text.get_caret_offset(), 0);
+ extents = text.get_character_extents(text.get_caret_offset(),
+ Atspi.CoordType.WINDOW);
+ extents = this._convertExtentsToScreenSpace(text, extents);
+ if (!extents)
+ return;
} catch (e) {
log(`Failed to read extents of text caret: ${e.message}`);
return;
}
- let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
- let [xCaret, yCaret] = [extents.x * scaleFactor, extents.y * scaleFactor];
+ const [xCaret, yCaret] = [extents.x, extents.y];
// Ignore event(s) if the caret size is none (0x0). This happens a lot if
// the cursor offset can't be translated into a location. This is a work
--
2.38.1

@ -1,4 +1,4 @@
From f54c3f9f66001c210e10fda6aa17b9218fb67dc1 Mon Sep 17 00:00:00 2001
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
@ -8,10 +8,10 @@ Subject: [PATCH] main: Dump stack on segfaults by default
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/main.c b/src/main.c
index 5d07a4301..ed0b78dcc 100644
index 245837783..788309de7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -38,6 +38,7 @@ static int caught_signal = 0;
@@ -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
@ -19,7 +19,7 @@ index 5d07a4301..ed0b78dcc 100644
enum {
SHELL_DEBUG_BACKTRACE_WARNINGS = 1,
SHELL_DEBUG_BACKTRACE_SEGFAULTS = 2,
@@ -279,8 +280,11 @@ shell_init_debug (const char *debug_env)
@@ -268,8 +269,11 @@ shell_init_debug (const char *debug_env)
{ "backtrace-segfaults", SHELL_DEBUG_BACKTRACE_SEGFAULTS },
};
@ -34,5 +34,5 @@ index 5d07a4301..ed0b78dcc 100644
static void
--
2.31.1
2.29.2

@ -1,31 +0,0 @@
From a9e79b1657dc7c1b702d7acc4d322539d2b8b6aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 6 Oct 2021 10:00:43 +0200
Subject: [PATCH] main: Leak the GJS context and ShellGlobal
There are many crash-on-exit happening as a side effect of destroying
the GJS context. Work around these until we have a better solution by
leaking them.
---
src/main.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/main.c b/src/main.c
index 91e5493fd1..d62dda9627 100644
--- a/src/main.c
+++ b/src/main.c
@@ -508,9 +508,11 @@ main (int argc, char **argv)
ecode = meta_run ();
shell_profiler_shutdown ();
+#if 0
g_debug ("Doing final cleanup");
_shell_global_destroy_gjs_context (shell_global_get ());
g_object_unref (shell_global_get ());
+#endif
return ecode;
}
--
2.31.1

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

@ -1,281 +0,0 @@
From be3a2303cf9ed4077955aaa9fae1fc4cbe2da277 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 24 Jan 2023 17:49:24 +0100
Subject: [PATCH] =?UTF-8?q?osk-layouts:=20Replace=20"SS"=20extra=20key=20w?=
=?UTF-8?q?ith=20"=E1=BA=9E"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The on-screen keyboard only handles a single keyval per key, so the
current upper-case version of the German "ß" ends up as "S" instead
of the expected "SS".
It is possible to change the keyboard code to emulate multiple key
presses/releases for that particular case, but then luckily a proper
upper-case form exists nowadays: "ẞ".
That seems more appropriate for a single key than a dedicated "SS"
key, so replace it in all layouts that include it. Anybody who prefers
the traditional "SS" can easily tap "S" twice.
Part-of:
<https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2612>
---
data/osk-layouts/cz.json | 2 +-
data/osk-layouts/de.json | 2 +-
data/osk-layouts/dk.json | 2 +-
data/osk-layouts/ee.json | 2 +-
data/osk-layouts/epo.json | 2 +-
data/osk-layouts/fi.json | 2 +-
data/osk-layouts/hr.json | 2 +-
data/osk-layouts/ke.json | 2 +-
data/osk-layouts/lt.json | 2 +-
data/osk-layouts/lv.json | 2 +-
data/osk-layouts/no.json | 2 +-
data/osk-layouts/pl.json | 2 +-
data/osk-layouts/ro.json | 2 +-
data/osk-layouts/se.json | 2 +-
data/osk-layouts/sk.json | 2 +-
data/osk-layouts/tr.json | 2 +-
data/osk-layouts/uk.json | 2 +-
data/osk-layouts/us.json | 2 +-
18 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/data/osk-layouts/cz.json b/data/osk-layouts/cz.json
index 9bad07402..526cb9cb6 100644
--- a/data/osk-layouts/cz.json
+++ b/data/osk-layouts/cz.json
@@ -246,7 +246,7 @@
[
"S",
"Š",
- "SS",
+ "ẞ",
"Ś"
],
[
diff --git a/data/osk-layouts/de.json b/data/osk-layouts/de.json
index 751a85603..3b1cb34b2 100644
--- a/data/osk-layouts/de.json
+++ b/data/osk-layouts/de.json
@@ -208,7 +208,7 @@
],
[
"S",
- "SS",
+ "ẞ",
"Ś",
"Š"
],
diff --git a/data/osk-layouts/dk.json b/data/osk-layouts/dk.json
index 80df9ae65..7bc6feaf3 100644
--- a/data/osk-layouts/dk.json
+++ b/data/osk-layouts/dk.json
@@ -218,7 +218,7 @@
],
[
"S",
- "SS",
+ "ẞ",
"Ś",
"Š"
],
diff --git a/data/osk-layouts/ee.json b/data/osk-layouts/ee.json
index 5fd2f11fa..b42b0afc9 100644
--- a/data/osk-layouts/ee.json
+++ b/data/osk-layouts/ee.json
@@ -281,7 +281,7 @@
[
"S",
"Š",
- "SS",
+ "ẞ",
"Ś",
"Ş"
],
diff --git a/data/osk-layouts/epo.json b/data/osk-layouts/epo.json
index 71f9ef8d9..d7257625f 100644
--- a/data/osk-layouts/epo.json
+++ b/data/osk-layouts/epo.json
@@ -316,7 +316,7 @@
],
[
"S",
- "SS",
+ "ẞ",
"Š",
"Ś",
"Ș",
diff --git a/data/osk-layouts/fi.json b/data/osk-layouts/fi.json
index 3ba5b567c..d664b0ec5 100644
--- a/data/osk-layouts/fi.json
+++ b/data/osk-layouts/fi.json
@@ -200,7 +200,7 @@
[
"S",
"Š",
- "SS",
+ "ẞ",
"Ś"
],
[
diff --git a/data/osk-layouts/hr.json b/data/osk-layouts/hr.json
index ff0d1d09a..e4977796a 100644
--- a/data/osk-layouts/hr.json
+++ b/data/osk-layouts/hr.json
@@ -168,7 +168,7 @@
"S",
"Š",
"Ś",
- "SS"
+ "ẞ"
],
[
"D",
diff --git a/data/osk-layouts/ke.json b/data/osk-layouts/ke.json
index 9c3e93565..2bd5b09d0 100644
--- a/data/osk-layouts/ke.json
+++ b/data/osk-layouts/ke.json
@@ -217,7 +217,7 @@
],
[
"S",
- "SS"
+ "ẞ"
],
[
"D"
diff --git a/data/osk-layouts/lt.json b/data/osk-layouts/lt.json
index 7cd5352a8..a43ff9146 100644
--- a/data/osk-layouts/lt.json
+++ b/data/osk-layouts/lt.json
@@ -270,7 +270,7 @@
[
"S",
"Š",
- "SS",
+ "ẞ",
"Ś",
"Ş"
],
diff --git a/data/osk-layouts/lv.json b/data/osk-layouts/lv.json
index bab6ae3d7..d72c93c25 100644
--- a/data/osk-layouts/lv.json
+++ b/data/osk-layouts/lv.json
@@ -268,7 +268,7 @@
[
"S",
"Š",
- "SS",
+ "ẞ",
"Ś",
"Ş"
],
diff --git a/data/osk-layouts/no.json b/data/osk-layouts/no.json
index a70be9ca0..0df786853 100644
--- a/data/osk-layouts/no.json
+++ b/data/osk-layouts/no.json
@@ -218,7 +218,7 @@
],
[
"S",
- "SS",
+ "ẞ",
"Ś",
"Š"
],
diff --git a/data/osk-layouts/pl.json b/data/osk-layouts/pl.json
index 4b08cd5d3..8583bd64c 100644
--- a/data/osk-layouts/pl.json
+++ b/data/osk-layouts/pl.json
@@ -212,7 +212,7 @@
[
"S",
"Ś",
- "SS",
+ "ẞ",
"Š"
],
[
diff --git a/data/osk-layouts/ro.json b/data/osk-layouts/ro.json
index c690f4ecd..8d4676126 100644
--- a/data/osk-layouts/ro.json
+++ b/data/osk-layouts/ro.json
@@ -188,7 +188,7 @@
[
"S",
"Ș",
- "SS",
+ "ẞ",
"Ś",
"Š"
],
diff --git a/data/osk-layouts/se.json b/data/osk-layouts/se.json
index 513a0b897..0ebb756e7 100644
--- a/data/osk-layouts/se.json
+++ b/data/osk-layouts/se.json
@@ -245,7 +245,7 @@
"Ś",
"Š",
"Ş",
- "SS"
+ "ẞ"
],
[
"D",
diff --git a/data/osk-layouts/sk.json b/data/osk-layouts/sk.json
index 678232b82..a74ad0b61 100644
--- a/data/osk-layouts/sk.json
+++ b/data/osk-layouts/sk.json
@@ -269,7 +269,7 @@
[
"S",
"Š",
- "SS",
+ "ẞ",
"Ś",
"Ş"
],
diff --git a/data/osk-layouts/tr.json b/data/osk-layouts/tr.json
index b3786cc88..8243aafad 100644
--- a/data/osk-layouts/tr.json
+++ b/data/osk-layouts/tr.json
@@ -202,7 +202,7 @@
[
"S",
"Ş",
- "SS",
+ "ẞ",
"Ś",
"Š"
],
diff --git a/data/osk-layouts/uk.json b/data/osk-layouts/uk.json
index c36a723a0..19f5aa6d9 100644
--- a/data/osk-layouts/uk.json
+++ b/data/osk-layouts/uk.json
@@ -216,7 +216,7 @@
],
[
"S",
- "SS"
+ "ẞ"
],
[
"D"
diff --git a/data/osk-layouts/us.json b/data/osk-layouts/us.json
index 94dd6d3ad..dd0cd368f 100644
--- a/data/osk-layouts/us.json
+++ b/data/osk-layouts/us.json
@@ -216,7 +216,7 @@
],
[
"S",
- "SS"
+ "ẞ"
],
[
"D"
--
2.38.1

@ -0,0 +1,38 @@
From 2ddb51234ca69c0e637b35071b4e760d1b72527a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Mon, 24 Feb 2020 11:19:28 +0100
Subject: [PATCH] overview: Hide the overview on session mode hasOverview
changes
If the sessionMode does not allow to show the overview, we should also
hide an already visible overview.
This fixes a bug where, if the lockscreen was shown while the overview
was visible, the Ctrl+Alt+Tab popup would allow navigating inside the
overview because the overview actor is still mapped.
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/1043
---
js/ui/overview.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/js/ui/overview.js b/js/ui/overview.js
index 5bad4cbd62..03cecb6dbc 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -196,7 +196,11 @@ var Overview = class {
}
_sessionUpdated() {
- this.isDummy = !Main.sessionMode.hasOverview;
+ const { hasOverview } = Main.sessionMode;
+ if (!hasOverview)
+ this.hide();
+
+ this.isDummy = !hasOverview;
this._createOverview();
}
--
2.43.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

@ -1,20 +1,20 @@
From b5db4d318546654f4e9c1e4999fa00456441f105 Mon Sep 17 00:00:00 2001
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/widgets/_panel.scss | 5 +++++
js/ui/panel.js | 11 ++++++++++-
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/data/theme/gnome-shell-sass/widgets/_panel.scss b/data/theme/gnome-shell-sass/widgets/_panel.scss
index 1f4650773..5f323cbc8 100644
--- a/data/theme/gnome-shell-sass/widgets/_panel.scss
+++ b/data/theme/gnome-shell-sass/widgets/_panel.scss
@@ -85,6 +85,11 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
// dimensions of the icon are hardcoded
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 {
@ -22,35 +22,33 @@ index 1f4650773..5f323cbc8 100644
+ icon-size: 1em;
+ }
+
&#panelActivities {
-natural-hpadding: $base_padding * 3;
&:hover {
color: lighten($fg_color, 10%);
}
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 1474886ef..ad11f4ba2 100644
index 16484850a..ede1c2b82 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -390,11 +390,20 @@ class ActivitiesButton extends PanelMenu.Button {
this.name = 'panelActivities';
+ const box = new St.BoxLayout();
+ this.add_child(box);
+ const iconFile = Gio.File.new_for_path('/usr/share/icons/hicolor/scalable/apps/start-here.svg');
+ this._icon = new St.Icon({
+ gicon: new Gio.FileIcon({ file: iconFile }),
+ style_class: 'panel-logo-icon',
+ });
+ box.add_child(this._icon);
@@ -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.add_actor(this._label);
+ box.add_child(this._label);
- this.actor.add_actor(this._label);
+ box.add_actor(this._label);
this.label_actor = this._label;
this.actor.label_actor = this._label;
--
2.31.1
2.21.0

File diff suppressed because it is too large Load Diff

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

@ -1,4 +1,4 @@
From 1e4e9248ef6bcdd95ec3b91c8c8e94c4587a876b Mon Sep 17 00:00:00 2001
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
@ -13,21 +13,21 @@ action to get the screen to unblank.
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
index 9a64fc32c..bc1a0fba7 100644
index a005a206b..cd38f11fc 100644
--- a/js/ui/screenShield.js
+++ b/js/ui/screenShield.js
@@ -85,8 +85,10 @@ var ScreenShield = class {
@@ -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._activateDialog();
this._liftShield(true, 0);
+ }
});
this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
--
2.31.1
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

@ -1,56 +0,0 @@
From b1be295de28f45762a525d3ad3f91729295a7511 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@redhat.com>
Date: Fri, 18 Oct 2024 13:20:23 +0200
Subject: [PATCH] shell/window-tracker: Help mutter finding app info's for
windows
---
src/shell-window-tracker.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/src/shell-window-tracker.c b/src/shell-window-tracker.c
index bc14040d9b..8fbcca4269 100644
--- a/src/shell-window-tracker.c
+++ b/src/shell-window-tracker.c
@@ -651,6 +651,20 @@ shell_window_tracker_on_n_workspaces_changed (MetaWorkspaceManager *workspace_ma
}
}
+static GAppInfo *
+on_find_app_info (MetaDisplay *display,
+ MetaWindow *window,
+ ShellWindowTracker *tracker)
+{
+ g_autoptr (ShellApp) app = NULL;
+
+ app = get_app_for_window (tracker, window);
+ if (!app)
+ return NULL;
+
+ return g_object_ref (G_APP_INFO (shell_app_get_app_info (app)));
+}
+
static void
init_window_tracking (ShellWindowTracker *self)
{
@@ -665,6 +679,17 @@ init_window_tracking (ShellWindowTracker *self)
g_signal_connect(display, "window-created",
G_CALLBACK (on_window_created), self);
+ if (g_signal_lookup ("find-app-info", META_TYPE_DISPLAY))
+ {
+ g_debug ("Mutter app finding with the help of gnome-shell");
+ g_signal_connect (display, "find-app-info",
+ G_CALLBACK (on_find_app_info), self);
+ }
+ else
+ {
+ g_debug ("No mutter app finding with the help of gnome-shell");
+ }
+
shell_window_tracker_on_n_workspaces_changed (workspace_manager, NULL, self);
}
--
2.44.0.501.g19981daefd.dirty

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

@ -1,36 +0,0 @@
From 187b851530f5e76786784ec9df235304c8ddede8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 4 Aug 2021 19:46:34 +0200
Subject: [PATCH] st/icon: Only get resource-scale after peeking theme node
If an actor is not on any stage view, then it doesn't have a valid
resource scale, which will hit an assert later.
When that is the case (for example when running headless), we expect
that there is no valid theme node (yet) either, so simply moving
the clutter_actor_get_resource_scale() call after peeking at the
theme node is enough to avoid the crash.
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4522
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1935>
---
src/st/st-icon.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/st/st-icon.c b/src/st/st-icon.c
index 0405d85259..e4d6e05f94 100644
--- a/src/st/st-icon.c
+++ b/src/st/st-icon.c
@@ -462,6 +462,8 @@ st_icon_update (StIcon *icon)
resource_scale = clutter_actor_get_resource_scale (CLUTTER_ACTOR (icon));
+ resource_scale = clutter_actor_get_resource_scale (CLUTTER_ACTOR (icon));
+
stage = clutter_actor_get_stage (CLUTTER_ACTOR (icon));
context = st_theme_context_get_for_stage (CLUTTER_STAGE (stage));
g_object_get (context, "scale-factor", &paint_scale, NULL);
--
2.31.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

@ -1,58 +0,0 @@
From 7e94d682985ac4ff422da73b5878f4f005eff67b Mon Sep 17 00:00:00 2001
From: Mohammed Sadiq <sadiq@sadiqpk.org>
Date: Tue, 10 Aug 2021 15:22:30 +0530
Subject: [PATCH] status/network: Use wwan settings panel for GSM/LTE Modems
GSM/UMTS/LTE modems now have better support with wwan panel in GNOME
Settings. So, if the modem supports, open wwan panel, otherwise
fallback to opening network panel when "Mobile Broadband Settings"
item is clicked.
See https://gitlab.gnome.org/GNOME/gnome-control-center/-/merge_requests/583
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1942>
---
js/ui/status/network.js | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
index f510f90ae..fe82fcb08 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -543,7 +543,11 @@ var NMDeviceModem = class extends NMConnectionDevice {
constructor(client, device) {
super(client, device);
- this.item.menu.addSettingsAction(_("Mobile Broadband Settings"), 'gnome-network-panel.desktop');
+ const settingsPanel = this._useWwanPanel()
+ ? 'gnome-wwan-panel.desktop'
+ : 'gnome-network-panel.desktop';
+
+ this.item.menu.addSettingsAction(_('Mobile Broadband Settings'), settingsPanel);
this._mobileDevice = null;
@@ -573,8 +577,19 @@ var NMDeviceModem = class extends NMConnectionDevice {
return NMConnectionCategory.WWAN;
}
+ _useWwanPanel() {
+ // Currently, wwan panel doesn't support CDMA_EVDO modems
+ const supportedCaps =
+ NM.DeviceModemCapabilities.GSM_UMTS |
+ NM.DeviceModemCapabilities.LTE;
+ return this._device.current_capabilities & supportedCaps;
+ }
+
_autoConnect() {
- launchSettingsPanel('network', 'connect-3g', this._device.get_path());
+ if (this._useWwanPanel())
+ launchSettingsPanel('wwan', 'show-device', this._device.udi);
+ else
+ launchSettingsPanel('network', 'connect-3g', this._device.get_path());
}
_sessionUpdated() {
--
2.31.1

@ -1,4 +1,4 @@
From b212b973175be1cbefa1da2c5ed4f58fae032c73 Mon Sep 17 00:00:00 2001
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
@ -14,17 +14,17 @@ controls.
1 file changed, 1 insertion(+)
diff --git a/js/ui/status/volume.js b/js/ui/status/volume.js
index 7164e1054..f623ee680 100644
index d555b426e..ab5065683 100644
--- a/js/ui/status/volume.js
+++ b/js/ui/status/volume.js
@@ -34,6 +34,7 @@ var StreamSlider = class {
@@ -30,6 +30,7 @@ var StreamSlider = class {
this._control = control;
this.item = new PopupMenu.PopupBaseMenuItem({ activate: false });
+ this.item.hide();
+ this.item.actor.hide();
this._slider = new Slider.Slider(0);
this._inDrag = false;
this._notifyVolumeChangeId = 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

@ -1,38 +0,0 @@
From 79049292451b9bb23ad92c572a438585ca37246b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 27 Oct 2021 15:18:20 +0200
Subject: [PATCH] welcomeDialog: Adapt dialog title
Use RHEL branding instead of the upstream GNOME XX one.
---
js/ui/welcomeDialog.js | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/js/ui/welcomeDialog.js b/js/ui/welcomeDialog.js
index 9d99f0035..783fd1108 100644
--- a/js/ui/welcomeDialog.js
+++ b/js/ui/welcomeDialog.js
@@ -1,9 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported WelcomeDialog */
-const { Clutter, GObject, Shell, St } = imports.gi;
+const { Clutter, GLib, GObject, Shell, St } = imports.gi;
-const Config = imports.misc.config;
const Dialog = imports.ui.dialog;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
@@ -32,8 +31,7 @@ class WelcomeDialog extends ModalDialog.ModalDialog {
}
_buildLayout() {
- const [majorVersion] = Config.PACKAGE_VERSION.split('.');
- const title = _('Welcome to GNOME %s').format(majorVersion);
+ const title = _('Welcome to %s').format(GLib.get_os_info('NAME'));
const description = _('If you want to learn your way around, check out the tour.');
const content = new Dialog.MessageDialogContent({ title, description });
--
2.33.1

@ -1,64 +0,0 @@
From a1d650ce2722fd154b047ce73fa23db205d823d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Mon, 12 Dec 2022 13:04:11 +0100
Subject: [PATCH] window-tracker: Emit 'tracked-windows-changed' on title
changes
This means the screen share window view gets updated also when the title
of a window changes. This is important since it often changes shortly
after mapping, which would otherwise go unnoticed by
xdg-desktop-portal-gnome.
An example is launching Files and it showing up as 'Loading..', or
launching a terminal, and it not showing the proper title (current
directory), but some place holder that is never visible on the
application window.
Adding it to the window tracker instead of in introspect.js itself is
for convenience - there is no per window signal tracking there, and it
already listens to the signal emissions about changed windows.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2578>
---
src/shell-window-tracker.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/shell-window-tracker.c b/src/shell-window-tracker.c
index 991613ea3f..df357f81b7 100644
--- a/src/shell-window-tracker.c
+++ b/src/shell-window-tracker.c
@@ -524,6 +524,15 @@ on_wm_class_changed (MetaWindow *window,
tracked_window_changed (self, window);
}
+static void
+on_title_changed (MetaWindow *window,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ ShellWindowTracker *self = SHELL_WINDOW_TRACKER (user_data);
+ tracked_window_changed (self, window);
+}
+
static void
on_gtk_application_id_changed (MetaWindow *window,
GParamSpec *pspec,
@@ -554,6 +563,7 @@ track_window (ShellWindowTracker *self,
g_hash_table_insert (self->window_to_app, window, app);
g_signal_connect (window, "notify::wm-class", G_CALLBACK (on_wm_class_changed), self);
+ g_signal_connect (window, "notify::title", G_CALLBACK (on_title_changed), self);
g_signal_connect (window, "notify::gtk-application-id", G_CALLBACK (on_gtk_application_id_changed), self);
g_signal_connect (window, "unmanaged", G_CALLBACK (on_window_unmanaged), self);
@@ -586,6 +596,7 @@ disassociate_window (ShellWindowTracker *self,
_shell_app_remove_window (app, window);
g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_wm_class_changed), self);
+ g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_title_changed), self);
g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_gtk_application_id_changed), self);
g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_window_unmanaged), self);
--
2.38.1

@ -1,44 +0,0 @@
From e3823964957ba4dcc86b21db09b280b9299bc8cc Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Fri, 10 Feb 2023 15:07:50 +0100
Subject: [PATCH] window-tracker: Only emit ::tracked-windows-changed on title
changes
Since commit a1d650ce27, window title changes are listened for in the
ShellWindowTracker in order to emit ::tracked-windows-changed when
there are window title changes.
The rest of the things that happen in between (removing the window
from a ShellApp, possibly have it destroyed, and possibly creating a
new ShellApp to re-insert the window) are superfluous and even result
in the altTab switcher popup ending up confused about the applications
available.
Only emit the signal so changes can be followed on D-Bus, but avoid
the ShellApp fiddling otherwise.
Fixes: a1d650ce27 - window-tracker: Emit 'tracked-windows-changed' on title changes
Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6385
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2634>
(cherry picked from commit 41c91c7a3b7f186720a0a518ef2211cb744421f3)
---
src/shell-window-tracker.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shell-window-tracker.c b/src/shell-window-tracker.c
index bc14040d9b..01143dfd7f 100644
--- a/src/shell-window-tracker.c
+++ b/src/shell-window-tracker.c
@@ -524,7 +524,7 @@ on_title_changed (MetaWindow *window,
gpointer user_data)
{
ShellWindowTracker *self = SHELL_WINDOW_TRACKER (user_data);
- tracked_window_changed (self, window);
+ g_signal_emit (self, signals[TRACKED_WINDOWS_CHANGED], 0);
}
static void
--
2.31.1

@ -1,4 +1,4 @@
From 34a7bfdade939e39c2a01cc1b0737a7bdccddd5b Mon Sep 17 00:00:00 2001
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
@ -13,10 +13,10 @@ are used.
1 file changed, 17 insertions(+)
diff --git a/js/ui/windowMenu.js b/js/ui/windowMenu.js
index bb6a8df7b..3449f759d 100644
index 628f145ea..f8eb4398c 100644
--- a/js/ui/windowMenu.js
+++ b/js/ui/windowMenu.js
@@ -116,6 +116,23 @@ var WindowMenu = class extends PopupMenu.PopupMenu {
@@ -115,6 +115,23 @@ var WindowMenu = class extends PopupMenu.PopupMenu {
window.change_workspace(workspace.get_neighbor(dir));
});
}
@ -41,5 +41,5 @@ index bb6a8df7b..3449f759d 100644
}
--
2.31.1
2.21.0

@ -1,4 +1,4 @@
From b3cac57511575e1265ab0ebd9c7465a6ade913e8 Mon Sep 17 00:00:00 2001
From e1eb24fdf731af8736cdb76dc28aa2b10679aa5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 28 Sep 2023 14:34:24 +0200
Subject: [PATCH] windowMenu: Ignore release
@ -10,10 +10,10 @@ until explicitly dismissed, regardless of the pointer position.
1 file changed, 1 insertion(+)
diff --git a/js/ui/windowMenu.js b/js/ui/windowMenu.js
index 3449f759da..ad5c2a74cc 100644
index f8eb4398c3..2ec11c7879 100644
--- a/js/ui/windowMenu.js
+++ b/js/ui/windowMenu.js
@@ -229,6 +229,7 @@ var WindowMenuManager = class {
@@ -205,6 +205,7 @@ var WindowMenuManager = class {
let menu = new WindowMenu(window, this._sourceActor);
this._manager.addMenu(menu);

@ -1,46 +0,0 @@
From 1cad6c8d47fb9f0b17a2c47f93e5f923d1cb32c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 7 Mar 2024 18:22:32 +0100
Subject: [PATCH] windowPreview: Override with window icon if available
---
js/ui/windowPreview.js | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/js/ui/windowPreview.js b/js/ui/windowPreview.js
index e67ec9ec0f..db325258b4 100644
--- a/js/ui/windowPreview.js
+++ b/js/ui/windowPreview.js
@@ -123,6 +123,12 @@ var WindowPreview = GObject.registerClass({
const tracker = Shell.WindowTracker.get_default();
const app = tracker.get_window_app(this.metaWindow);
this._icon = app.create_icon_texture(ICON_SIZE);
+ // Override with window icon if available
+ if (this._hasWindowIcon()) {
+ const textureCache = St.TextureCache.get_default();
+ this._icon.gicon = textureCache.bind_cairo_surface_property(
+ this.metaWindow, 'icon');
+ }
this._icon.add_style_class_name('icon-dropshadow');
this._icon.set({
reactive: true,
@@ -226,6 +232,16 @@ var WindowPreview = GObject.registerClass({
});
}
+ _hasWindowIcon() {
+ // HACK: GI cannot handle CairoSurface, so this
+ // will throw if the icon property is non-null
+ try {
+ return this.metaWindow.icon !== null;
+ } catch (e) {
+ return true;
+ }
+ }
+
_updateIconScale() {
const { ControlsState } = OverviewControls;
const { currentState, initialState, finalState } =
--
2.44.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

@ -1,7 +1,7 @@
From 483f0340bb64767bd8d6d95788058270dfdb5def Mon Sep 17 00:00:00 2001
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] st-texture-cache: purge on resume
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.
@ -12,10 +12,10 @@ so the texture cache needs to evict all textures in that situation.
3 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/js/ui/main.js b/js/ui/main.js
index 979fcefa5..dbf3a32d3 100644
index 061303cf3..8d1755cf1 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -249,7 +249,11 @@ function _initializeUI() {
@@ -200,7 +200,11 @@ function _initializeUI() {
return true;
});
@ -29,10 +29,10 @@ index 979fcefa5..dbf3a32d3 100644
// 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 b7b547a78..583c3f7d2 100644
index cbe3afaba..40a11dd6d 100644
--- a/src/st/st-texture-cache.c
+++ b/src/st/st-texture-cache.c
@@ -130,6 +130,16 @@ st_texture_cache_class_init (StTextureCacheClass *klass)
@@ -113,6 +113,16 @@ st_texture_cache_class_init (StTextureCacheClass *klass)
G_TYPE_NONE, 1, G_TYPE_FILE);
}
@ -50,7 +50,7 @@ index b7b547a78..583c3f7d2 100644
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 55d84952d..948915c30 100644
index 11d1c4e64..9079d1fda 100644
--- a/src/st/st-texture-cache.h
+++ b/src/st/st-texture-cache.h
@@ -53,6 +53,7 @@ typedef enum {
@ -62,5 +62,5 @@ index 55d84952d..948915c30 100644
ClutterActor *
st_texture_cache_load_sliced_image (StTextureCache *cache,
--
2.31.1
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

@ -1,333 +0,0 @@
From 2103c5fcf994bb6aebd978553b338436e85fa7ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 7 Jul 2021 22:05:25 +0200
Subject: [PATCH 1/2] status/powerProfiles: Add power mode selection
Settings' power panel gained support for switchable power profiles
in GNOME 40. It's useful to have that functionality more readily
available, so expose it in the system status menu as well.
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3944
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1907>
---
.../net.hadess.PowerProfiles.xml | 76 ++++++++++++
.../gnome-shell-dbus-interfaces.gresource.xml | 1 +
js/js-resources.gresource.xml | 1 +
js/ui/panel.js | 4 +
js/ui/status/powerProfiles.js | 111 ++++++++++++++++++
po/POTFILES.in | 1 +
6 files changed, 194 insertions(+)
create mode 100644 data/dbus-interfaces/net.hadess.PowerProfiles.xml
create mode 100644 js/ui/status/powerProfiles.js
diff --git a/data/dbus-interfaces/net.hadess.PowerProfiles.xml b/data/dbus-interfaces/net.hadess.PowerProfiles.xml
new file mode 100644
index 000000000..fce04a86d
--- /dev/null
+++ b/data/dbus-interfaces/net.hadess.PowerProfiles.xml
@@ -0,0 +1,76 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+
+<node>
+
+ <!--
+ net.hadess.PowerProfiles:
+ @short_description: Power Profiles daemon
+
+ The power-profiles-daemon API is meant to be used by parts of the OS or
+ desktop environment to switch system power profiles based on user choice,
+ or user intent.
+
+ OS components would typically use the "Profiles" property to construct
+ their UI (2 or 3 profiles available), and monitor the "ActiveProfile"
+ and the "PerformanceInhibited" properties to update that UI. The UI
+ would try to set the "ActiveProfile" property if the user selected
+ a different one.
+
+ Note that the reason why the project exists and how it is different from
+ existing projects is explained <ulink href=" https://gitlab.freedesktop.org/hadess/power-profiles-daemon/-/blob/master/README.md">
+ in the project's README file</ulink>.
+
+ The object path will be "/net/hadess/PowerProfiles".
+ -->
+ <interface name="net.hadess.PowerProfiles">
+ <!--
+ ActiveProfile:
+
+ The type of the currently active profile. It might change automatically
+ if the "performance" profile was selected but it got inhibited, in which
+ case the "PerformanceInhibited" property will reflect the reason.
+ -->
+ <property name="ActiveProfile" type="s" access="readwrite"/>
+
+ <!--
+ PerformanceInhibited:
+
+ This will be set if the performance power profile is unavailable, with
+ the value being used to identify the reason for unavailability. As new
+ reasons can be added, it is recommended that front-ends show a generic
+ reason if they do not recognise the value. Possible values are:
+ - "lap-detected" (the computer is sitting on the user's lap)
+ - "high-operating-temperature" (the computer is close to overheating)
+ - "" (the empty string, if not inhibited)
+ -->
+ <property name="PerformanceInhibited" type="s" access="read"/>
+
+ <!--
+ Profiles:
+
+ An array of key-pair values representing each profile. The key named
+ "Driver" (s) identifies the power-profiles-daemon backend code used to
+ implement the profile.
+
+ The key named "Profile" (s) will be one of:
+ - "power-saver" (battery saving profile)
+ - "balanced" (the default profile)
+ - "performance" (a profile that does not care about noise or battery consumption)
+
+ Only one of each type of profile will be listed, with the daemon choosing the
+ more appropriate "driver" for each profile type.
+ -->
+ <property name="Profiles" type="aa{sv}" access="read"/>
+
+ <!--
+ Actions:
+
+ An array of strings listing each one of the "actions" implemented in
+ the running daemon. This is used by API users to figure out whether
+ particular functionality is available in a version of the daemon.
+ -->
+ <property name="Actions" type="as" access="read"/>
+
+ </interface>
+</node>
diff --git a/data/gnome-shell-dbus-interfaces.gresource.xml b/data/gnome-shell-dbus-interfaces.gresource.xml
index e7972f6cb..6682c462d 100644
--- a/data/gnome-shell-dbus-interfaces.gresource.xml
+++ b/data/gnome-shell-dbus-interfaces.gresource.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/shell/dbus-interfaces">
+ <file preprocess="xml-stripblanks">net.hadess.PowerProfiles.xml</file>
<file preprocess="xml-stripblanks">net.hadess.SensorProxy.xml</file>
<file preprocess="xml-stripblanks">net.reactivated.Fprint.Device.xml</file>
<file preprocess="xml-stripblanks">net.reactivated.Fprint.Manager.xml</file>
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index b2c603a55..7a94e2ff1 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -134,6 +134,7 @@
<file>ui/status/nightLight.js</file>
<file>ui/status/network.js</file>
<file>ui/status/power.js</file>
+ <file>ui/status/powerProfiles.js</file>
<file>ui/status/rfkill.js</file>
<file>ui/status/volume.js</file>
<file>ui/status/bluetooth.js</file>
diff --git a/js/ui/panel.js b/js/ui/panel.js
index ad11f4ba2..84668e96e 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -693,6 +693,7 @@ class AggregateMenu extends PanelMenu.Button {
this._remoteAccess = new imports.ui.status.remoteAccess.RemoteAccessApplet();
this._power = new imports.ui.status.power.Indicator();
+ this._powerProfiles = new imports.ui.status.powerProfiles.Indicator();
this._rfkill = new imports.ui.status.rfkill.Indicator();
this._volume = new imports.ui.status.volume.Indicator();
this._brightness = new imports.ui.status.brightness.Indicator();
@@ -712,6 +713,7 @@ class AggregateMenu extends PanelMenu.Button {
this._indicators.add_child(this._rfkill);
this._indicators.add_child(this._volume);
this._indicators.add_child(this._power);
+ this._indicators.add_child(this._powerProfiles);
this.menu.addMenuItem(this._volume.menu);
this.menu.addMenuItem(this._brightness.menu);
@@ -726,6 +728,7 @@ class AggregateMenu extends PanelMenu.Button {
this.menu.addMenuItem(this._location.menu);
this.menu.addMenuItem(this._rfkill.menu);
this.menu.addMenuItem(this._power.menu);
+ this.menu.addMenuItem(this._powerProfiles.menu);
this.menu.addMenuItem(this._nightLight.menu);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addMenuItem(this._system.menu);
@@ -733,6 +736,7 @@ class AggregateMenu extends PanelMenu.Button {
menuLayout.addSizeChild(this._location.menu.actor);
menuLayout.addSizeChild(this._rfkill.menu.actor);
menuLayout.addSizeChild(this._power.menu.actor);
+ menuLayout.addSizeChild(this._powerProfiles.menu.actor);
menuLayout.addSizeChild(this._system.menu.actor);
}
});
diff --git a/js/ui/status/powerProfiles.js b/js/ui/status/powerProfiles.js
new file mode 100644
index 000000000..f6bc5835b
--- /dev/null
+++ b/js/ui/status/powerProfiles.js
@@ -0,0 +1,111 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+/* exported Indicator */
+
+const { Gio, GObject } = imports.gi;
+
+const Main = imports.ui.main;
+const PanelMenu = imports.ui.panelMenu;
+const PopupMenu = imports.ui.popupMenu;
+
+const { loadInterfaceXML } = imports.misc.fileUtils;
+
+const BUS_NAME = 'net.hadess.PowerProfiles';
+const OBJECT_PATH = '/net/hadess/PowerProfiles';
+
+const PowerProfilesIface = loadInterfaceXML('net.hadess.PowerProfiles');
+const PowerProfilesProxy = Gio.DBusProxy.makeProxyWrapper(PowerProfilesIface);
+
+const PROFILE_LABELS = {
+ 'performance': _('Performance Mode'),
+ 'balanced': _('Balanced Power'),
+ 'power-saver': _('Power Saver'),
+};
+const PROFILE_ICONS = {
+ 'performance': 'power-profile-performance-symbolic',
+ 'balanced': 'power-profile-balanced-symbolic',
+ 'power-saver': 'power-profile-power-saver-symbolic',
+};
+
+var Indicator = GObject.registerClass(
+class Indicator extends PanelMenu.SystemIndicator {
+ _init() {
+ super._init();
+
+ this._profileItems = new Map();
+ this._updateProfiles = true;
+
+ this._proxy = new PowerProfilesProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH,
+ (proxy, error) => {
+ if (error) {
+ log(error.message);
+ } else {
+ this._proxy.connect('g-properties-changed',
+ (p, properties) => {
+ const propertyNames = properties.deep_unpack();
+ this._updateProfiles = 'Profiles' in propertyNames;
+ this._sync();
+ });
+ }
+ this._sync();
+ });
+
+ this._item = new PopupMenu.PopupSubMenuMenuItem('', true);
+
+ this._profileSection = new PopupMenu.PopupMenuSection();
+ this._item.menu.addMenuItem(this._profileSection);
+ this._item.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+ this._item.menu.addSettingsAction(_('Power Settings'),
+ 'gnome-power-panel.desktop');
+ this.menu.addMenuItem(this._item);
+
+ Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
+ this._sessionUpdated();
+ this._sync();
+ }
+
+ _sessionUpdated() {
+ const sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
+ this.menu.setSensitive(sensitive);
+ }
+
+ _sync() {
+ this._item.visible = this._proxy.g_name_owner !== null;
+
+ if (!this._item.visible)
+ return;
+
+ if (this._updateProfiles) {
+ this._profileSection.removeAll();
+ this._profileItems.clear();
+
+ const profiles = this._proxy.Profiles
+ .map(p => p.Profile.unpack())
+ .reverse();
+ for (const profile of profiles) {
+ const label = PROFILE_LABELS[profile];
+ if (!label)
+ continue;
+
+ const item = new PopupMenu.PopupMenuItem(label);
+ item.connect('activate',
+ () => (this._proxy.ActiveProfile = profile));
+ this._profileItems.set(profile, item);
+ this._profileSection.addMenuItem(item);
+ }
+ this._updateProfiles = false;
+ }
+
+ for (const [profile, item] of this._profileItems) {
+ item.setOrnament(profile === this._proxy.ActiveProfile
+ ? PopupMenu.Ornament.DOT
+ : PopupMenu.Ornament.NONE);
+ }
+
+ const perfItem = this._profileItems.get('performance');
+ if (perfItem)
+ perfItem.sensitive = this._proxy.PerformanceInhibited === '';
+
+ this._item.label.text = PROFILE_LABELS[this._proxy.ActiveProfile];
+ this._item.icon.icon_name = PROFILE_ICONS[this._proxy.ActiveProfile];
+ }
+});
diff --git a/po/POTFILES.in b/po/POTFILES.in
index cb279c1ee..727cb01a8 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -61,6 +61,7 @@ js/ui/status/location.js
js/ui/status/network.js
js/ui/status/nightLight.js
js/ui/status/power.js
+js/ui/status/powerProfiles.js
js/ui/status/remoteAccess.js
js/ui/status/rfkill.js
js/ui/status/system.js
--
2.31.1
From 0f8a2e2c6c3119492670efce5aff1224f2c3c47f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 6 Aug 2021 21:04:24 +0200
Subject: [PATCH 2/2] powerProfiles: Tweak profile names
After some more discussion, we settled on slightly different
profile names.
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4530
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1939>
---
js/ui/status/powerProfiles.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/js/ui/status/powerProfiles.js b/js/ui/status/powerProfiles.js
index f6bc5835b..61205bbc6 100644
--- a/js/ui/status/powerProfiles.js
+++ b/js/ui/status/powerProfiles.js
@@ -16,9 +16,9 @@ const PowerProfilesIface = loadInterfaceXML('net.hadess.PowerProfiles');
const PowerProfilesProxy = Gio.DBusProxy.makeProxyWrapper(PowerProfilesIface);
const PROFILE_LABELS = {
- 'performance': _('Performance Mode'),
- 'balanced': _('Balanced Power'),
- 'power-saver': _('Power Saver'),
+ 'performance': C_('Power profile', 'Performance'),
+ 'balanced': C_('Power profile', 'Balanced'),
+ 'power-saver': C_('Power profile', 'Power Saver'),
};
const PROFILE_ICONS = {
'performance': 'power-profile-performance-symbolic',
--
2.31.1

@ -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,488 @@
From 7b514e637837e00372e20fa52f841e993966b734 Mon Sep 17 00:00:00 2001
From: Umang Jain <mailumangjain@gmail.com>
Date: Fri, 13 Dec 2019 13:36:14 +0530
Subject: [PATCH 1/7] shellEntry: Add CapsLockWarning class
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/619
---
data/theme/gnome-shell-sass/_common.scss | 5 +++
js/ui/shellEntry.js | 39 +++++++++++++++++++++++-
2 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
index b1eeb0ce97..19a736ab7d 100644
--- a/data/theme/gnome-shell-sass/_common.scss
+++ b/data/theme/gnome-shell-sass/_common.scss
@@ -391,6 +391,11 @@ StScrollBar {
padding-bottom: 8px;
}
+ .prompt-dialog-caps-lock-warning {
+ @extend .prompt-dialog-error-label;
+ padding-left: 6.2em;
+ }
+
.prompt-dialog-info-label {
font-size: 10pt;
padding-bottom: 8px;
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
index 79f1aad3e7..c1738c4064 100644
--- a/js/ui/shellEntry.js
+++ b/js/ui/shellEntry.js
@@ -1,6 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-const { Clutter, Shell, St } = imports.gi;
+const { Clutter, GObject, Pango, Shell, St } = imports.gi;
const BoxPointer = imports.ui.boxpointer;
const Main = imports.ui.main;
@@ -170,3 +170,40 @@ function addContextMenu(entry, params) {
entry._menuManager = null;
});
}
+
+var CapsLockWarning = GObject.registerClass(
+class CapsLockWarning extends St.Label {
+ _init(params) {
+ let defaultParams = { style_class: 'prompt-dialog-error-label' };
+ super._init(Object.assign(defaultParams, params));
+
+ this.text = _('Caps lock is on.');
+
+ this._keymap = Clutter.get_default_backend().get_keymap();
+
+ this.connect('notify::mapped', () => {
+ if (this.is_mapped()) {
+ this.stateChangedId = this._keymap.connect('state-changed',
+ this._updateCapsLockWarningOpacity.bind(this));
+ } else {
+ this._keymap.disconnect(this.stateChangedId);
+ this.stateChangedId = 0;
+ }
+
+ this._updateCapsLockWarningOpacity();
+ });
+
+ this.connect('destroy', () => {
+ if (this.stateChangedId > 0)
+ this._keymap.disconnect(this.stateChangedId);
+ });
+
+ this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
+ this.clutter_text.line_wrap = true;
+ }
+
+ _updateCapsLockWarningOpacity() {
+ let capsLockOn = this._keymap.get_caps_lock_state();
+ this.opacity = capsLockOn ? 255 : 0;
+ }
+});
--
2.21.1
From aa4938f261454f85c782e59e40d4e5a9e1a01dbc Mon Sep 17 00:00:00 2001
From: Umang Jain <mailumangjain@gmail.com>
Date: Wed, 18 Dec 2019 01:33:45 +0530
Subject: [PATCH 2/7] js: Add caps-lock Warning to the dialogs
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/619
---
js/gdm/authPrompt.js | 4 ++++
js/ui/components/keyring.js | 6 ++++++
js/ui/components/networkAgent.js | 8 ++++++++
js/ui/components/polkitAgent.js | 2 ++
js/ui/shellMountOperation.js | 3 +++
5 files changed, 23 insertions(+)
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
index 71069e93b8..3ce9fd0d01 100644
--- a/js/gdm/authPrompt.js
+++ b/js/gdm/authPrompt.js
@@ -113,6 +113,9 @@ var AuthPrompt = class {
this._entry.grab_key_focus();
+ this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
+ this.actor.add_child(this._capsLockWarningLabel);
+
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
scale_x: 0 });
@@ -432,6 +435,7 @@ var AuthPrompt = class {
setPasswordChar(passwordChar) {
this._entry.clutter_text.set_password_char(passwordChar);
this._entry.menu.isPassword = passwordChar != '';
+ this._capsLockWarningLabel.visible = passwordChar !== '';
}
setQuestion(question) {
diff --git a/js/ui/components/keyring.js b/js/ui/components/keyring.js
index 0d9f1e4663..3512fb63b1 100644
--- a/js/ui/components/keyring.js
+++ b/js/ui/components/keyring.js
@@ -128,6 +128,12 @@ var KeyringDialog = class extends ModalDialog.ModalDialog {
this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null);
this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null);
+ if (this._passwordEntry || this._confirmEntry) {
+ this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
+ layout.attach(this._capsLockWarningLabel, 1, row, 1, 1);
+ row++;
+ }
+
if (this.prompt.choice_visible) {
let choice = new CheckBox.CheckBox();
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
diff --git a/js/ui/components/networkAgent.js b/js/ui/components/networkAgent.js
index f871c732d9..32d40fb2b9 100644
--- a/js/ui/components/networkAgent.js
+++ b/js/ui/components/networkAgent.js
@@ -95,6 +95,14 @@ var NetworkSecretDialog = class extends ModalDialog.ModalDialog {
secret.entry.clutter_text.set_password_char('\u25cf');
}
+ if (this._content.secrets.some(s => s.password)) {
+ this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
+ if (rtl)
+ layout.attach(this._capsLockWarningLabel, 0, pos, 1, 1);
+ else
+ layout.attach(this._capsLockWarningLabel, 1, pos, 1, 1);
+ }
+
contentBox.messageBox.add(secretTable);
if (flags & NM.SecretAgentGetSecretsFlags.WPS_PBC_ACTIVE) {
diff --git a/js/ui/components/polkitAgent.js b/js/ui/components/polkitAgent.js
index 21feb40903..734a217335 100644
--- a/js/ui/components/polkitAgent.js
+++ b/js/ui/components/polkitAgent.js
@@ -108,6 +108,8 @@ var AuthenticationDialog = class extends ModalDialog.ModalDialog {
this.setInitialKeyFocus(this._passwordEntry);
this._passwordBox.hide();
+ this._capsLockWarningLabel = new ShellEntry.CapsLockWarning({ style_class: 'prompt-dialog-caps-lock-warning' });
+ content.messageBox.add(this._capsLockWarningLabel);
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' });
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
diff --git a/js/ui/shellMountOperation.js b/js/ui/shellMountOperation.js
index f976f400f4..3a2377ddaf 100644
--- a/js/ui/shellMountOperation.js
+++ b/js/ui/shellMountOperation.js
@@ -305,6 +305,9 @@ var ShellMountPasswordDialog = class extends ModalDialog.ModalDialog {
this._passwordBox.add(this._passwordEntry, {expand: true });
this.setInitialKeyFocus(this._passwordEntry);
+ this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
+ content.messageBox.add(this._capsLockWarningLabel);
+
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label',
text: _("Sorry, that didnt work. Please try again.") });
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
--
2.21.1
From 016cbd971711665844d40ec678d2779c160f791b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Thu, 23 Jan 2020 22:37:06 +0100
Subject: [PATCH 3/7] shellEntry: Make signal id variable private
Signal connection IDs should be private variables, so make this one
private.
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/952
---
js/ui/shellEntry.js | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
index c1738c4064..cd7c9a6c88 100644
--- a/js/ui/shellEntry.js
+++ b/js/ui/shellEntry.js
@@ -183,19 +183,19 @@ class CapsLockWarning extends St.Label {
this.connect('notify::mapped', () => {
if (this.is_mapped()) {
- this.stateChangedId = this._keymap.connect('state-changed',
+ this._stateChangedId = this._keymap.connect('state-changed',
this._updateCapsLockWarningOpacity.bind(this));
} else {
- this._keymap.disconnect(this.stateChangedId);
- this.stateChangedId = 0;
+ this._keymap.disconnect(this._stateChangedId);
+ this._stateChangedId = 0;
}
this._updateCapsLockWarningOpacity();
});
this.connect('destroy', () => {
- if (this.stateChangedId > 0)
- this._keymap.disconnect(this.stateChangedId);
+ if (this._stateChangedId > 0)
+ this._keymap.disconnect(this._stateChangedId);
});
this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
--
2.21.1
From ba65f9066d72731e345a5aced61f35d39c1c1376 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Thu, 23 Jan 2020 23:26:45 +0100
Subject: [PATCH 4/7] theme: Move caps-lock warning to entry widget stylesheet
The caps-lock warning is more related to entries than dialogs and is
also used in gdm, which is not realated to dialogs at all. Rename the
css class to caps-lock-warning-label and move it to the entry
stylesheet.
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/952
---
data/theme/gnome-shell-sass/_common.scss | 12 +++++++-----
js/ui/shellEntry.js | 2 +-
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
index 19a736ab7d..4661533de2 100644
--- a/data/theme/gnome-shell-sass/_common.scss
+++ b/data/theme/gnome-shell-sass/_common.scss
@@ -94,6 +94,13 @@ StEntry {
}
}
+.caps-lock-warning-label {
+ padding-left: 6.2em;
+ @include fontsize($font-size - 1);
+ color: $warning_color;
+}
+
+
/* Scrollbars */
@@ -391,11 +398,6 @@ StScrollBar {
padding-bottom: 8px;
}
- .prompt-dialog-caps-lock-warning {
- @extend .prompt-dialog-error-label;
- padding-left: 6.2em;
- }
-
.prompt-dialog-info-label {
font-size: 10pt;
padding-bottom: 8px;
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
index cd7c9a6c88..46eba88d54 100644
--- a/js/ui/shellEntry.js
+++ b/js/ui/shellEntry.js
@@ -174,7 +174,7 @@ function addContextMenu(entry, params) {
var CapsLockWarning = GObject.registerClass(
class CapsLockWarning extends St.Label {
_init(params) {
- let defaultParams = { style_class: 'prompt-dialog-error-label' };
+ let defaultParams = { style_class: 'caps-lock-warning-label' };
super._init(Object.assign(defaultParams, params));
this.text = _('Caps lock is on.');
--
2.21.1
From afd764c82febe21aec70bdfc19d256f3401530e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Thu, 23 Jan 2020 22:36:09 +0100
Subject: [PATCH 5/7] shellEntry: Hide caps lock warning and use animation to
show it
Since the caps-lock warning adds a lot of spacing to dialogs and the
lock screen, hide it by default and only show it when necessary. To make
the transition smooth instead of just showing the label, animate it in
using the height and opacity.
Also add some bottom padding to the label so we can show or hide that
padding, too.
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/952
---
data/theme/gnome-shell-sass/_common.scss | 1 +
js/ui/shellEntry.js | 33 ++++++++++++++++++------
2 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
index 4661533de2..9e0751c8c5 100644
--- a/data/theme/gnome-shell-sass/_common.scss
+++ b/data/theme/gnome-shell-sass/_common.scss
@@ -95,6 +95,7 @@ StEntry {
}
.caps-lock-warning-label {
+ padding-bottom: 8px;
padding-left: 6.2em;
@include fontsize($font-size - 1);
color: $warning_color;
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
index 46eba88d54..fc8ee37a9a 100644
--- a/js/ui/shellEntry.js
+++ b/js/ui/shellEntry.js
@@ -6,6 +6,7 @@ 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;
var EntryMenu = class extends PopupMenu.PopupMenu {
constructor(entry) {
@@ -179,31 +180,47 @@ class CapsLockWarning extends St.Label {
this.text = _('Caps lock is on.');
+ this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
+ this.clutter_text.line_wrap = true;
+
this._keymap = Clutter.get_default_backend().get_keymap();
this.connect('notify::mapped', () => {
if (this.is_mapped()) {
this._stateChangedId = this._keymap.connect('state-changed',
- this._updateCapsLockWarningOpacity.bind(this));
+ () => this._sync(true));
} else {
this._keymap.disconnect(this._stateChangedId);
this._stateChangedId = 0;
}
- this._updateCapsLockWarningOpacity();
+ this._sync(false);
});
this.connect('destroy', () => {
- if (this._stateChangedId > 0)
+ if (this._stateChangedId)
this._keymap.disconnect(this._stateChangedId);
});
-
- this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
- this.clutter_text.line_wrap = true;
}
- _updateCapsLockWarningOpacity() {
+ _sync(animate) {
let capsLockOn = this._keymap.get_caps_lock_state();
- this.opacity = capsLockOn ? 255 : 0;
+
+ Tweener.removeTweens(this);
+
+ this.natural_height_set = false;
+ let [, height] = this.get_preferred_height(-1);
+ this.natural_height_set = true;
+
+ Tweener.addTween(this, {
+ height: capsLockOn ? height : 0,
+ opacity: capsLockOn ? 255 : 0,
+ time: animate ? 0.2 : 0,
+ transition: 'easeOutQuad',
+ onComplete: () => {
+ if (capsLockOn)
+ this.height = -1;
+ },
+ });
}
});
--
2.21.1
From 1ef3dafb51da380c54635d0565dc098e40bbb3e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 29 Jan 2020 17:48:57 +0100
Subject: [PATCH 6/7] js: Initialize some properties
Otherwise those can result in the (harmless) "reference to undefined
property" warnings.
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/970
---
js/ui/overview.js | 1 +
js/ui/shellEntry.js | 1 +
2 files changed, 2 insertions(+)
diff --git a/js/ui/overview.js b/js/ui/overview.js
index dc6ad1821b..5bad4cbd62 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -80,6 +80,7 @@ var Overview = class {
constructor() {
this._overviewCreated = false;
this._initCalled = false;
+ this._visible = false;
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
this._sessionUpdated();
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
index fc8ee37a9a..55267e7c87 100644
--- a/js/ui/shellEntry.js
+++ b/js/ui/shellEntry.js
@@ -184,6 +184,7 @@ class CapsLockWarning extends St.Label {
this.clutter_text.line_wrap = true;
this._keymap = Clutter.get_default_backend().get_keymap();
+ this._stateChangedId = 0;
this.connect('notify::mapped', () => {
if (this.is_mapped()) {
--
2.21.1
From 273f7adb43cfee907342d017e1454ea90d42d262 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 21 Feb 2020 19:38:53 +0100
Subject: [PATCH 7/7] shellEntry: Restore natural-height-set instead of forcing
it
If we are transitioning the label from 0 to its natural height, we
must set natural-height-set again after querying the preferred height,
otherwise Clutter would skip the transition.
However when transitioning in the opposite direction, setting the
property to true can go horribly wrong:
If the actor hasn't been allocated before, it will store a fixed
natural height of 0. But as there is no fixed min-height, we can
end up with min-height > natural-height, which is a fatal error.
(This isn't an issue when *actually* setting a fixed height, as
that will set both natural and minimum height)
So instead of always setting natural-height-set to true, restore
its previous value to fix the issue.
https://gitlab.gnome.org/GNOME/gnome-shell/issues/2255
---
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 55267e7c87..4a30b22f7a 100644
--- a/js/ui/shellEntry.js
+++ b/js/ui/shellEntry.js
@@ -209,9 +209,10 @@ class CapsLockWarning extends St.Label {
Tweener.removeTweens(this);
+ const naturalHeightSet = this.natural_height_set;
this.natural_height_set = false;
let [, height] = this.get_preferred_height(-1);
- this.natural_height_set = true;
+ this.natural_height_set = naturalHeightSet;
Tweener.addTween(this, {
height: capsLockOn ? height : 0,
--
2.21.1

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

@ -1,4 +1,4 @@
From 6739f213965c2b6a41c21b446095f393f9d86e43 Mon Sep 17 00:00:00 2001
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
@ -12,59 +12,50 @@ front, before a password is asked.
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
index 4844b9ee0..149e5ad4a 100644
index d7f53a92e..d421a8856 100644
--- a/js/gdm/authPrompt.js
+++ b/js/gdm/authPrompt.js
@@ -179,7 +179,7 @@ var AuthPrompt = GObject.registerClass({
@@ -169,7 +169,7 @@ var AuthPrompt = class {
this._updateNextButtonSensitivity(this._entry.text.length > 0);
[this._textEntry, this._passwordEntry].forEach(entry => {
entry.clutter_text.connect('text-changed', () => {
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.31.1
2.21.0
From 2b84c3d611120ae2f60386d5c637b84d1958398d Mon Sep 17 00:00:00 2001
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 | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
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 149e5ad4a..c5643d046 100644
index d421a8856..62c5bd078 100644
--- a/js/gdm/authPrompt.js
+++ b/js/gdm/authPrompt.js
@@ -243,13 +243,14 @@ var AuthPrompt = GObject.registerClass({
this.verificationStatus = AuthPromptStatus.VERIFICATION_IN_PROGRESS;
this.updateSensitivity(false);
@@ -60,8 +60,8 @@ var AuthPrompt = class {
- if (shouldSpin)
this.connect('next', () => {
this.updateSensitivity(false);
- this.startSpinning();
+ if (this._queryingService) {
+ if (shouldSpin)
if (this._queryingService) {
+ this.startSpinning();
- if (this._queryingService)
this._userVerifier.answerQuery(this._queryingService, this._entry.text);
- else
+ } else {
} else {
this._preemptiveAnswer = this._entry.text;
+ }
this.emit('next');
}
--
2.31.1
2.21.0
From 56360c872e01b0554b4d8b53dddba5407d4e889b Mon Sep 17 00:00:00 2001
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
@ -78,32 +69,43 @@ 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, 36 insertions(+), 1 deletion(-)
js/gdm/authPrompt.js | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
index c5643d046..84c608b2f 100644
index 62c5bd078..27eb31a89 100644
--- a/js/gdm/authPrompt.js
+++ b/js/gdm/authPrompt.js
@@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported AuthPrompt */
-const { Clutter, GLib, GObject, Pango, Shell, St } = imports.gi;
+const { Clutter, GLib, GObject, Meta, Pango, Shell, St } = imports.gi;
@@ -6,6 +6,7 @@ const Signals = imports.signals;
const Animation = imports.ui.animation;
const Batch = imports.gdm.batch;
@@ -63,6 +63,8 @@ var AuthPrompt = GObject.registerClass({
this._defaultButtonWellActor = null;
this._cancelledRetries = 0;
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;
@@ -119,6 +121,11 @@ var AuthPrompt = GObject.registerClass({
@@ -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() {
@ -115,19 +117,7 @@ index c5643d046..84c608b2f 100644
this._userVerifier.destroy();
this._userVerifier = null;
}
@@ -250,6 +257,11 @@ var AuthPrompt = GObject.registerClass({
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;
+ }
}
this.emit('next');
@@ -429,6 +441,11 @@ var AuthPrompt = GObject.registerClass({
@@ -342,6 +355,11 @@ var AuthPrompt = class {
}
setQuestion(question) {
@ -136,11 +126,11 @@ index c5643d046..84c608b2f 100644
+ this._preemptiveAnswerWatchId = 0;
+ }
+
this._entry.hint_text = question;
this._label.set_text(question);
this._entry.show();
@@ -530,6 +547,19 @@ var AuthPrompt = GObject.registerClass({
this._updateEntry(false);
this._label.show();
@@ -427,6 +445,19 @@ var AuthPrompt = class {
}
}
+ _onUserStoppedTypePreemptiveAnswer() {
@ -159,18 +149,19 @@ index c5643d046..84c608b2f 100644
reset() {
let oldStatus = this.verificationStatus;
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
@@ -537,6 +567,11 @@ var AuthPrompt = GObject.registerClass({
this.cancelButton.can_focus = this._hasCancelButton;
@@ -434,6 +465,12 @@ var AuthPrompt = class {
this.nextButton.label = _("Next");
this._preemptiveAnswer = null;
+ if (this._preemptiveAnswerWatchId)
+ if (this._preemptiveAnswerWatchId) {
+ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
+ this._preemptiveAnswerWatchId = this._idleMonitor.add_idle_watch(500,
+ }
+ this._preemptiveAnswerWatchId = this._idleMonitor.add_idle_watch (500,
+ this._onUserStoppedTypePreemptiveAnswer.bind(this));
+
if (this._userVerifier)
this._userVerifier.cancel();
--
2.31.1
2.21.0

@ -1,4 +1,4 @@
From d2c12a372ea0ccbe6ba682c553d8b83b3253169f Mon Sep 17 00:00:00 2001
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
@ -16,27 +16,27 @@ This commit adds the necessary api to detect that case.
1 file changed, 7 insertions(+)
diff --git a/js/misc/smartcardManager.js b/js/misc/smartcardManager.js
index d9b6ff474..26f9f5aaa 100644
index fda782d1e..bb43c96e7 100644
--- a/js/misc/smartcardManager.js
+++ b/js/misc/smartcardManager.js
@@ -111,5 +111,12 @@ var SmartcardManager = class {
@@ -112,5 +112,12 @@ var SmartcardManager = class {
return true;
}
+
+ loggedInWithToken() {
+ if (this._loginToken)
+ return true;
+
+ return false;
+ }
+
};
Signals.addSignalMethods(SmartcardManager.prototype);
--
2.31.1
2.21.0
From 98393eef884edc9e685b712c71356751acdd552f Mon Sep 17 00:00:00 2001
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
@ -49,18 +49,18 @@ gets used for unlock, too.
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/js/gdm/util.js b/js/gdm/util.js
index 72561daab..6b92e3564 100644
index 2e9935250..2b80e1dd9 100644
--- a/js/gdm/util.js
+++ b/js/gdm/util.js
@@ -149,7 +149,6 @@ var ShellUserVerifier = class {
@@ -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 = new FprintManagerProxy(Gio.DBus.system,
'net.reactivated.Fprint',
@@ -166,6 +165,8 @@ var ShellUserVerifier = class {
this._fprintManager = Fprint.FprintManager();
this._smartcardManager = SmartcardManager.getSmartcardManager();
@@ -138,6 +137,8 @@ var ShellUserVerifier = class {
this.smartcardDetected = false;
this._checkForSmartcard();
@ -69,7 +69,7 @@ index 72561daab..6b92e3564 100644
this._smartcardInsertedId = this._smartcardManager.connect('smartcard-inserted',
this._checkForSmartcard.bind(this));
this._smartcardRemovedId = this._smartcardManager.connect('smartcard-removed',
@@ -527,7 +528,9 @@ var ShellUserVerifier = class {
@@ -407,7 +408,9 @@ var ShellUserVerifier = class {
}
_updateDefaultService() {
@ -81,10 +81,10 @@ index 72561daab..6b92e3564 100644
else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
this._defaultService = SMARTCARD_SERVICE_NAME;
--
2.31.1
2.21.0
From 57ca969a0af6f65e71dc1158163b9c826bdb7079 Mon Sep 17 00:00:00 2001
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
@ -97,10 +97,10 @@ after we get a smartcard insertion event.
1 file changed, 2 insertions(+)
diff --git a/js/gdm/util.js b/js/gdm/util.js
index 6b92e3564..e62114cb1 100644
index 2b80e1dd9..6e940d2ab 100644
--- a/js/gdm/util.js
+++ b/js/gdm/util.js
@@ -420,6 +420,8 @@ var ShellUserVerifier = class {
@@ -327,6 +327,8 @@ var ShellUserVerifier = class {
else if (this._preemptingService == SMARTCARD_SERVICE_NAME)
this._preemptingService = null;
@ -110,5 +110,5 @@ index 6b92e3564..e62114cb1 100644
}
}
--
2.31.1
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

@ -1,107 +0,0 @@
From 3a89e8597f6f3e7fa468bae93768f8253a3141e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 6 Oct 2022 14:30:20 +0200
Subject: [PATCH 1/2] inhibitShortcutsDialog: Don't override resource
PermissionStore's Set() method takes a complete permission
table, so when setting an app's permission, we are implicitly
removing all previously set entries for other apps.
Switch to the SetPermission() method which sets the permission
for a single app.
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5937
Part-of:
<https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2504>
---
...g.freedesktop.impl.portal.PermissionStore.xml | 7 +++++++
js/ui/inhibitShortcutsDialog.js | 16 ++++++----------
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/data/dbus-interfaces/org.freedesktop.impl.portal.PermissionStore.xml b/data/dbus-interfaces/org.freedesktop.impl.portal.PermissionStore.xml
index 75fbc468a8..55d3fc30cb 100644
--- a/data/dbus-interfaces/org.freedesktop.impl.portal.PermissionStore.xml
+++ b/data/dbus-interfaces/org.freedesktop.impl.portal.PermissionStore.xml
@@ -13,6 +13,13 @@
<arg name="app_permissions" type="a{sas}" direction="in"/>
<arg name="data" type="v" direction="in"/>
</method>
+ <method name="SetPermission">
+ <arg name='table' type='s' direction='in'/>
+ <arg name='create' type='b' direction='in'/>
+ <arg name='id' type='s' direction='in'/>
+ <arg name='app' type='s' direction='in'/>
+ <arg name='permissions' type='as' direction='in'/>
+ </method>
<signal name="Changed">
<arg name="table" type="s" direction="out"/>
<arg name="id" type="s" direction="out"/>
diff --git a/js/ui/inhibitShortcutsDialog.js b/js/ui/inhibitShortcutsDialog.js
index c59544eaf9..8ef5861261 100644
--- a/js/ui/inhibitShortcutsDialog.js
+++ b/js/ui/inhibitShortcutsDialog.js
@@ -1,5 +1,5 @@
/* exported InhibitShortcutsDialog */
-const { Clutter, Gio, GLib, GObject, Gtk, Meta, Pango, Shell, St } = imports.gi;
+const {Clutter, Gio, GObject, Gtk, Meta, Pango, Shell, St} = imports.gi;
const Dialog = imports.ui.dialog;
const ModalDialog = imports.ui.modalDialog;
@@ -57,15 +57,11 @@ var InhibitShortcutsDialog = GObject.registerClass({
if (!this._shouldUsePermStore() || this._permStore == null)
return;
- let permissions = {};
- permissions[this._app.get_id()] = [grant];
- let data = GLib.Variant.new('av', {});
-
- this._permStore.SetRemote(APP_PERMISSIONS_TABLE,
- true,
- APP_PERMISSIONS_ID,
- permissions,
- data,
+ this._permStore.SetPermissionRemote(APP_PERMISSIONS_TABLE,
+ true,
+ APP_PERMISSIONS_ID,
+ this._app.get_id(),
+ [grant],
(result, error) => {
if (error != null)
log(error.message);
--
2.43.0
From 1391efb2356d1b1eac631df2f5fbd61a7a72bf52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 18 Nov 2022 22:40:31 +0100
Subject: [PATCH 2/2] inhibitShorcutsDialog: Fix permission check
Each permission entry is an array of strings, so checking that against
the expected string itself will always fail.
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6107
Part-of:
<https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2548>
---
js/ui/inhibitShortcutsDialog.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/ui/inhibitShortcutsDialog.js b/js/ui/inhibitShortcutsDialog.js
index 8ef5861261..4cd2793c3d 100644
--- a/js/ui/inhibitShortcutsDialog.js
+++ b/js/ui/inhibitShortcutsDialog.js
@@ -145,7 +145,7 @@ var InhibitShortcutsDialog = GObject.registerClass({
let [permissions] = res;
if (permissions[appId] === undefined) // Not found
this._dialog.open();
- else if (permissions[appId] == GRANTED)
+ else if (permissions[appId][0] === GRANTED)
this._emitResponse(DialogResponse.ALLOW);
else
this._emitResponse(DialogResponse.DENY);
--
2.43.0

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

@ -1,334 +0,0 @@
From 49a950b9e0dc262fd20c28e21ee4815ea8efe758 Mon Sep 17 00:00:00 2001
From: Sebastian Keller <skeller@gnome.org>
Date: Tue, 16 Nov 2021 18:57:26 +0100
Subject: [PATCH 1/3] search: Split out the description highlighter into its
own class
No functional change yet, only preparation to allow adding a unit test
later on.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2033>
---
js/misc/util.js | 38 +++++++++++++++++++++++++++++++++++++-
js/ui/search.js | 12 +++++-------
2 files changed, 42 insertions(+), 8 deletions(-)
diff --git a/js/misc/util.js b/js/misc/util.js
index 8139d3f47..d1a702960 100644
--- a/js/misc/util.js
+++ b/js/misc/util.js
@@ -1,7 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
formatTime, formatTimeSpan, createTimeLabel, insertSorted,
- ensureActorVisibleInScrollView, wiggle, lerp, GNOMEversionCompare */
+ ensureActorVisibleInScrollView, wiggle, lerp, GNOMEversionCompare,
+ Highlighter */
const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi;
const Gettext = imports.gettext;
@@ -477,3 +478,38 @@ function GNOMEversionCompare(version1, version2) {
return 0;
}
+
+/* @class Highlighter Highlight given terms in text using markup. */
+var Highlighter = class {
+ /**
+ * @param {?string[]} terms - list of terms to highlight
+ */
+ constructor(terms) {
+ if (!terms)
+ return;
+
+ const escapedTerms = terms
+ .map(term => Shell.util_regex_escape(term))
+ .filter(term => term.length > 0);
+
+ if (escapedTerms.length === 0)
+ return;
+
+ this._highlightRegex = new RegExp('(%s)'.format(
+ escapedTerms.join('|')), 'gi');
+ }
+
+ /**
+ * Highlight all occurences of the terms defined for this
+ * highlighter in the provided text using markup.
+ *
+ * @param {string} text - text to highlight the defined terms in
+ * @returns {string}
+ */
+ highlight(text) {
+ if (!this._highlightRegex)
+ return text;
+
+ return text.replace(this._highlightRegex, '<b>$1</b>');
+ }
+};
diff --git a/js/ui/search.js b/js/ui/search.js
index 7300b053e..b1e76c46d 100644
--- a/js/ui/search.js
+++ b/js/ui/search.js
@@ -10,6 +10,8 @@ const ParentalControlsManager = imports.misc.parentalControlsManager;
const RemoteSearch = imports.ui.remoteSearch;
const Util = imports.misc.util;
+const { Highlighter } = imports.misc.util;
+
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
var MAX_LIST_SEARCH_RESULTS_ROWS = 5;
@@ -596,7 +598,7 @@ var SearchResultsView = GObject.registerClass({
this._providers = [];
- this._highlightRegex = null;
+ this._highlighter = new Highlighter();
this._searchSettings = new Gio.Settings({ schema_id: SEARCH_PROVIDERS_SCHEMA });
this._searchSettings.connect('changed::disabled', this._reloadRemoteProviders.bind(this));
@@ -739,8 +741,7 @@ var SearchResultsView = GObject.registerClass({
if (this._searchTimeoutId == 0)
this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 150, this._onSearchTimeout.bind(this));
- let escapedTerms = this._terms.map(term => Shell.util_regex_escape(term));
- this._highlightRegex = new RegExp('(%s)'.format(escapedTerms.join('|')), 'gi');
+ this._highlighter = new Highlighter(this._terms);
this.emit('terms-changed');
}
@@ -894,10 +895,7 @@ var SearchResultsView = GObject.registerClass({
if (!description)
return '';
- if (!this._highlightRegex)
- return description;
-
- return description.replace(this._highlightRegex, '<b>$1</b>');
+ return this._highlighter.highlight(description);
}
});
--
2.35.1
From 7c1abe1bd91ecf274d81e122035cbeeef6fd58d4 Mon Sep 17 00:00:00 2001
From: Sebastian Keller <skeller@gnome.org>
Date: Wed, 17 Nov 2021 02:50:39 +0100
Subject: [PATCH 2/3] util: Properly handle markup in highlighter
The code to highlight matches did not properly escape the passed in text
as for markup before adding its highlighting markup. This lead to some
search result descriptions not showing up, because their descriptions
contained characters, such as "<", that would have to be escaped when
used in markup or otherwise lead to invalid markup.
To work around this some search providers wrongly started escaping the
description on their end before sending them to gnome-shell. This lead
to another issue. Now if the highlighter was trying to highlight the
term "a", and the escaped description contained "&apos;", the "a" in
that would be considered a match and surrounded by "<b></b>". This
however would also generate invalid markup, again leading to an error
and the description not being shown.
Fix this by always escaping the passed in string before applying the
highlights in such a way that there are no matches within entities.
This also means that search providers that escaped their description
strings will now show up with the markup syntax. This will have to be
fixed separately in the affected search providers.
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4791
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2033>
---
js/misc/util.js | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/js/misc/util.js b/js/misc/util.js
index d1a702960..802398d18 100644
--- a/js/misc/util.js
+++ b/js/misc/util.js
@@ -508,8 +508,25 @@ var Highlighter = class {
*/
highlight(text) {
if (!this._highlightRegex)
- return text;
+ return GLib.markup_escape_text(text, -1);
+
+ let escaped = [];
+ let lastMatchEnd = 0;
+ let match;
+ while ((match = this._highlightRegex.exec(text))) {
+ if (match.index > lastMatchEnd) {
+ let unmatched = GLib.markup_escape_text(
+ text.slice(lastMatchEnd, match.index), -1);
+ escaped.push(unmatched);
+ }
+ let matched = GLib.markup_escape_text(match[0], -1);
+ escaped.push('<b>%s</b>'.format(matched));
+ lastMatchEnd = match.index + match[0].length;
+ }
+ let unmatched = GLib.markup_escape_text(
+ text.slice(lastMatchEnd), -1);
+ escaped.push(unmatched);
- return text.replace(this._highlightRegex, '<b>$1</b>');
+ return escaped.join('');
}
};
--
2.35.1
From 82e2a6dcfabc2f82efbf468175d16c303f0c73da Mon Sep 17 00:00:00 2001
From: Sebastian Keller <skeller@gnome.org>
Date: Wed, 17 Nov 2021 03:05:05 +0100
Subject: [PATCH 3/3] tests: Add unit test for highlighter
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2033>
---
tests/meson.build | 12 ++++-
tests/unit/highlighter.js | 106 ++++++++++++++++++++++++++++++++++++++
2 files changed, 117 insertions(+), 1 deletion(-)
create mode 100644 tests/unit/highlighter.js
diff --git a/tests/meson.build b/tests/meson.build
index c0431631f..50fb601e9 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -10,7 +10,17 @@ run_test = configure_file(
testenv = environment()
testenv.set('GSETTINGS_SCHEMA_DIR', join_paths(meson.build_root(), 'data'))
-foreach test : ['insertSorted', 'jsParse', 'markup', 'params', 'url', 'versionCompare']
+tests = [
+ 'highlighter',
+ 'insertSorted',
+ 'jsParse',
+ 'markup',
+ 'params',
+ 'url',
+ 'versionCompare',
+]
+
+foreach test : tests
test(test, run_test,
args: 'unit/@0@.js'.format(test),
env: testenv,
diff --git a/tests/unit/highlighter.js b/tests/unit/highlighter.js
new file mode 100644
index 000000000..d582d38e3
--- /dev/null
+++ b/tests/unit/highlighter.js
@@ -0,0 +1,106 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+// Test cases for SearchResult description match highlighter
+
+const JsUnit = imports.jsUnit;
+const Pango = imports.gi.Pango;
+
+const Environment = imports.ui.environment;
+Environment.init();
+
+const Util = imports.misc.util;
+
+const tests = [
+ { input: 'abc cba',
+ terms: null,
+ output: 'abc cba' },
+ { input: 'abc cba',
+ terms: [],
+ output: 'abc cba' },
+ { input: 'abc cba',
+ terms: [''],
+ output: 'abc cba' },
+ { input: 'abc cba',
+ terms: ['a'],
+ output: '<b>a</b>bc cb<b>a</b>' },
+ { input: 'abc cba',
+ terms: ['a', 'a'],
+ output: '<b>a</b>bc cb<b>a</b>' },
+ { input: 'CaSe InSenSiTiVe',
+ terms: ['cas', 'sens'],
+ output: '<b>CaS</b>e In<b>SenS</b>iTiVe' },
+ { input: 'This contains the < character',
+ terms: null,
+ output: 'This contains the &lt; character' },
+ { input: 'Don\'t',
+ terms: ['t'],
+ output: 'Don&apos;<b>t</b>' },
+ { input: 'Don\'t',
+ terms: ['n\'t'],
+ output: 'Do<b>n&apos;t</b>' },
+ { input: 'Don\'t',
+ terms: ['o', 't'],
+ output: 'D<b>o</b>n&apos;<b>t</b>' },
+ { input: 'salt&pepper',
+ terms: ['salt'],
+ output: '<b>salt</b>&amp;pepper' },
+ { input: 'salt&pepper',
+ terms: ['salt', 'alt'],
+ output: '<b>salt</b>&amp;pepper' },
+ { input: 'salt&pepper',
+ terms: ['pepper'],
+ output: 'salt&amp;<b>pepper</b>' },
+ { input: 'salt&pepper',
+ terms: ['salt', 'pepper'],
+ output: '<b>salt</b>&amp;<b>pepper</b>' },
+ { input: 'salt&pepper',
+ terms: ['t', 'p'],
+ output: 'sal<b>t</b>&amp;<b>p</b>e<b>p</b><b>p</b>er' },
+ { input: 'salt&pepper',
+ terms: ['t', '&', 'p'],
+ output: 'sal<b>t</b><b>&amp;</b><b>p</b>e<b>p</b><b>p</b>er' },
+ { input: 'salt&pepper',
+ terms: ['e'],
+ output: 'salt&amp;p<b>e</b>pp<b>e</b>r' },
+ { input: 'salt&pepper',
+ terms: ['&a', '&am', '&amp', '&amp;'],
+ output: 'salt&amp;pepper' },
+ { input: '&&&&&',
+ terms: ['a'],
+ output: '&amp;&amp;&amp;&amp;&amp;' },
+ { input: '&;&;&;&;&;',
+ terms: ['a'],
+ output: '&amp;;&amp;;&amp;;&amp;;&amp;;' },
+ { input: '&;&;&;&;&;',
+ terms: [';'],
+ output: '&amp;<b>;</b>&amp;<b>;</b>&amp;<b>;</b>&amp;<b>;</b>&amp;<b>;</b>' },
+ { input: '&amp;',
+ terms: ['a'],
+ output: '&amp;<b>a</b>mp;' }
+];
+
+try {
+ for (let i = 0; i < tests.length; i++) {
+ let highlighter = new Util.Highlighter(tests[i].terms);
+ let output = highlighter.highlight(tests[i].input);
+
+ JsUnit.assertEquals(`Test ${i + 1} highlight ` +
+ `"${tests[i].terms}" in "${tests[i].input}"`,
+ output, tests[i].output);
+
+ let parsed = false;
+ try {
+ Pango.parse_markup(output, -1, '');
+ parsed = true;
+ } catch (e) {}
+ JsUnit.assertEquals(`Test ${i + 1} is valid markup`, true, parsed);
+ }
+} catch (e) {
+ if (typeof(e.isJsUnitException) != 'undefined'
+ && e.isJsUnitException)
+ {
+ if (e.comment)
+ log(`Error in: ${e.comment}`);
+ }
+ throw e;
+}
--
2.35.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

@ -1,92 +0,0 @@
From ce8ac36613ef4fbb697fc9f6613844168c05a8d3 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 8 Oct 2021 11:08:17 -0400
Subject: [PATCH 1/2] unlockDialog: Don't create AuthDialog just to finish it
If the the unlock dialog gets finished before an auth dialog is
created, the code currently creates one just to tell it to finish.
This commit changes the code to skip creating the auth dialog in
that case.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1999>
---
js/ui/unlockDialog.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js
index c81c6184a9..d8c45f7510 100644
--- a/js/ui/unlockDialog.js
+++ b/js/ui/unlockDialog.js
@@ -884,7 +884,11 @@ var UnlockDialog = GObject.registerClass({
}
finish(onComplete) {
- this._ensureAuthPrompt();
+ if (!this._authPrompt) {
+ onComplete();
+ return;
+ }
+
this._authPrompt.finish(onComplete);
}
--
2.39.1
From 2a513d44e7b887b355d6b71cf88c4114a8b685f8 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 5 Oct 2021 11:01:19 -0400
Subject: [PATCH 2/2] unlockDialog: Properly reset auth prompt when showing it
If a user hits escape twice really fast when coming back to
their machine to unlock it, they made end up getting presented
with a non-functional unlock screen that doesn't show their
user icon and doesn't ask for a password.
This is because showPrompt assumes that if an auth prompt already
exists, it's ready to go. That may not be true, if it's in the
process of getting torn down at the time because it's in the middle
of a cancel animation.
This commit solves the problem by ensuring the auth prompt is always
in a fresh reset state before showing it.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1999>
---
js/ui/unlockDialog.js | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js
index d8c45f7510..00e3eef971 100644
--- a/js/ui/unlockDialog.js
+++ b/js/ui/unlockDialog.js
@@ -689,16 +689,14 @@ var UnlockDialog = GObject.registerClass({
}
_ensureAuthPrompt() {
- if (this._authPrompt)
- return;
-
- 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));
-
- this._promptBox.add_child(this._authPrompt);
+ if (!this._authPrompt) {
+ 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));
+ this._promptBox.add_child(this._authPrompt);
+ }
this._authPrompt.reset();
this._authPrompt.updateSensitivity(true);
--
2.39.1

@ -1,7 +1,47 @@
From 05a5f4641c8ad6337ccb46e63abcaf27dd7eb852 Mon Sep 17 00:00:00 2001
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 1/4] popupMenu: Guard against non-menu-item children
Subject: [PATCH 2/6] popupMenu: Guard against non-menu-item children
This avoid a harmless but annoying warning.
---
@ -9,10 +49,10 @@ This avoid a harmless but annoying warning.
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
index 11528560d..144c600d7 100644
index 44818533a..b5115d7f7 100644
--- a/js/ui/popupMenu.js
+++ b/js/ui/popupMenu.js
@@ -773,7 +773,8 @@ var PopupMenuBase = class {
@@ -696,7 +696,8 @@ var PopupMenuBase = class {
}
_getMenuItems() {
@ -23,13 +63,13 @@ index 11528560d..144c600d7 100644
});
}
--
2.31.1
2.33.1
From e5b2c2b3cfd0443fa83fd1f6f56f65fefa5186c3 Mon Sep 17 00:00:00 2001
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 2/4] st/shadow: Check pipeline when painting
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.
@ -38,10 +78,10 @@ called before paint() or that the pipeline was created successfully.
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/st/st-shadow.c b/src/st/st-shadow.c
index ab3eaa856..d53808698 100644
index f3a22f034..7665de755 100644
--- a/src/st/st-shadow.c
+++ b/src/st/st-shadow.c
@@ -296,9 +296,10 @@ st_shadow_helper_paint (StShadowHelper *helper,
@@ -289,9 +289,10 @@ st_shadow_helper_paint (StShadowHelper *helper,
ClutterActorBox *actor_box,
guint8 paint_opacity)
{
@ -58,127 +98,126 @@ index ab3eaa856..d53808698 100644
+ paint_opacity);
}
--
2.31.1
2.33.1
From 0f7656d85af51339d14217b9a673442a18df3de8 Mon Sep 17 00:00:00 2001
From b57d6efccbeb139d6c7c1894f83caa7a26fd6bad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 8 Jul 2021 19:10:05 +0200
Subject: [PATCH 3/4] messageTray: Always remove destroyed banners
Currently we only mark the banner as removed if it is destroyed
while in SHOWN or SHOWING state, but not if we're already HIDING
(for example in response to `NotificationBanner::done-displaying`).
If this happens, we'll try to destroy the notification again at
the end of the transition, which leads to (harmless but annoying)
log spam since Notifications were turned into GObjects (that are
disposed when destroyed).
Address this by always marking destroyed banners as removed, while
still only triggering a state update while shown (or in the process
of being shown).
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4457
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/messageTray.js | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
index 1dab00a70..ccf56fc5b 100644
--- a/js/ui/messageTray.js
+++ b/js/ui/messageTray.js
@@ -1022,17 +1022,20 @@ var MessageTray = GObject.registerClass({
}
_onNotificationDestroy(notification) {
- if (this._notification == notification && (this._notificationState == State.SHOWN || this._notificationState == State.SHOWING)) {
- this._updateNotificationTimeout(0);
- this._notificationRemoved = true;
- this._updateState();
- return;
- }
+ this._notificationRemoved = this._notification === notification;
- let index = this._notificationQueue.indexOf(notification);
- if (index != -1) {
- this._notificationQueue.splice(index, 1);
- this.emit('queue-changed');
+ if (this._notificationRemoved) {
+ if (this._notificationState === State.SHOWN ||
+ this._notificationState === State.SHOWING) {
+ this._updateNotificationTimeout(0);
+ this._updateState();
+ }
+ } else {
+ const index = this._notificationQueue.indexOf(notification);
+ if (index !== -1) {
+ this._notificationQueue.splice(index, 1);
+ this.emit('queue-changed');
+ }
}
}
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.31.1
2.33.1
From 8652836521d0729ce230268c7b448cdb393d5b47 Mon Sep 17 00:00:00 2001
From 0c76c91c3d16c8386a242daf367d66057364a5d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 8 Jul 2021 19:23:38 +0200
Subject: [PATCH 4/4] shellInfo: Don't destroy source on undo
Destroying the source from an action callback will result in the
notification being destroyed twice:
- source.destroy() destroys all its notifications
- a notification destroys itself after an action
was activated
This results in unwanted log spam when attempting to dispose the
notification for a second time.
Date: Fri, 23 Oct 2020 23:44:48 +0200
Subject: [PATCH 5/6] workspacesView: Don't set up MetaLater when unparented
There is actually no good reason for destroying the source explicitly,
as sources already self-destruct with their last notification.
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4457
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/overview.js | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/js/ui/overview.js b/js/ui/overview.js
index 529779ea8..c71b11389 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -25,16 +25,6 @@ var OVERVIEW_ACTIVATION_TIMEOUT = 0.5;
var ShellInfo = class {
constructor() {
this._source = null;
- this._undoCallback = null;
- }
-
- _onUndoClicked() {
- if (this._undoCallback)
- this._undoCallback();
- this._undoCallback = null;
-
- if (this._source)
- this._source.destroy();
}
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
setMessage(text, options) {
@@ -64,9 +54,8 @@ var ShellInfo = class {
notification.update(text, null, { clear: true });
}
- this._undoCallback = undoCallback;
if (undoCallback)
- notification.addAction(_("Undo"), this._onUndoClicked.bind(this));
+ notification.addAction(_('Undo'), () => undoCallback());
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
this._source.showNotification(notification);
}
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.31.1
2.33.1

@ -1,4 +1,4 @@
From 1eb9fef5e18d56bbe7a6422303ff8e31fe677759 Mon Sep 17 00:00:00 2001
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
@ -12,10 +12,10 @@ failing silently, turn the item insensitive.
1 file changed, 12 insertions(+)
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
index 5487fde40..6e7878d20 100644
index b3bb7589c..3ad7b04dd 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -563,6 +563,10 @@ var NMDeviceModem = class extends NMConnectionDevice {
@@ -514,6 +514,10 @@ var NMDeviceModem = class extends NMConnectionDevice {
this._iconChanged();
});
}
@ -26,8 +26,8 @@ index 5487fde40..6e7878d20 100644
}
get category() {
@@ -573,6 +577,10 @@ var NMDeviceModem = class extends NMConnectionDevice {
launchSettingsPanel('network', 'connect-3g', this._device.get_path());
@@ -525,6 +529,10 @@ var NMDeviceModem = class extends NMConnectionDevice {
'connect-3g', this._device.get_path()]);
}
+ _sessionUpdated() {
@ -37,7 +37,7 @@ index 5487fde40..6e7878d20 100644
destroy() {
if (this._operatorNameId) {
this._mobileDevice.disconnect(this._operatorNameId);
@@ -582,6 +590,10 @@ var NMDeviceModem = class extends NMConnectionDevice {
@@ -534,6 +542,10 @@ var NMDeviceModem = class extends NMConnectionDevice {
this._mobileDevice.disconnect(this._signalQualityId);
this._signalQualityId = 0;
}
@ -52,7 +52,7 @@ index 5487fde40..6e7878d20 100644
2.31.1
From 0288558940c0090dca0873daeaa33e8d20cdbb0f Mon Sep 17 00:00:00 2001
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
@ -62,35 +62,34 @@ 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 | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
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 6e7878d20..36915dbc1 100644
index 3ad7b04dd..c023022a7 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -1,6 +1,6 @@
@@ -1,5 +1,5 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported NMApplet */
-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;
const Animation = imports.ui.animation;
@@ -816,6 +816,11 @@ class NMWirelessDialog extends ModalDialog.ModalDialog {
GLib.source_remove(this._scanTimeoutId);
@@ -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();
}
_onScanTimeout() {
@@ -1149,9 +1154,32 @@ class NMWirelessDialog extends ModalDialog.ModalDialog {
this._itemBox.insert_child_at_index(network.item, newPos);
@@ -1081,9 +1086,31 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog {
this._itemBox.insert_child_at_index(network.item.actor, newPos);
}
+ this._queueSyncItemVisibility();
@ -114,7 +113,6 @@ index 6e7878d20..36915dbc1 100644
+ network.connections.length > 0 ||
+ (firstAp._secType !== WPA2_ENT && firstAp._secType !== WPA_ENT);
+ }
+ this._syncVisibilityId = 0;
+ return GLib.SOURCE_REMOVE;
+ });
+ }
@ -126,7 +124,7 @@ index 6e7878d20..36915dbc1 100644
2.31.1
From eb9620bc134ef8e7732f5e64b93ac9ea5bba2092 Mon Sep 17 00:00:00 2001
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
@ -136,33 +134,37 @@ 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 | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
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 36915dbc1..e238fdfe7 100644
index c023022a7..79729e01b 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -1,6 +1,6 @@
@@ -1,5 +1,5 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported NMApplet */
-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;
const Animation = imports.ui.animation;
@@ -1750,11 +1750,21 @@ class Indicator extends PanelMenu.SystemIndicator {
@@ -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 = await Polkit.Permission.new(
+ 'org.freedesktop.NetworkManager.network-control', null, null);
+ this._configPermission = Polkit.Permission.new_finish(res);
+ } catch (e) {
+ log('No permission to control network connections: %s'.format(e.toString()));
+ this._configPermission = null;
+ }
this._sessionUpdated();
+ this._sessionUpdated();
+ });
}
_sessionUpdated() {
@ -178,7 +180,7 @@ index 36915dbc1..e238fdfe7 100644
2.31.1
From 2392810bb7e3d48fb33c4d6de39f5be2eca58988 Mon Sep 17 00:00:00 2001
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
@ -191,10 +193,10 @@ requests (like wifi/VPN passwords).
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js
index aa69fd115..4d4fb2444 100644
index 25aa75a3d..fa7f83416 100644
--- a/js/ui/sessionMode.js
+++ b/js/ui/sessionMode.js
@@ -47,7 +47,9 @@ const _modes = {
@@ -43,7 +43,9 @@ const _modes = {
isGreeter: true,
isPrimary: true,
unlockDialog: imports.gdm.loginDialog.LoginDialog,
@ -209,7 +211,7 @@ index aa69fd115..4d4fb2444 100644
2.31.1
From b5fedfd846f271bf28be02ce5cd8517af7a3bc0a Mon Sep 17 00:00:00 2001
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
@ -228,10 +230,10 @@ old behavior if desired.
1 file changed, 1 deletion(-)
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
index e238fdfe7..f510f90ae 100644
index 79729e01b..914dbbd99 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -1763,7 +1763,6 @@ class Indicator extends PanelMenu.SystemIndicator {
@@ -1700,7 +1700,6 @@ var NMApplet = class extends PanelMenu.SystemIndicator {
_sessionUpdated() {
const sensitive =
!Main.sessionMode.isLocked &&

@ -1,67 +0,0 @@
From 1f8252470ce43dc8a0680871013e2f4492764302 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Mon, 28 Feb 2022 10:27:09 -0500
Subject: [PATCH] data: Enable logo extension out of the box
Our brand team would like the logo extension to be used on new
installs.
This commit makes sure it gets enabled out of the box.
---
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 d5ea1e3..e3f440c 100644
--- a/data/org.gnome.shell.gschema.xml.in
+++ b/data/org.gnome.shell.gschema.xml.in
@@ -1,45 +1,45 @@
<schemalist>
<schema id="org.gnome.shell" path="/org/gnome/shell/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="development-tools" type="b">
<default>true</default>
<summary>
Enable internal tools useful for developers and testers from Alt-F2
</summary>
<description>
Allows access to internal debugging and monitoring tools
using the Alt-F2 dialog.
</description>
</key>
<key name="enabled-extensions" type="as">
- <default>[]</default>
+ <default>['background-logo@fedorahosted.org']</default>
<summary>UUIDs of extensions to enable</summary>
<description>
GNOME Shell extensions have a UUID property; this key lists extensions
which should be loaded. Any extension that wants to be loaded needs
to be in this list. You can also manipulate this list with the
EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell.
</description>
</key>
<key name="disabled-extensions" type="as">
<default>[]</default>
<summary>UUIDs of extensions to force disabling</summary>
<description>
GNOME Shell extensions have a UUID property; this key lists extensions
which should be disabled, even if loaded as part of the current mode.
You can also manipulate this list with the EnableExtension and
DisableExtension D-Bus methods on org.gnome.Shell.
This key takes precedence over the “enabled-extensions” setting.
</description>
</key>
<key name="disable-user-extensions" type="b">
<default>false</default>
<summary>Disable user extensions</summary>
<description>
Disable all extensions the user has enabled without affecting
the “enabled-extension” setting.
</description>
</key>
<key name="disable-extension-version-validation" type="b">
<default>false</default>
<summary>Disables the validation of extension version compatibility</summary>
--
2.35.1

@ -1,7 +1,7 @@
From a2e62e671260576d23f18c22c10a48ac4a8504af Mon Sep 17 00:00:00 2001
From 87104647f061892525236a71f304b63609960626 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 17 Sep 2014 07:11:12 +0200
Subject: [PATCH] Replace Web with Firefox in default favorites
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 +-
@ -9,23 +9,23 @@ Subject: [PATCH] Replace Web with Firefox in default favorites
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 cd6a2356d..b8a13a9cc 100644
index 24e2a75b0..2f50036d0 100644
--- a/data/org.gnome.shell.gschema.xml.in
+++ b/data/org.gnome.shell.gschema.xml.in
@@ -50,7 +50,7 @@
@@ -39,7 +39,7 @@
</description>
</key>
<key name="favorite-apps" type="as">
- <default>[ 'org.gnome.Epiphany.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
+ <default>[ 'firefox.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
- <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 a876727ed..24ce16f81 100644
index 657e15965..1e44a1655 100644
--- a/js/ui/appFavorites.js
+++ b/js/ui/appFavorites.js
@@ -52,6 +52,7 @@ const RENAMED_DESKTOP_IDS = {
@@ -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',
@ -34,5 +34,5 @@ index a876727ed..24ce16f81 100644
'org.gnome.gnome-2048.desktop': 'org.gnome.TwentyFortyEight.desktop',
'org.gnome.taquin.desktop': 'org.gnome.Taquin.desktop',
--
2.30.1
2.21.0

@ -1,25 +1,25 @@
From 1e699b55f3dc84b2ddbc5acd03424240eddbe06c Mon Sep 17 00:00:00 2001
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 3/3] appFavorites: Add terminal
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 35ddaf4a9..d5ea1e35f 100644
index 40526187e..9d7e011fc 100644
--- a/data/org.gnome.shell.gschema.xml.in
+++ b/data/org.gnome.shell.gschema.xml.in
@@ -50,7 +50,7 @@
@@ -39,7 +39,7 @@
</description>
</key>
<key name="favorite-apps" type="as">
- <default>[ 'firefox.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop' ]</default>
+ <default>[ 'firefox.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop', 'org.gnome.Terminal.desktop' ]</default>
- <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.31.1
2.21.0

@ -1,7 +1,7 @@
From 4e21aed64d48ddd22e40a3605084379b2fa7f1cb Mon Sep 17 00:00:00 2001
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 2/3] Add 'yelp' to default favorites
Subject: [PATCH] Add 'yelp' to default favorites
Help should be easily available, so add it to the default favorites.
---
@ -9,18 +9,18 @@ Help should be easily available, so add it to the default favorites.
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 b8a13a9cc..35ddaf4a9 100644
index 2f50036d0..40526187e 100644
--- a/data/org.gnome.shell.gschema.xml.in
+++ b/data/org.gnome.shell.gschema.xml.in
@@ -50,7 +50,7 @@
@@ -39,7 +39,7 @@
</description>
</key>
<key name="favorite-apps" type="as">
- <default>[ 'firefox.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
+ <default>[ 'firefox.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.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' ]</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.31.1
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

@ -1,227 +0,0 @@
From 4024d59871d0c8990ef5e4243c9fc485971755e7 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Aug 2021 13:25:57 -0400
Subject: [PATCH 1/3] 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 | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index 9f4eb757b..2aae44b53 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -23,7 +23,6 @@ const UPDATE_CHECK_TIMEOUT = 24 * 60 * 60; // 1 day in seconds
var ExtensionManager = class {
constructor() {
this._initialized = false;
- this._enabled = false;
this._updateNotified = false;
this._extensions = new Map();
@@ -597,9 +596,6 @@ var ExtensionManager = class {
}
_enableAllExtensions() {
- if (this._enabled)
- return;
-
if (!this._initialized) {
this._loadExtensions();
this._initialized = true;
@@ -608,20 +604,14 @@ var ExtensionManager = class {
this._callExtensionEnable(uuid);
});
}
- this._enabled = true;
}
_disableAllExtensions() {
- if (!this._enabled)
- return;
-
if (this._initialized) {
this._extensionOrder.slice().reverse().forEach(uuid => {
this._callExtensionDisable(uuid);
});
}
-
- this._enabled = false;
}
_sessionUpdated() {
--
2.33.1
From f883c3f87f9778a0c2ed34db648aad73668949e3 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Sat, 28 Aug 2021 13:54:39 -0400
Subject: [PATCH 2/3] 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 | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index 2aae44b53..937f86199 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -75,6 +75,28 @@ var ExtensionManager = class {
return [...this._extensions.keys()];
}
+ _extensionSupportsSessionMode(uuid) {
+ const 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)
@@ -134,7 +156,7 @@ var ExtensionManager = class {
}
_callExtensionEnable(uuid) {
- if (!Main.sessionMode.allowExtensions)
+ if (!this._sessionModeCanUseExtension(uuid))
return;
let extension = this.lookup(uuid);
@@ -316,6 +338,7 @@ var ExtensionManager = class {
hasPrefs: dir.get_child('prefs.js').query_exists(null),
hasUpdate: false,
canChange: false,
+ sessionModes: meta['session-modes'] ? meta['session-modes'] : [ 'user' ],
};
this._extensions.set(uuid, extension);
@@ -398,7 +421,7 @@ var ExtensionManager = class {
}
_callExtensionInit(uuid) {
- if (!Main.sessionMode.allowExtensions)
+ if (!this._sessionModeCanUseExtension(uuid))
return false;
let extension = this.lookup(uuid);
@@ -487,13 +510,15 @@ var ExtensionManager = class {
// 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))
+ .filter(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.
this._extensionOrder
- .filter(uuid => !newEnabledExtensions.includes(uuid))
+ .filter(uuid => !newEnabledExtensions.includes(uuid) ||
+ !this._extensionSupportsSessionMode(uuid))
.reverse().forEach(uuid => this._callExtensionDisable(uuid));
this._enabledExtensions = newEnabledExtensions;
--
2.33.1
From c637d0a14ea7223ea7d763e1c4dedb4d6b6609a4 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Aug 2021 15:31:00 -0400
Subject: [PATCH 3/3] 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 | 2 ++
1 file changed, 2 insertions(+)
diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js
index 4d4fb2444..0534fd1d4 100644
--- a/js/ui/sessionMode.js
+++ b/js/ui/sessionMode.js
@@ -43,6 +43,7 @@ const _modes = {
},
'gdm': {
+ allowExtensions: true,
hasNotifications: true,
isGreeter: true,
isPrimary: true,
@@ -59,6 +60,7 @@ const _modes = {
},
'unlock-dialog': {
+ allowExtensions: true,
isLocked: true,
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
--
2.33.1

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

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save