Compare commits
No commits in common. 'c8-beta' and 'c9' have entirely different histories.
@ -1 +1 @@
|
||||
SOURCES/gnome-shell-3.32.2.tar.xz
|
||||
SOURCES/gnome-shell-40.10.tar.xz
|
||||
|
@ -1 +1 @@
|
||||
331e9cf71cd1d2a4e9238d87d216da4c6f3a400e SOURCES/gnome-shell-3.32.2.tar.xz
|
||||
c955a004fb650a83863d1151e3adbbd6758b1c2e SOURCES/gnome-shell-40.10.tar.xz
|
||||
|
@ -1,25 +0,0 @@
|
||||
From f5ddd0fc02e99597e4b8506ac35523a6fa8ac22f Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Wed, 4 Mar 2020 16:08:31 +0100
|
||||
Subject: [PATCH] Do not change Wacom LEDs through g-s-d
|
||||
|
||||
Let the wacom kernel driver sort it out by itself.
|
||||
---
|
||||
js/ui/windowManager.js | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
|
||||
index dfe1b44..b2e938c 100644
|
||||
--- a/js/ui/windowManager.js
|
||||
+++ b/js/ui/windowManager.js
|
||||
@@ -1037,7 +1037,6 @@ var WindowManager = class {
|
||||
|
||||
if (this._gsdWacomProxy) {
|
||||
this._gsdWacomProxy.SetOLEDLabelsRemote(pad.get_device_node(), labels);
|
||||
- this._gsdWacomProxy.SetGroupModeLEDRemote(pad.get_device_node(), group, mode);
|
||||
}
|
||||
});
|
||||
|
||||
--
|
||||
2.24.1
|
||||
|
@ -0,0 +1,25 @@
|
||||
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
|
||||
|
@ -0,0 +1,364 @@
|
||||
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
|
||||
|
@ -1,58 +0,0 @@
|
||||
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
|
||||
|
@ -1,40 +0,0 @@
|
||||
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,111 +0,0 @@
|
||||
From a1c35ebb8f29103035526e6f48eba4ff37551964 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 21 Jun 2018 18:03:31 +0200
|
||||
Subject: [PATCH] appDisplay: Show full app name on hover
|
||||
|
||||
---
|
||||
data/theme/gnome-shell-sass/_common.scss | 8 ++++
|
||||
js/ui/appDisplay.js | 48 ++++++++++++++++++++++++
|
||||
2 files changed, 56 insertions(+)
|
||||
|
||||
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
|
||||
index 3b0d2bf04..293ea2ab9 100644
|
||||
--- a/data/theme/gnome-shell-sass/_common.scss
|
||||
+++ b/data/theme/gnome-shell-sass/_common.scss
|
||||
@@ -1411,6 +1411,14 @@ StScrollBar {
|
||||
|
||||
}
|
||||
|
||||
+ .app-well-hover-text {
|
||||
+ text-align: center;
|
||||
+ color: $osd_fg_color;
|
||||
+ background-color: $osd_bg_color;
|
||||
+ border-radius: 5px;
|
||||
+ padding: 3px;
|
||||
+ }
|
||||
+
|
||||
.app-well-app-running-dot { //running apps indicator
|
||||
width: 10px; height: 3px;
|
||||
background-color: $selected_bg_color;
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index adaefa7dd..a07db6573 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -1478,6 +1478,20 @@ var AppIcon = class AppIcon {
|
||||
this.actor.connect('clicked', this._onClicked.bind(this));
|
||||
this.actor.connect('popup-menu', this._onKeyboardPopupMenu.bind(this));
|
||||
|
||||
+ this._hoverText = null;
|
||||
+ this._hoverTimeoutId = 0;
|
||||
+
|
||||
+ if (this.icon.label) {
|
||||
+ this._hoverText = new St.Label({ style_class: 'app-well-hover-text',
|
||||
+ text: this.icon.label.text,
|
||||
+ visible: false });
|
||||
+ this._hoverText.clutter_text.line_wrap = true;
|
||||
+ Main.layoutManager.addChrome(this._hoverText);
|
||||
+
|
||||
+ this.actor.connect('notify::hover', this._syncHoverText.bind(this));
|
||||
+ this.connect('sync-tooltip', this._syncHoverText.bind(this));
|
||||
+ }
|
||||
+
|
||||
this._menu = null;
|
||||
this._menuManager = new PopupMenu.PopupMenuManager(this);
|
||||
|
||||
@@ -1509,12 +1523,39 @@ var AppIcon = class AppIcon {
|
||||
this.app.disconnect(this._stateChangedId);
|
||||
this._stateChangedId = 0;
|
||||
this._removeMenuTimeout();
|
||||
+ this._removeHoverTimeout();
|
||||
+ if (this._hoverText)
|
||||
+ this._hoverText.destroy();
|
||||
+ this._hoverText = null;
|
||||
}
|
||||
|
||||
_createIcon(iconSize) {
|
||||
return this.app.create_icon_texture(iconSize);
|
||||
}
|
||||
|
||||
+ _syncHoverText() {
|
||||
+ if (this.shouldShowTooltip()) {
|
||||
+ if (this._hoverTimeoutId)
|
||||
+ return;
|
||||
+
|
||||
+ this._hoverTimeoutId = Mainloop.timeout_add(300, () => {
|
||||
+ this._hoverText.style = `max-width: ${2 * this.icon.iconSize}px;`;
|
||||
+ this._hoverText.ensure_style();
|
||||
+
|
||||
+ let [x, y] = this.icon.label.get_transformed_position();
|
||||
+ let offset = (this._hoverText.width - this.icon.label.width) / 2;
|
||||
+ this._hoverText.set_position(Math.floor(x - offset), Math.floor(y));
|
||||
+ this._hoverText.show();
|
||||
+
|
||||
+ this._hoverTimeoutId = 0;
|
||||
+ return GLib.SOURCE_REMOVE;
|
||||
+ });
|
||||
+ } else {
|
||||
+ this._removeHoverTimeout();
|
||||
+ this._hoverText.hide();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
_removeMenuTimeout() {
|
||||
if (this._menuTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
@@ -1522,6 +1563,13 @@ var AppIcon = class AppIcon {
|
||||
}
|
||||
}
|
||||
|
||||
+ _removeHoverTimeout() {
|
||||
+ if (this._hoverTimeoutId > 0) {
|
||||
+ Mainloop.source_remove(this._hoverTimeoutId);
|
||||
+ this._hoverTimeoutId = 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
_updateRunningStyle() {
|
||||
if (this.app.state != Shell.AppState.STOPPED)
|
||||
this._dot.show();
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,100 @@
|
||||
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
|
||||
|
@ -1,29 +0,0 @@
|
||||
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
|
||||
|
@ -1,37 +0,0 @@
|
||||
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
|
||||
|
@ -1,65 +0,0 @@
|
||||
From 6e80934456f0b4cc48da6a7201700dc4386a3474 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 27 Feb 2020 13:46:44 -0800
|
||||
Subject: [PATCH] environment: reduce calls to g_time_zone_new_local()
|
||||
|
||||
Creating a new GTimeZone for the local timezone can be quite expensive if
|
||||
done repeatedly. It requires an open(), mmap(), and parsing of
|
||||
/etc/localtime.
|
||||
|
||||
This patch was provided by Florian, and I've tested it as far back as
|
||||
3.28.4 to ensure that we are really reducing the number of open() calls
|
||||
on the compositor thread.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/1051
|
||||
|
||||
Signed-off-by: Christian Hergert <chergert@redhat.com>
|
||||
---
|
||||
js/ui/environment.js | 22 +++++++++++++++++++++-
|
||||
1 file changed, 21 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/environment.js b/js/ui/environment.js
|
||||
index 9c125d3eb..809b48e45 100644
|
||||
--- a/js/ui/environment.js
|
||||
+++ b/js/ui/environment.js
|
||||
@@ -11,6 +11,9 @@ imports.gi.versions.TelepathyLogger = '0.2';
|
||||
|
||||
const { Clutter, Gio, GLib, Shell, St } = imports.gi;
|
||||
const Gettext = imports.gettext;
|
||||
+const System = imports.system;
|
||||
+
|
||||
+let _localTimeZone = null;
|
||||
|
||||
// We can't import shell JS modules yet, because they may have
|
||||
// variable initializations, etc, that depend on init() already having
|
||||
@@ -117,9 +120,26 @@ function init() {
|
||||
}
|
||||
};
|
||||
|
||||
+ // Override to clear our own timezone cache as well
|
||||
+ const origClearDateCaches = System.clearDateCaches;
|
||||
+ System.clearDateCaches = function () {
|
||||
+ _localTimeZone = null;
|
||||
+ origClearDateCaches();
|
||||
+ };
|
||||
+
|
||||
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
|
||||
Date.prototype.toLocaleFormat = function(format) {
|
||||
- return Shell.util_format_date(format, this.getTime());
|
||||
+ if (_localTimeZone === null)
|
||||
+ _localTimeZone = GLib.TimeZone.new_local();
|
||||
+
|
||||
+ let dt = GLib.DateTime.new(_localTimeZone,
|
||||
+ this.getYear(),
|
||||
+ this.getMonth() + 1,
|
||||
+ this.getDate(),
|
||||
+ this.getHours(),
|
||||
+ this.getMinutes(),
|
||||
+ this.getSeconds());
|
||||
+ return dt ? dt.format(format) : '';
|
||||
};
|
||||
|
||||
let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR');
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,36 @@
|
||||
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
|
||||
|
@ -1,87 +0,0 @@
|
||||
From 1b6eb29ade832647510b36ddc13c9b88a25036df Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
|
||||
Date: Wed, 11 Sep 2019 20:18:20 +0200
|
||||
Subject: [PATCH 1/4] extensionSystem: Handle added or removed sessionMode
|
||||
extensions
|
||||
|
||||
Right now we're only handling added sessionMode extensions correctly on
|
||||
sessionMode updates, also handle the other case and disable removed
|
||||
sessionMode extensions on sessionMode updates.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/96
|
||||
---
|
||||
js/ui/extensionSystem.js | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
|
||||
index 81804ea5e..77929f2a6 100644
|
||||
--- a/js/ui/extensionSystem.js
|
||||
+++ b/js/ui/extensionSystem.js
|
||||
@@ -515,62 +515,62 @@ var ExtensionManager = class {
|
||||
if (!this._initted) {
|
||||
this._loadExtensions();
|
||||
this._initted = true;
|
||||
} else {
|
||||
this._enabledExtensions.forEach(uuid => {
|
||||
this._callExtensionEnable(uuid);
|
||||
});
|
||||
}
|
||||
this._enabled = true;
|
||||
}
|
||||
|
||||
_disableAllExtensions() {
|
||||
if (!this._enabled)
|
||||
return;
|
||||
|
||||
if (this._initted) {
|
||||
this._extensionOrder.slice().reverse().forEach(uuid => {
|
||||
this._callExtensionDisable(uuid);
|
||||
});
|
||||
}
|
||||
|
||||
this._enabled = false;
|
||||
}
|
||||
|
||||
_sessionUpdated() {
|
||||
// For now sessionMode.allowExtensions controls extensions from both the
|
||||
// 'enabled-extensions' preference and the sessionMode.enabledExtensions
|
||||
// property; it might make sense to make enabledExtensions independent
|
||||
// from allowExtensions in the future
|
||||
if (Main.sessionMode.allowExtensions) {
|
||||
- if (this._initted)
|
||||
- this._enabledExtensions = this._getEnabledExtensions();
|
||||
+ // Take care of added or removed sessionMode extensions
|
||||
+ this._onEnabledExtensionsChanged();
|
||||
this._enableAllExtensions();
|
||||
} else {
|
||||
this._disableAllExtensions();
|
||||
}
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(ExtensionManager.prototype);
|
||||
|
||||
class ExtensionUpdateSource extends MessageTray.Source {
|
||||
constructor() {
|
||||
const appSys = Shell.AppSystem.get_default();
|
||||
this._app = appSys.lookup_app('gnome-shell-extension-prefs.desktop');
|
||||
|
||||
super(this._app.get_name());
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
return this._app.app_info.get_icon();
|
||||
}
|
||||
|
||||
_createPolicy() {
|
||||
return new MessageTray.NotificationApplicationPolicy(this._app.id);
|
||||
}
|
||||
|
||||
open() {
|
||||
this._app.activate();
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
}
|
||||
}
|
||||
--
|
||||
2.27.0
|
||||
|
@ -0,0 +1,92 @@
|
||||
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
|
||||
|
@ -1,42 +0,0 @@
|
||||
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
|
||||
|
@ -1,237 +0,0 @@
|
||||
From 592bf9b4ba879a365375a7edcb6c48258386e413 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Tue, 18 Jul 2017 12:58:14 -0400
|
||||
Subject: [PATCH 1/2] gdm: add AuthList control
|
||||
|
||||
Ultimately, we want to add support for GDM's new ChoiceList
|
||||
PAM extension. That extension allows PAM modules to present
|
||||
a list of choices to the user. Before we can support that
|
||||
extension, however, we need to have a list control in the
|
||||
login-screen/unlock screen. This commit adds that control.
|
||||
|
||||
For the most part, it's a copy-and-paste of the gdm userlist,
|
||||
but with less features. It lacks API specific to the users,
|
||||
lacks the built in timed login indicator, etc. It does feature
|
||||
a label heading.
|
||||
---
|
||||
js/gdm/authList.js | 195 ++++++++++++++++++++++++++++++++++
|
||||
js/js-resources.gresource.xml | 1 +
|
||||
2 files changed, 196 insertions(+)
|
||||
create mode 100644 js/gdm/authList.js
|
||||
|
||||
diff --git a/js/gdm/authList.js b/js/gdm/authList.js
|
||||
new file mode 100644
|
||||
index 000000000..fc1c3d6e4
|
||||
--- /dev/null
|
||||
+++ b/js/gdm/authList.js
|
||||
@@ -0,0 +1,195 @@
|
||||
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
+/*
|
||||
+ * Copyright 2017 Red Hat, Inc
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2, or (at your option)
|
||||
+ * any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+const Clutter = imports.gi.Clutter;
|
||||
+const GObject = imports.gi.GObject;
|
||||
+const Gtk = imports.gi.Gtk;
|
||||
+const Lang = imports.lang;
|
||||
+const Meta = imports.gi.Meta;
|
||||
+const Signals = imports.signals;
|
||||
+const St = imports.gi.St;
|
||||
+
|
||||
+const Tweener = imports.ui.tweener;
|
||||
+
|
||||
+const _SCROLL_ANIMATION_TIME = 0.5;
|
||||
+
|
||||
+const AuthListItem = new Lang.Class({
|
||||
+ Name: 'AuthListItem',
|
||||
+
|
||||
+ _init(key, text) {
|
||||
+ this.key = key;
|
||||
+ let label = new St.Label({ style_class: 'auth-list-item-label',
|
||||
+ y_align: Clutter.ActorAlign.CENTER });
|
||||
+ label.text = text;
|
||||
+
|
||||
+ this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
|
||||
+ button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
+ can_focus: true,
|
||||
+ child: label,
|
||||
+ reactive: true,
|
||||
+ x_align: St.Align.START,
|
||||
+ x_fill: true });
|
||||
+
|
||||
+ this.actor.connect('key-focus-in', () => {
|
||||
+ this._setSelected(true);
|
||||
+ });
|
||||
+ this.actor.connect('key-focus-out', () => {
|
||||
+ this._setSelected(false);
|
||||
+ });
|
||||
+ this.actor.connect('notify::hover', () => {
|
||||
+ this._setSelected(this.actor.hover);
|
||||
+ });
|
||||
+
|
||||
+ this.actor.connect('clicked', this._onClicked.bind(this));
|
||||
+ },
|
||||
+
|
||||
+ _onClicked() {
|
||||
+ this.emit('activate');
|
||||
+ },
|
||||
+
|
||||
+ _setSelected(selected) {
|
||||
+ if (selected) {
|
||||
+ this.actor.add_style_pseudo_class('selected');
|
||||
+ this.actor.grab_key_focus();
|
||||
+ } else {
|
||||
+ this.actor.remove_style_pseudo_class('selected');
|
||||
+ }
|
||||
+ }
|
||||
+});
|
||||
+Signals.addSignalMethods(AuthListItem.prototype);
|
||||
+
|
||||
+var AuthList = new Lang.Class({
|
||||
+ Name: 'AuthList',
|
||||
+
|
||||
+ _init() {
|
||||
+ this.actor = new St.BoxLayout({ vertical: true,
|
||||
+ style_class: 'login-dialog-auth-list-layout' });
|
||||
+
|
||||
+ this.label = new St.Label({ style_class: 'prompt-dialog-headline' });
|
||||
+ this.actor.add_actor(this.label);
|
||||
+
|
||||
+ this._scrollView = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
|
||||
+ this._scrollView.set_policy(Gtk.PolicyType.NEVER,
|
||||
+ Gtk.PolicyType.AUTOMATIC);
|
||||
+ this.actor.add_actor(this._scrollView);
|
||||
+
|
||||
+ this._box = new St.BoxLayout({ vertical: true,
|
||||
+ style_class: 'login-dialog-user-list',
|
||||
+ pseudo_class: 'expanded' });
|
||||
+
|
||||
+ this._scrollView.add_actor(this._box);
|
||||
+ this._items = {};
|
||||
+
|
||||
+ this.actor.connect('key-focus-in', this._moveFocusToItems.bind(this));
|
||||
+ },
|
||||
+
|
||||
+ _moveFocusToItems() {
|
||||
+ let hasItems = Object.keys(this._items).length > 0;
|
||||
+
|
||||
+ if (!hasItems)
|
||||
+ return;
|
||||
+
|
||||
+ if (global.stage.get_key_focus() != this.actor)
|
||||
+ return;
|
||||
+
|
||||
+ let focusSet = this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
+ if (!focusSet) {
|
||||
+ Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
|
||||
+ this._moveFocusToItems();
|
||||
+ return false;
|
||||
+ });
|
||||
+ }
|
||||
+ },
|
||||
+
|
||||
+ _onItemActivated(activatedItem) {
|
||||
+ this.emit('activate', activatedItem.key);
|
||||
+ },
|
||||
+
|
||||
+ scrollToItem(item) {
|
||||
+ let box = item.actor.get_allocation_box();
|
||||
+
|
||||
+ let adjustment = this._scrollView.get_vscroll_bar().get_adjustment();
|
||||
+
|
||||
+ let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
|
||||
+ Tweener.removeTweens(adjustment);
|
||||
+ Tweener.addTween (adjustment,
|
||||
+ { value: value,
|
||||
+ time: _SCROLL_ANIMATION_TIME,
|
||||
+ transition: 'easeOutQuad' });
|
||||
+ },
|
||||
+
|
||||
+ jumpToItem(item) {
|
||||
+ let box = item.actor.get_allocation_box();
|
||||
+
|
||||
+ let adjustment = this._scrollView.get_vscroll_bar().get_adjustment();
|
||||
+
|
||||
+ let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
|
||||
+
|
||||
+ adjustment.set_value(value);
|
||||
+ },
|
||||
+
|
||||
+ getItem(key) {
|
||||
+ let item = this._items[key];
|
||||
+
|
||||
+ if (!item)
|
||||
+ return null;
|
||||
+
|
||||
+ return item;
|
||||
+ },
|
||||
+
|
||||
+ addItem(key, text) {
|
||||
+ this.removeItem(key);
|
||||
+
|
||||
+ let item = new AuthListItem(key, text);
|
||||
+ this._box.add(item.actor, { x_fill: true });
|
||||
+
|
||||
+ this._items[key] = item;
|
||||
+
|
||||
+ item.connect('activate',
|
||||
+ this._onItemActivated.bind(this));
|
||||
+
|
||||
+ // Try to keep the focused item front-and-center
|
||||
+ item.actor.connect('key-focus-in',
|
||||
+ () => { this.scrollToItem(item); });
|
||||
+
|
||||
+ this._moveFocusToItems();
|
||||
+
|
||||
+ this.emit('item-added', item);
|
||||
+ },
|
||||
+
|
||||
+ removeItem(key) {
|
||||
+ let item = this._items[key];
|
||||
+
|
||||
+ if (!item)
|
||||
+ return;
|
||||
+
|
||||
+ item.actor.destroy();
|
||||
+ delete this._items[key];
|
||||
+ },
|
||||
+
|
||||
+ numItems() {
|
||||
+ return Object.keys(this._items).length;
|
||||
+ },
|
||||
+
|
||||
+ clear() {
|
||||
+ this.label.text = "";
|
||||
+ this._box.destroy_all_children();
|
||||
+ this._items = {};
|
||||
+ }
|
||||
+});
|
||||
+Signals.addSignalMethods(AuthList.prototype);
|
||||
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
|
||||
index 836d1c674..002b202f8 100644
|
||||
--- a/js/js-resources.gresource.xml
|
||||
+++ b/js/js-resources.gresource.xml
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gnome/shell">
|
||||
+ <file>gdm/authList.js</file>
|
||||
<file>gdm/authPrompt.js</file>
|
||||
<file>gdm/batch.js</file>
|
||||
<file>gdm/fingerprint.js</file>
|
||||
--
|
||||
2.21.0
|
||||
|
@ -0,0 +1,51 @@
|
||||
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
|
||||
|
@ -0,0 +1,33 @@
|
||||
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
|
||||
|
@ -0,0 +1,51 @@
|
||||
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
|
||||
|
@ -1,39 +0,0 @@
|
||||
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,56 +0,0 @@
|
||||
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
|
||||
|
@ -1,49 +0,0 @@
|
||||
From 6d26b6f9f66e14843f175305441a2464dd255fd1 Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Mon, 27 Jul 2020 10:58:49 -0400
|
||||
Subject: [PATCH] loginDialog: Reset auth prompt on vt switch before fade in
|
||||
|
||||
At the moment, if a user switches to the login screen vt,
|
||||
the login screen fades in whatever was on screen prior, and
|
||||
then does a reset.
|
||||
|
||||
It makes more sense to reset first, so we fade in what the
|
||||
user is going to interact with instead of what they interacted
|
||||
with before.
|
||||
|
||||
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2997
|
||||
---
|
||||
js/gdm/loginDialog.js | 10 ++++------
|
||||
1 file changed, 4 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
|
||||
index 214c2f512..eb6846d5c 100644
|
||||
--- a/js/gdm/loginDialog.js
|
||||
+++ b/js/gdm/loginDialog.js
|
||||
@@ -923,6 +923,9 @@ var LoginDialog = GObject.registerClass({
|
||||
if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||
return;
|
||||
|
||||
+ if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||
+ this._authPrompt.reset();
|
||||
+
|
||||
Tweener.addTween(this,
|
||||
{ opacity: 255,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
@@ -935,12 +938,7 @@ var LoginDialog = GObject.registerClass({
|
||||
children[i].opacity = this.opacity;
|
||||
}
|
||||
},
|
||||
- onUpdateScope: this,
|
||||
- onComplete() {
|
||||
- if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||
- this._authPrompt.reset();
|
||||
- },
|
||||
- onCompleteScope: this });
|
||||
+ onUpdateScope: this });
|
||||
}
|
||||
|
||||
_gotGreeterSessionProxy(proxy) {
|
||||
--
|
||||
2.32.0
|
||||
|
@ -0,0 +1,148 @@
|
||||
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
|
||||
|
@ -0,0 +1,31 @@
|
||||
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
|
||||
|
@ -1,49 +0,0 @@
|
||||
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
|
||||
|
@ -1,29 +0,0 @@
|
||||
From bd4a3186dc21f2c8d3e0f851cf262a34ddb6b625 Mon Sep 17 00:00:00 2001
|
||||
From: Lubomir Rintel <lkundrak@v3.sk>
|
||||
Date: Fri, 4 Oct 2019 14:21:25 +0200
|
||||
Subject: [PATCH] networkAgent: add support for SAE secrets
|
||||
|
||||
NetworkManager supports "WPA3 Personal" networks for some time now, they
|
||||
use the SAE authentication. Add support for it alongside other
|
||||
password-based mechanisms.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/751
|
||||
---
|
||||
js/ui/components/networkAgent.js | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/js/ui/components/networkAgent.js b/js/ui/components/networkAgent.js
|
||||
index 32d40fb2b..3ff957bf6 100644
|
||||
--- a/js/ui/components/networkAgent.js
|
||||
+++ b/js/ui/components/networkAgent.js
|
||||
@@ -216,6 +216,7 @@ var NetworkSecretDialog = class extends ModalDialog.ModalDialog {
|
||||
// First the easy ones
|
||||
case 'wpa-none':
|
||||
case 'wpa-psk':
|
||||
+ case 'sae':
|
||||
secrets.push({ label: _("Password: "), key: 'psk',
|
||||
value: wirelessSecuritySetting.psk || '',
|
||||
validate: this._validateWpaPsk, password: true });
|
||||
--
|
||||
2.32.0
|
||||
|
@ -0,0 +1,281 @@
|
||||
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
|
||||
|
@ -1,38 +0,0 @@
|
||||
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
|
||||
|
@ -1,80 +0,0 @@
|
||||
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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,36 +0,0 @@
|
||||
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,253 +0,0 @@
|
||||
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
|
||||
|
@ -1,78 +0,0 @@
|
||||
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
|
||||
|
@ -1,28 +0,0 @@
|
||||
From 3182ad73c8f88628cb51a96feba0fc32ce7f01c9 Mon Sep 17 00:00:00 2001
|
||||
From: Illya Klymov <xanf@xanf.me>
|
||||
Date: Mon, 8 Jul 2019 03:29:36 +0000
|
||||
Subject: [PATCH] shell-recorder: Restore cursor recording
|
||||
|
||||
Due to changes introduced in 5357e0a1 cursor recording interaction with
|
||||
magnifier was reversed. This fix restores original correct behavior
|
||||
Related issue: https://gitlab.gnome.org/GNOME/gnome-shell/issues/1208
|
||||
---
|
||||
src/shell-recorder.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/shell-recorder.c b/src/shell-recorder.c
|
||||
index 0203ecf1c..cf1cc336f 100644
|
||||
--- a/src/shell-recorder.c
|
||||
+++ b/src/shell-recorder.c
|
||||
@@ -465,7 +465,7 @@ recorder_record_frame (ShellRecorder *recorder,
|
||||
|
||||
g_object_get (settings, "magnifier-active", &magnifier_active, NULL);
|
||||
|
||||
- if (magnifier_active)
|
||||
+ if (!magnifier_active)
|
||||
recorder_draw_cursor (recorder, buffer);
|
||||
}
|
||||
|
||||
--
|
||||
2.35.1
|
||||
|
@ -0,0 +1,56 @@
|
||||
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
|
||||
|
@ -1,66 +0,0 @@
|
||||
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
|
||||
|
@ -1,91 +0,0 @@
|
||||
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
|
||||
|
@ -1,36 +0,0 @@
|
||||
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
|
||||
|
@ -1,59 +0,0 @@
|
||||
From 96404287bc4269dea7b037e7b178e54ebf616d47 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel van Vugt <daniel.van.vugt@canonical.com>
|
||||
Date: Tue, 24 Nov 2020 17:34:08 +0800
|
||||
Subject: [PATCH] st-bin: Disallow st_bin_set_child with already-parented
|
||||
children
|
||||
|
||||
Not checking for this would result in `clutter_actor_add_child`
|
||||
failing, but StBin keeping a copy in `priv->child`. So later on,
|
||||
`st_bin_remove` would never be called on it and this assertion
|
||||
would fail and crash the whole shell:
|
||||
|
||||
```
|
||||
static void
|
||||
st_bin_destroy (ClutterActor *actor)
|
||||
{
|
||||
StBinPrivate *priv = st_bin_get_instance_private (ST_BIN (actor));
|
||||
|
||||
if (priv->child)
|
||||
clutter_actor_destroy (priv->child);
|
||||
g_assert (priv->child == NULL);
|
||||
|
||||
```
|
||||
|
||||
By disallowing spurious `st_bin_set_child` calls we now prevent StBin
|
||||
from entering such a corrupt state and the above assertion won't fail
|
||||
anymore.
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1507>
|
||||
---
|
||||
src/st/st-bin.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/src/st/st-bin.c b/src/st/st-bin.c
|
||||
index f013909e8..7959a4e95 100644
|
||||
--- a/src/st/st-bin.c
|
||||
+++ b/src/st/st-bin.c
|
||||
@@ -434,6 +434,19 @@ st_bin_set_child (StBin *bin,
|
||||
if (priv->child == child)
|
||||
return;
|
||||
|
||||
+ if (child)
|
||||
+ {
|
||||
+ ClutterActor *parent = clutter_actor_get_parent (child);
|
||||
+
|
||||
+ if (parent)
|
||||
+ {
|
||||
+ g_warning ("%s: The provided 'child' actor %p already has a "
|
||||
+ "(different) parent %p and can't be made a child of %p.",
|
||||
+ G_STRFUNC, child, parent, bin);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (priv->child)
|
||||
clutter_actor_remove_child (CLUTTER_ACTOR (bin), priv->child);
|
||||
|
||||
--
|
||||
2.38.1
|
||||
|
@ -0,0 +1,36 @@
|
||||
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
|
||||
|
@ -1,94 +0,0 @@
|
||||
From 1bf28eea64056846547ec33d783c7f2e0dad78a4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 22 May 2020 22:53:39 +0200
|
||||
Subject: [PATCH] st/texture-cache: Cancel pending requests on icon-theme
|
||||
changes
|
||||
|
||||
As outlined in commit 36b8dcbe07, we can end up with wrong icons
|
||||
if the icon theme changes right after a GTK theme change to/from
|
||||
HighContrast triggered a theme reload.
|
||||
|
||||
That's because when we reload icons for the new icon theme, there
|
||||
are already pending requests due to the icon-style change; those
|
||||
requests are simply re-used for the new icons, with the existing
|
||||
icon infos from the old theme.
|
||||
|
||||
The above commit applied a simple work-around by changing the
|
||||
icon theme before the GTK theme, but that only works for the
|
||||
HighContrast switch in our own UI.
|
||||
|
||||
It turns out that Settings also uses the "wrong" order, so the
|
||||
issue still reproduces with the Universal Access panel.
|
||||
|
||||
So instead of relying on everything changing the settings in the
|
||||
order we expect, cancel all ongoing requests on icon-theme changes.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1277
|
||||
---
|
||||
src/st/st-texture-cache.c | 17 +++++++++++++++--
|
||||
1 file changed, 15 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c
|
||||
index 35e9d036f..6dc351282 100644
|
||||
--- a/src/st/st-texture-cache.c
|
||||
+++ b/src/st/st-texture-cache.c
|
||||
@@ -48,6 +48,8 @@ struct _StTextureCachePrivate
|
||||
|
||||
/* File monitors to evict cache data on changes */
|
||||
GHashTable *file_monitors; /* char * -> GFileMonitor * */
|
||||
+
|
||||
+ GCancellable *cancellable;
|
||||
};
|
||||
|
||||
static void st_texture_cache_dispose (GObject *object);
|
||||
@@ -152,6 +154,9 @@ on_icon_theme_changed (StSettings *settings,
|
||||
{
|
||||
g_autofree gchar *theme;
|
||||
|
||||
+ g_cancellable_cancel (cache->priv->cancellable);
|
||||
+ g_cancellable_reset (cache->priv->cancellable);
|
||||
+
|
||||
st_texture_cache_evict_icons (cache);
|
||||
|
||||
g_object_get (settings, "gtk-icon-theme", &theme, NULL);
|
||||
@@ -186,6 +191,8 @@ st_texture_cache_init (StTextureCache *self)
|
||||
self->priv->file_monitors = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
|
||||
g_object_unref, g_object_unref);
|
||||
|
||||
+ self->priv->cancellable = g_cancellable_new ();
|
||||
+
|
||||
on_icon_theme_changed (settings, NULL, self);
|
||||
}
|
||||
|
||||
@@ -194,8 +201,11 @@ st_texture_cache_dispose (GObject *object)
|
||||
{
|
||||
StTextureCache *self = (StTextureCache*)object;
|
||||
|
||||
+ g_cancellable_cancel (self->priv->cancellable);
|
||||
+
|
||||
g_clear_object (&self->priv->settings);
|
||||
g_clear_object (&self->priv->icon_theme);
|
||||
+ g_clear_object (&self->priv->cancellable);
|
||||
|
||||
g_clear_pointer (&self->priv->keyed_cache, g_hash_table_destroy);
|
||||
g_clear_pointer (&self->priv->keyed_surface_cache, g_hash_table_destroy);
|
||||
@@ -675,11 +685,14 @@ load_texture_async (StTextureCache *cache,
|
||||
gtk_icon_info_load_symbolic_async (data->icon_info,
|
||||
&foreground_color, &success_color,
|
||||
&warning_color, &error_color,
|
||||
- NULL, on_symbolic_icon_loaded, data);
|
||||
+ cache->priv->cancellable,
|
||||
+ on_symbolic_icon_loaded, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
- gtk_icon_info_load_icon_async (data->icon_info, NULL, on_icon_loaded, data);
|
||||
+ gtk_icon_info_load_icon_async (data->icon_info,
|
||||
+ cache->priv->cancellable,
|
||||
+ on_icon_loaded, data);
|
||||
}
|
||||
}
|
||||
else
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,58 @@
|
||||
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,76 +0,0 @@
|
||||
From c68fd3c94c6debdbf11020940c5a6aaee8bc230d Mon Sep 17 00:00:00 2001
|
||||
From: Feichtmeier <frederik.feichtmeier@gmail.com>
|
||||
Date: Fri, 15 Mar 2019 14:41:55 +0100
|
||||
Subject: [PATCH] theme: Update window preview style
|
||||
|
||||
- simplify the close button to use blue, lighter blue and darker blue
|
||||
solid disks for normal, hover and active states
|
||||
|
||||
- use a milky, transparent white border for the hover effect of the border
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/461
|
||||
---
|
||||
data/theme/gnome-shell-sass/_common.scss | 29 ++++++++++++------------
|
||||
1 file changed, 14 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
|
||||
index 9e0751c8c..8bf368f6e 100644
|
||||
--- a/data/theme/gnome-shell-sass/_common.scss
|
||||
+++ b/data/theme/gnome-shell-sass/_common.scss
|
||||
@@ -1164,25 +1164,23 @@ StScrollBar {
|
||||
//close buttons
|
||||
|
||||
.window-close {
|
||||
- background-color: white;
|
||||
+ background-color: $selected_bg_color;
|
||||
+ color: white;
|
||||
border-radius: 24px;
|
||||
- border: 4px solid $selected_bg_color;
|
||||
- box-shadow: inset 0 -4px 0 0 transparentize($selected_bg_color, 0.5);
|
||||
- color: $selected_bg_color;
|
||||
+ border: 2px solid $selected_bg_color;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
- -shell-close-overlap: 14px;
|
||||
+ -shell-close-overlap: 11px;
|
||||
+ box-shadow: -1px 1px 5px 0px transparentize(black, 0.5);
|
||||
|
||||
&:hover {
|
||||
- background-color: $selected_bg_color;
|
||||
- border-color: white;
|
||||
- color: white;
|
||||
+ background-color: lighten($selected_bg_color, 5%);
|
||||
+ border-color: lighten($selected_bg_color, 5%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
- background-color: mix(white, $selected_bg_color, 75%);
|
||||
- border-color: $selected_bg_color;
|
||||
- color: $selected_bg_color;
|
||||
+ background-color: darken($selected_bg_color, 5%);
|
||||
+ border-color: darken($selected_bg_color, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,13 +1245,14 @@ StScrollBar {
|
||||
}
|
||||
|
||||
.window-clone-border {
|
||||
- border: 4px solid $selected_bg_color;
|
||||
- border-radius: 4px;
|
||||
+ $_bg: transparentize(white, 0.65);
|
||||
+ border: 5px solid $_bg;
|
||||
+ border-radius: 6px;
|
||||
// For window decorations with round corners we can't match
|
||||
// the exact shape when the window is scaled. So apply a shadow
|
||||
// to fix that case
|
||||
- box-shadow: inset 0px 0px 0px 1px $selected_bg_color;
|
||||
- }
|
||||
+ box-shadow: inset 0 0 0 1px $_bg;
|
||||
+}
|
||||
.window-caption {
|
||||
spacing: 25px;
|
||||
color: $selected_fg_color;
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,38 @@
|
||||
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
|
||||
|
@ -0,0 +1,64 @@
|
||||
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
|
||||
|
@ -0,0 +1,44 @@
|
||||
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
|
||||
|
@ -0,0 +1,46 @@
|
||||
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
|
||||
|
@ -1,31 +0,0 @@
|
||||
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
|
||||
|
@ -1,37 +0,0 @@
|
||||
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
|
||||
|
@ -1,31 +0,0 @@
|
||||
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
|
||||
|
@ -1,33 +0,0 @@
|
||||
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
|
||||
|
@ -1,237 +0,0 @@
|
||||
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
|
||||
|
@ -1,267 +0,0 @@
|
||||
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
|
||||
|
@ -1,92 +0,0 @@
|
||||
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
|
||||
|
@ -1,393 +0,0 @@
|
||||
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
|
||||
|
@ -1,152 +0,0 @@
|
||||
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
|
||||
|
@ -1,119 +0,0 @@
|
||||
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,115 +0,0 @@
|
||||
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
|
||||
|
@ -1,124 +0,0 @@
|
||||
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
|
||||
|
@ -1,116 +0,0 @@
|
||||
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
|
||||
|
@ -1,116 +0,0 @@
|
||||
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
|
||||
|
@ -1,674 +0,0 @@
|
||||
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
|
||||
|
@ -1,36 +0,0 @@
|
||||
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
|
||||
|
@ -1,66 +0,0 @@
|
||||
From a0df79f8de4c13c36ed3b22cfdbb78e324424ef1 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Sat, 14 Mar 2020 14:45:42 +0100
|
||||
Subject: [PATCH 6/6] js: Always use AppSystem to lookup apps
|
||||
|
||||
There is no good reason for bypassing the application cache in
|
||||
AppSystem and loading .desktop files again.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1093
|
||||
---
|
||||
js/ui/appDisplay.js | 4 ++--
|
||||
js/ui/calendar.js | 16 ++++++++++------
|
||||
2 files changed, 12 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
|
||||
index a2d691085..cb2be7d3c 100644
|
||||
--- a/js/ui/appDisplay.js
|
||||
+++ b/js/ui/appDisplay.js
|
||||
@@ -1001,8 +1001,8 @@ var AppSearchProvider = class AppSearchProvider {
|
||||
let results = [];
|
||||
groups.forEach(group => {
|
||||
group = group.filter(appID => {
|
||||
- let app = Gio.DesktopAppInfo.new(appID);
|
||||
- return app && app.should_show();
|
||||
+ const app = this._appSys.lookup_app(appID);
|
||||
+ return app && app.app_info.should_show();
|
||||
});
|
||||
results = results.concat(group.sort(
|
||||
(a, b) => usage.compare(a, b)
|
||||
diff --git a/js/ui/calendar.js b/js/ui/calendar.js
|
||||
index cd3e879c4..3ae2e44f8 100644
|
||||
--- a/js/ui/calendar.js
|
||||
+++ b/js/ui/calendar.js
|
||||
@@ -791,8 +791,9 @@ var EventsSection = class EventsSection extends MessageList.MessageListSection {
|
||||
this._title.connect('clicked', this._onTitleClicked.bind(this));
|
||||
this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this));
|
||||
|
||||
- Shell.AppSystem.get_default().connect('installed-changed',
|
||||
- this._appInstalledChanged.bind(this));
|
||||
+ this._appSys = Shell.AppSystem.get_default();
|
||||
+ this._appSys.connect('installed-changed',
|
||||
+ this._appInstalledChanged.bind(this));
|
||||
this._appInstalledChanged();
|
||||
}
|
||||
|
||||
@@ -883,10 +884,13 @@ var EventsSection = class EventsSection extends MessageList.MessageListSection {
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
|
||||
- let app = this._getCalendarApp();
|
||||
- if (app.get_id() == 'evolution.desktop')
|
||||
- app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
|
||||
- app.launch([], global.create_app_launch_context(0, -1));
|
||||
+ let appInfo = this._getCalendarApp();
|
||||
+ if (app.get_id() == 'evolution.desktop') {
|
||||
+ let app = this._appSys.lookup_app('evolution-calendar.desktop');
|
||||
+ if (app)
|
||||
+ appInfo = app.app_info;
|
||||
+ }
|
||||
+ appInfo.launch([], global.create_app_launch_context(0, -1));
|
||||
}
|
||||
|
||||
setDate(date) {
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,333 @@
|
||||
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
|
||||
|
@ -1,159 +0,0 @@
|
||||
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
|
||||
|
@ -1,145 +0,0 @@
|
||||
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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,421 +0,0 @@
|
||||
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
|
||||
|
@ -1,101 +0,0 @@
|
||||
From 49d066234f9f528122bb40c5144b40d8b19a0071 Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Mon, 22 Aug 2022 12:52:19 +0200
|
||||
Subject: [PATCH] Background: Avoid double dispose and actors recreations
|
||||
|
||||
Subject: [PATCH 1/2] background: Use Garbage Collector to dispose background:
|
||||
|
||||
The same Meta.Background could be used by multiple instances of background
|
||||
actors, and so should not be disposed when the actor using it is destroyed.
|
||||
|
||||
Instead of calling `run_dispose` directly on it, just nullify the reference
|
||||
on destroy method, leaving the job of doing the proper disposition to the
|
||||
gabage collector that keeps the proper reference count on the Meta.Background.
|
||||
|
||||
Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/501
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/558
|
||||
|
||||
Subject: [PATCH 2/2] background: Group 'changed' signal emission
|
||||
|
||||
Background is monitoring the whole `org.gnome.desktop.background` gsettings keys
|
||||
for changes connecting to the non-specialized 'changed' signal and re-emitting
|
||||
this as-is.
|
||||
This means that when the background is changed via control-center, we get
|
||||
multiple 'changed' signal events from GSettings, and for each one of this we
|
||||
recreate a Background and a BackgroundActor.
|
||||
|
||||
Avoid this by using an idle to delay the emission of the 'changed' signal
|
||||
grouping the events.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/558
|
||||
---
|
||||
js/ui/background.js | 26 +++++++++++++++++++++-----
|
||||
1 file changed, 21 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/js/ui/background.js b/js/ui/background.js
|
||||
index 06e0388..2a404ae 100644
|
||||
--- a/js/ui/background.js
|
||||
+++ b/js/ui/background.js
|
||||
@@ -257,14 +257,15 @@ var Background = class Background {
|
||||
this._refreshAnimation();
|
||||
});
|
||||
|
||||
- this._settingsChangedSignalId = this._settings.connect('changed', () => {
|
||||
- this.emit('changed');
|
||||
- });
|
||||
+ this._settingsChangedSignalId =
|
||||
+ this._settings.connect('changed', this._emitChangedSignal.bind(this));
|
||||
|
||||
this._load();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
+ this.background = null;
|
||||
+
|
||||
this._cancellable.cancel();
|
||||
this._removeAnimationTimeout();
|
||||
|
||||
@@ -288,6 +289,22 @@ var Background = class Background {
|
||||
if (this._settingsChangedSignalId != 0)
|
||||
this._settings.disconnect(this._settingsChangedSignalId);
|
||||
this._settingsChangedSignalId = 0;
|
||||
+
|
||||
+ if (this._changedIdleId) {
|
||||
+ GLib.source_remove(this._changedIdleId);
|
||||
+ this._changedIdleId = 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ _emitChangedSignal() {
|
||||
+ if (this._changedIdleId)
|
||||
+ return;
|
||||
+
|
||||
+ this._changedIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||
+ this._changedIdleId = 0;
|
||||
+ this.emit('changed');
|
||||
+ return GLib.SOURCE_REMOVE;
|
||||
+ });
|
||||
}
|
||||
|
||||
updateResolution() {
|
||||
@@ -343,7 +360,7 @@ var Background = class Background {
|
||||
if (changedFile.equal(file)) {
|
||||
let imageCache = Meta.BackgroundImageCache.get_default();
|
||||
imageCache.purge(changedFile);
|
||||
- this.emit('changed');
|
||||
+ this._emitChangedSignal();
|
||||
}
|
||||
});
|
||||
this._fileWatches[key] = signalId;
|
||||
@@ -699,7 +716,6 @@ var BackgroundManager = class BackgroundManager {
|
||||
time: FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete() {
|
||||
- oldBackgroundActor.background.run_dispose();
|
||||
oldBackgroundActor.destroy();
|
||||
}
|
||||
});
|
||||
--
|
||||
2.35.3
|
||||
|
@ -0,0 +1,107 @@
|
||||
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
|
||||
|
@ -1,224 +0,0 @@
|
||||
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
|
||||
|
@ -1,161 +0,0 @@
|
||||
From 214c4f390faa40199c03a80594313760ffe9c5a6 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 20 Sep 2019 13:17:40 +0200
|
||||
Subject: [PATCH 1/2] unlockDialog: Use inheritance instead of composition
|
||||
|
||||
The screen shield creates the unlock dialog based on the session mode.
|
||||
|
||||
However since commit 0c0d76f7d6990 turned LoginDialog into an actor
|
||||
subclass (while UnlockDialog kept using the delegate pattern), it is
|
||||
no longer possible to handle both objects the same way without warnings.
|
||||
|
||||
Allow this again by turning UnlockDialog into an actor subclass as well.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/736
|
||||
---
|
||||
js/ui/unlockDialog.js | 46 ++++++++++++++++++++++++-------------------
|
||||
1 file changed, 26 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js
|
||||
index 4b0470f4b..55abb652d 100644
|
||||
--- a/js/ui/unlockDialog.js
|
||||
+++ b/js/ui/unlockDialog.js
|
||||
@@ -1,8 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const { AccountsService, Atk, Clutter,
|
||||
- Gdm, Gio, GLib, Meta, Shell, St } = imports.gi;
|
||||
-const Signals = imports.signals;
|
||||
+ Gdm, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
|
||||
const Layout = imports.ui.layout;
|
||||
const Main = imports.ui.main;
|
||||
@@ -12,15 +11,19 @@ const AuthPrompt = imports.gdm.authPrompt;
|
||||
// The timeout before going back automatically to the lock screen (in seconds)
|
||||
const IDLE_TIMEOUT = 2 * 60;
|
||||
|
||||
-var UnlockDialog = class {
|
||||
- constructor(parentActor) {
|
||||
- this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW,
|
||||
- style_class: 'login-dialog',
|
||||
- layout_manager: new Clutter.BoxLayout(),
|
||||
- visible: false });
|
||||
+var UnlockDialog = GObject.registerClass({
|
||||
+ Signals: { 'failed': {} },
|
||||
+}, class UnlockDialog extends St.Widget {
|
||||
+ _init(parentActor) {
|
||||
+ super._init({
|
||||
+ accessible_role: Atk.Role.WINDOW,
|
||||
+ style_class: 'login-dialog',
|
||||
+ layout_manager: new Clutter.BoxLayout(),
|
||||
+ visible: false,
|
||||
+ });
|
||||
|
||||
- this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
||||
- parentActor.add_child(this.actor);
|
||||
+ this.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
||||
+ parentActor.add_child(this);
|
||||
|
||||
this._userManager = AccountsService.UserManager.get_default();
|
||||
this._userName = GLib.get_user_name();
|
||||
@@ -31,7 +34,7 @@ var UnlockDialog = class {
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
x_expand: true,
|
||||
y_expand: true });
|
||||
- this.actor.add_child(this._promptBox);
|
||||
+ this.add_child(this._promptBox);
|
||||
|
||||
this._gdmClient = new Gdm.Client();
|
||||
|
||||
@@ -70,10 +73,12 @@ var UnlockDialog = class {
|
||||
this._authPrompt.reset();
|
||||
this._updateSensitivity(true);
|
||||
|
||||
- Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic');
|
||||
+ Main.ctrlAltTabManager.addGroup(this, _("Unlock Window"), 'dialog-password-symbolic');
|
||||
|
||||
this._idleMonitor = Meta.IdleMonitor.get_core();
|
||||
this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, this._escape.bind(this));
|
||||
+
|
||||
+ this.connect('destroy', this._onDestroy.bind(this));
|
||||
}
|
||||
|
||||
_updateSensitivity(sensitive) {
|
||||
@@ -112,9 +117,8 @@ var UnlockDialog = class {
|
||||
this._authPrompt.cancel();
|
||||
}
|
||||
|
||||
- destroy() {
|
||||
+ _onDestroy() {
|
||||
this.popModal();
|
||||
- this.actor.destroy();
|
||||
|
||||
if (this._idleWatchId) {
|
||||
this._idleMonitor.remove_watch(this._idleWatchId);
|
||||
@@ -137,13 +141,16 @@ var UnlockDialog = class {
|
||||
}
|
||||
|
||||
open(timestamp) {
|
||||
- this.actor.show();
|
||||
+ this.show();
|
||||
|
||||
if (this._isModal)
|
||||
return true;
|
||||
|
||||
- if (!Main.pushModal(this.actor, { timestamp: timestamp,
|
||||
- actionMode: Shell.ActionMode.UNLOCK_SCREEN }))
|
||||
+ let modalParams = {
|
||||
+ timestamp,
|
||||
+ actionMode: Shell.ActionMode.UNLOCK_SCREEN,
|
||||
+ };
|
||||
+ if (!Main.pushModal(this, modalParams))
|
||||
return false;
|
||||
|
||||
this._isModal = true;
|
||||
@@ -153,9 +160,8 @@ var UnlockDialog = class {
|
||||
|
||||
popModal(timestamp) {
|
||||
if (this._isModal) {
|
||||
- Main.popModal(this.actor, timestamp);
|
||||
+ Main.popModal(this, timestamp);
|
||||
this._isModal = false;
|
||||
}
|
||||
}
|
||||
-};
|
||||
-Signals.addSignalMethods(UnlockDialog.prototype);
|
||||
+});
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
||||
From cddeb2f4e38928e0d5e0f3a852961f639536aff3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 20 Sep 2019 13:14:40 +0200
|
||||
Subject: [PATCH 2/2] screenShield: Stop using deprecated actor property
|
||||
|
||||
Both LoginDialog and UnlockDialog are now actor subclasses, so stop
|
||||
using the deprecated actor delegate that will trigger a warning.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/736
|
||||
---
|
||||
js/ui/screenShield.js | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
|
||||
index 2d0a429be..f97a9288a 100644
|
||||
--- a/js/ui/screenShield.js
|
||||
+++ b/js/ui/screenShield.js
|
||||
@@ -917,8 +917,8 @@ var ScreenShield = class {
|
||||
this._lockScreenGroup.hide();
|
||||
|
||||
if (this._dialog) {
|
||||
- this._dialog.actor.grab_key_focus();
|
||||
- this._dialog.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
|
||||
+ this._dialog.grab_key_focus();
|
||||
+ this._dialog.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,334 @@
|
||||
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 "'", 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 < character' },
|
||||
+ { input: 'Don\'t',
|
||||
+ terms: ['t'],
|
||||
+ output: 'Don'<b>t</b>' },
|
||||
+ { input: 'Don\'t',
|
||||
+ terms: ['n\'t'],
|
||||
+ output: 'Do<b>n't</b>' },
|
||||
+ { input: 'Don\'t',
|
||||
+ terms: ['o', 't'],
|
||||
+ output: 'D<b>o</b>n'<b>t</b>' },
|
||||
+ { input: 'salt&pepper',
|
||||
+ terms: ['salt'],
|
||||
+ output: '<b>salt</b>&pepper' },
|
||||
+ { input: 'salt&pepper',
|
||||
+ terms: ['salt', 'alt'],
|
||||
+ output: '<b>salt</b>&pepper' },
|
||||
+ { input: 'salt&pepper',
|
||||
+ terms: ['pepper'],
|
||||
+ output: 'salt&<b>pepper</b>' },
|
||||
+ { input: 'salt&pepper',
|
||||
+ terms: ['salt', 'pepper'],
|
||||
+ output: '<b>salt</b>&<b>pepper</b>' },
|
||||
+ { input: 'salt&pepper',
|
||||
+ terms: ['t', 'p'],
|
||||
+ output: 'sal<b>t</b>&<b>p</b>e<b>p</b><b>p</b>er' },
|
||||
+ { input: 'salt&pepper',
|
||||
+ terms: ['t', '&', 'p'],
|
||||
+ output: 'sal<b>t</b><b>&</b><b>p</b>e<b>p</b><b>p</b>er' },
|
||||
+ { input: 'salt&pepper',
|
||||
+ terms: ['e'],
|
||||
+ output: 'salt&p<b>e</b>pp<b>e</b>r' },
|
||||
+ { input: 'salt&pepper',
|
||||
+ terms: ['&a', '&am', '&', '&'],
|
||||
+ output: 'salt&pepper' },
|
||||
+ { input: '&&&&&',
|
||||
+ terms: ['a'],
|
||||
+ output: '&&&&&' },
|
||||
+ { input: '&;&;&;&;&;',
|
||||
+ terms: ['a'],
|
||||
+ output: '&;&;&;&;&;' },
|
||||
+ { input: '&;&;&;&;&;',
|
||||
+ terms: [';'],
|
||||
+ output: '&<b>;</b>&<b>;</b>&<b>;</b>&<b>;</b>&<b>;</b>' },
|
||||
+ { input: '&',
|
||||
+ terms: ['a'],
|
||||
+ output: '&<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
|
||||
|
@ -1,131 +0,0 @@
|
||||
From e2a1b737156804e2647e5de938c3d170c11b6ba4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Fri, 31 Jul 2020 20:40:36 +0200
|
||||
Subject: [PATCH 1/2] status/network: Use D-Bus to launch Settings panels
|
||||
|
||||
For more obscure network configurations, we need to launch the
|
||||
corresponding Settings panel with additional parameters, so we
|
||||
cannot simply launch the .desktop file.
|
||||
|
||||
However we can do better than spawning a command line: Control center
|
||||
exposes an application action we can use instead, so the process is
|
||||
launched with the appropriate activation environment and startup
|
||||
notification support.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1385
|
||||
---
|
||||
js/ui/status/network.js | 33 +++++++++++++++++++++++++++++----
|
||||
1 file changed, 29 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
|
||||
index f8991d02f..0e7e82ce0 100644
|
||||
--- a/js/ui/status/network.js
|
||||
+++ b/js/ui/status/network.js
|
||||
@@ -15,6 +15,8 @@ const Util = imports.misc.util;
|
||||
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
+Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
|
||||
+
|
||||
const NMConnectionCategory = {
|
||||
INVALID: 'invalid',
|
||||
WIRED: 'wired',
|
||||
@@ -75,6 +77,30 @@ function ensureActiveConnectionProps(active, client) {
|
||||
}
|
||||
}
|
||||
|
||||
+function launchSettingsPanel(panel, ...args) {
|
||||
+ const param = new GLib.Variant('(sav)',
|
||||
+ [panel, args.map(s => new GLib.Variant('s', s))]);
|
||||
+ const platformData = {
|
||||
+ 'desktop-startup-id': new GLib.Variant('s',
|
||||
+ '_TIME%s'.format(global.get_current_time())),
|
||||
+ };
|
||||
+ try {
|
||||
+ Gio.DBus.session.call(
|
||||
+ 'org.gnome.ControlCenter',
|
||||
+ '/org/gnome/ControlCenter',
|
||||
+ 'org.freedesktop.Application',
|
||||
+ 'ActivateAction',
|
||||
+ new GLib.Variant('(sava{sv})',
|
||||
+ ['launch-panel', [param], platformData]),
|
||||
+ null,
|
||||
+ Gio.DBusCallFlags.NONE,
|
||||
+ -1,
|
||||
+ null);
|
||||
+ } catch (e) {
|
||||
+ log('Failed to launch Settings panel: %s'.format(e.message));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
var NMConnectionItem = class {
|
||||
constructor(section, connection) {
|
||||
this._section = section;
|
||||
@@ -534,8 +560,7 @@ var NMDeviceModem = class extends NMConnectionDevice {
|
||||
}
|
||||
|
||||
_autoConnect() {
|
||||
- Util.spawn(['gnome-control-center', 'network',
|
||||
- 'connect-3g', this._device.get_path()]);
|
||||
+ launchSettingsPanel('network', 'connect-3g', this._device.get_path());
|
||||
}
|
||||
|
||||
_sessionUpdated() {
|
||||
@@ -920,8 +945,8 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog {
|
||||
|| (accessPoints[0]._secType == NMAccessPointSecurity.WPA_ENT)) {
|
||||
// 802.1x-enabled APs require further configuration, so they're
|
||||
// handled in gnome-control-center
|
||||
- Util.spawn(['gnome-control-center', 'wifi', 'connect-8021x-wifi',
|
||||
- this._device.get_path(), accessPoints[0].get_path()]);
|
||||
+ launchSettingsPanel('wifi', 'connect-8021x-wifi',
|
||||
+ this._device.get_path(), accessPoints[0].get_path());
|
||||
} else {
|
||||
let connection = new NM.SimpleConnection();
|
||||
this._client.add_and_activate_connection_async(connection, this._device, accessPoints[0].get_path(), null, null)
|
||||
--
|
||||
2.38.1
|
||||
|
||||
|
||||
From 9ca1989fcc73157685742470c25f538d01d8df44 Mon Sep 17 00:00:00 2001
|
||||
From: Xiaoguang Wang <xwang@suse.com>
|
||||
Date: Mon, 21 Feb 2022 09:11:23 +0800
|
||||
Subject: [PATCH 2/2] network: Get dbus path from NMDevice
|
||||
|
||||
In the NetworkManager new version the NMDevice.get_path returns pci
|
||||
path, we need to use NM prototype to get device dbus path.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4565
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2194>
|
||||
---
|
||||
js/ui/status/network.js | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
|
||||
index 0e7e82ce0..9d6a83b73 100644
|
||||
--- a/js/ui/status/network.js
|
||||
+++ b/js/ui/status/network.js
|
||||
@@ -946,7 +946,7 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog {
|
||||
// 802.1x-enabled APs require further configuration, so they're
|
||||
// handled in gnome-control-center
|
||||
launchSettingsPanel('wifi', 'connect-8021x-wifi',
|
||||
- this._device.get_path(), accessPoints[0].get_path());
|
||||
+ this._getDeviceDBusPath(), accessPoints[0].get_path());
|
||||
} else {
|
||||
let connection = new NM.SimpleConnection();
|
||||
this._client.add_and_activate_connection_async(connection, this._device, accessPoints[0].get_path(), null, null)
|
||||
@@ -956,6 +956,11 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog {
|
||||
this.close();
|
||||
}
|
||||
|
||||
+ _getDeviceDBusPath() {
|
||||
+ // nm_object_get_path() is shadowed by nm_device_get_path()
|
||||
+ return NM.Object.prototype.get_path.call(this._device);
|
||||
+ }
|
||||
+
|
||||
_notifySsidCb(accessPoint) {
|
||||
if (accessPoint.get_ssid() != null) {
|
||||
accessPoint.disconnect(accessPoint._notifySsidId);
|
||||
--
|
||||
2.38.1
|
||||
|
@ -0,0 +1,92 @@
|
||||
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
|
||||
|
@ -0,0 +1,67 @@
|
||||
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,25 +1,25 @@
|
||||
From d15a92aeaa075230f711921f4bcd929c49bfc97d Mon Sep 17 00:00:00 2001
|
||||
From 1e699b55f3dc84b2ddbc5acd03424240eddbe06c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 9 Mar 2017 14:44:32 +0100
|
||||
Subject: [PATCH] appFavorites: Add terminal
|
||||
Subject: [PATCH 3/3] appFavorites: Add terminal
|
||||
|
||||
---
|
||||
data/org.gnome.shell.gschema.xml.in | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
|
||||
index 40526187e..9d7e011fc 100644
|
||||
index 35ddaf4a9..d5ea1e35f 100644
|
||||
--- a/data/org.gnome.shell.gschema.xml.in
|
||||
+++ b/data/org.gnome.shell.gschema.xml.in
|
||||
@@ -39,7 +39,7 @@
|
||||
@@ -50,7 +50,7 @@
|
||||
</description>
|
||||
</key>
|
||||
<key name="favorite-apps" type="as">
|
||||
- <default>[ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop' ]</default>
|
||||
+ <default>[ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop', 'gnome-terminal.desktop' ]</default>
|
||||
- <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>
|
||||
<summary>List of desktop file IDs for favorite applications</summary>
|
||||
<description>
|
||||
The applications corresponding to these identifiers
|
||||
--
|
||||
2.21.0
|
||||
2.31.1
|
||||
|
||||
|
@ -1,399 +0,0 @@
|
||||
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
|
||||
|
@ -1,643 +0,0 @@
|
||||
From 781dfcf6ce7168c6b116d58df5f1c67291a7b513 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Thu, 16 May 2019 00:57:27 +0200
|
||||
Subject: [PATCH 01/11] introspect: Include `sandboxed-app-id` as well
|
||||
|
||||
App IDs in gnome-shell don't match AppStream, Flatpak or Snap IDs. For the
|
||||
desktop portal, the latter two are more relevant, so include it in the
|
||||
returned information.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1289
|
||||
---
|
||||
js/misc/introspect.js | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index f7a7f2fe6..1e8300d0a 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -55,6 +55,11 @@ var IntrospectService = class {
|
||||
return APP_WHITELIST.includes(sender);
|
||||
}
|
||||
|
||||
+ _getSandboxedAppId(app) {
|
||||
+ let ids = app.get_windows().map(w => w.get_sandboxed_app_id());
|
||||
+ return ids.find(id => id != null);
|
||||
+ }
|
||||
+
|
||||
_syncRunningApplications() {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let apps = this._appSystem.get_running();
|
||||
@@ -76,6 +81,10 @@ var IntrospectService = class {
|
||||
newActiveApplication = app.get_id();
|
||||
}
|
||||
|
||||
+ let sandboxedAppId = this._getSandboxedAppId(app);
|
||||
+ if (sandboxedAppId)
|
||||
+ appInfo['sandboxed-app-id'] = new GLib.Variant('s', sandboxedAppId);
|
||||
+
|
||||
newRunningApplications[app.get_id()] = appInfo;
|
||||
}
|
||||
|
||||
@@ -137,6 +146,7 @@ var IntrospectService = class {
|
||||
let frameRect = window.get_frame_rect();
|
||||
let title = window.get_title();
|
||||
let wmClass = window.get_wm_class();
|
||||
+ let sandboxedAppId = window.get_sandboxed_app_id();
|
||||
|
||||
windowsList[windowId] = {
|
||||
'app-id': GLib.Variant.new('s', app.get_id()),
|
||||
@@ -153,6 +163,10 @@ var IntrospectService = class {
|
||||
|
||||
if (wmClass != null)
|
||||
windowsList[windowId]['wm-class'] = GLib.Variant.new('s', wmClass);
|
||||
+
|
||||
+ if (sandboxedAppId != null)
|
||||
+ windowsList[windowId]['sandboxed-app-id'] =
|
||||
+ GLib.Variant.new('s', sandboxedAppId);
|
||||
}
|
||||
}
|
||||
invocation.return_value(new GLib.Variant('(a{ta{sv}})', [windowsList]));
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From b0b4fb82c058722e2171d24902ba3855ffe243f3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Wed, 18 Sep 2019 14:57:48 +0200
|
||||
Subject: [PATCH 02/11] introspect: Check whitelist also for
|
||||
GetRunningWindows()
|
||||
|
||||
Otherwise the xdg-desktop-portal-gtk screen cast widget won't work.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/732
|
||||
---
|
||||
js/misc/introspect.js | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index 1e8300d0a..cee6409a8 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -128,7 +128,8 @@ var IntrospectService = class {
|
||||
let apps = this._appSystem.get_running();
|
||||
let windowsList = {};
|
||||
|
||||
- if (!this._isIntrospectEnabled()) {
|
||||
+ if (!this._isIntrospectEnabled() &&
|
||||
+ !this._isSenderWhitelisted(invocation.get_sender())) {
|
||||
invocation.return_error_literal(Gio.DBusError,
|
||||
Gio.DBusError.ACCESS_DENIED,
|
||||
'App introspection not allowed');
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 23556e03db3743ddf478a3c1bbb64946c687afdf Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
|
||||
Date: Mon, 25 Nov 2019 19:44:10 +0100
|
||||
Subject: [PATCH 03/11] introspect: Fix whitelist check
|
||||
|
||||
The whitelist is a list of well-known D-Bus names, which we then search
|
||||
for the unique name we get from the method invocation - unsuccesfully.
|
||||
|
||||
Fix this by watching the bus for any name in the whitelist in order
|
||||
to maintain a map from wel-known to unique name that we can use for
|
||||
matching.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1916
|
||||
---
|
||||
js/misc/introspect.js | 11 ++++++++++-
|
||||
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index cee6409a8..f14eabfad 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -39,6 +39,15 @@ var IntrospectService = class {
|
||||
});
|
||||
|
||||
this._syncRunningApplications();
|
||||
+
|
||||
+ this._whitelistMap = new Map();
|
||||
+ APP_WHITELIST.forEach(appName => {
|
||||
+ Gio.DBus.watch_name(Gio.BusType.SESSION,
|
||||
+ appName,
|
||||
+ Gio.BusNameWatcherFlags.NONE,
|
||||
+ (conn, name, owner) => this._whitelistMap.set(name, owner),
|
||||
+ (conn, name) => this._whitelistMap.delete(name));
|
||||
+ });
|
||||
}
|
||||
|
||||
_isStandaloneApp(app) {
|
||||
@@ -52,7 +61,7 @@ var IntrospectService = class {
|
||||
}
|
||||
|
||||
_isSenderWhitelisted(sender) {
|
||||
- return APP_WHITELIST.includes(sender);
|
||||
+ return [...this._whitelistMap.values()].includes(sender);
|
||||
}
|
||||
|
||||
_getSandboxedAppId(app) {
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 1a6275add6d214df958ed8a06c097445bef021bc Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Wed, 25 Sep 2019 20:36:28 +0200
|
||||
Subject: [PATCH 04/11] introspect: Add helper to check method call permission
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
js/misc/introspect.js | 16 ++++++++++++----
|
||||
1 file changed, 12 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index f14eabfad..6186754cd 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -120,9 +120,18 @@ var IntrospectService = class {
|
||||
type == Meta.WindowType.UTILITY);
|
||||
}
|
||||
|
||||
+ _isInvocationAllowed(invocation) {
|
||||
+ if (this._isIntrospectEnabled())
|
||||
+ return true;
|
||||
+
|
||||
+ if (this._isSenderWhitelisted(invocation.get_sender()))
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
GetRunningApplicationsAsync(params, invocation) {
|
||||
- if (!this._isIntrospectEnabled() &&
|
||||
- !this._isSenderWhitelisted(invocation.get_sender())) {
|
||||
+ if (!this._isInvocationAllowed(invocation)) {
|
||||
invocation.return_error_literal(Gio.DBusError,
|
||||
Gio.DBusError.ACCESS_DENIED,
|
||||
'App introspection not allowed');
|
||||
@@ -137,8 +146,7 @@ var IntrospectService = class {
|
||||
let apps = this._appSystem.get_running();
|
||||
let windowsList = {};
|
||||
|
||||
- if (!this._isIntrospectEnabled() &&
|
||||
- !this._isSenderWhitelisted(invocation.get_sender())) {
|
||||
+ if (!this._isInvocationAllowed(invocation)) {
|
||||
invocation.return_error_literal(Gio.DBusError,
|
||||
Gio.DBusError.ACCESS_DENIED,
|
||||
'App introspection not allowed');
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From f578dc01cf774faa4504a4d258cc0e82060d988b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 11:55:33 +0200
|
||||
Subject: [PATCH 05/11] shell-util: Add API to check for X11 extensions
|
||||
|
||||
Will be used to disable animations when running inside Xvnc. This was
|
||||
done in gsd-xsettings before.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
src/shell-util.c | 26 ++++++++++++++++++++++++++
|
||||
src/shell-util.h | 3 +++
|
||||
2 files changed, 29 insertions(+)
|
||||
|
||||
diff --git a/src/shell-util.c b/src/shell-util.c
|
||||
index 31bb18e70..fa3fc08c8 100644
|
||||
--- a/src/shell-util.c
|
||||
+++ b/src/shell-util.c
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <meta/meta-shaped-texture.h>
|
||||
+#include <meta/display.h>
|
||||
+#include <meta/meta-x11-display.h>
|
||||
|
||||
#include <locale.h>
|
||||
#ifdef HAVE__NL_TIME_FIRST_WEEKDAY
|
||||
@@ -613,3 +615,27 @@ shell_util_check_cloexec_fds (void)
|
||||
fdwalk (check_cloexec, NULL);
|
||||
g_info ("Open fd CLOEXEC check complete");
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * shell_util_has_x11_display_extension:
|
||||
+ * @display: A #MetaDisplay
|
||||
+ * @extension: An X11 extension
|
||||
+ *
|
||||
+ * If the corresponding X11 display provides the passed extension, return %TRUE,
|
||||
+ * otherwise %FALSE. If there is no X11 display, %FALSE is passed.
|
||||
+ */
|
||||
+gboolean
|
||||
+shell_util_has_x11_display_extension (MetaDisplay *display,
|
||||
+ const char *extension)
|
||||
+{
|
||||
+ MetaX11Display *x11_display;
|
||||
+ Display *xdisplay;
|
||||
+ int op, event, error;
|
||||
+
|
||||
+ x11_display = meta_display_get_x11_display (display);
|
||||
+ if (!x11_display)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ xdisplay = meta_x11_display_get_xdisplay (x11_display);
|
||||
+ return XQueryExtension (xdisplay, extension, &op, &event, &error);
|
||||
+}
|
||||
diff --git a/src/shell-util.h b/src/shell-util.h
|
||||
index 6904f43bc..02b8404e9 100644
|
||||
--- a/src/shell-util.h
|
||||
+++ b/src/shell-util.h
|
||||
@@ -59,6 +59,9 @@ cairo_surface_t * shell_util_composite_capture_images (ClutterCapture *captures
|
||||
|
||||
void shell_util_check_cloexec_fds (void);
|
||||
|
||||
+gboolean shell_util_has_x11_display_extension (MetaDisplay *display,
|
||||
+ const char *extension);
|
||||
+
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_UTIL_H__ */
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 48ee79bb7b48c7e93e77e35629f21bbdbabc253f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 11:56:34 +0200
|
||||
Subject: [PATCH 06/11] st/settings: Add API to inhibit animations
|
||||
|
||||
There may be situations where we shouldn't enable animations. Make it
|
||||
possible for the Shell to decide when there are such situations and in
|
||||
when needed inhibit animations.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
src/st/st-settings.c | 38 +++++++++++++++++++++++++++++++++++++-
|
||||
src/st/st-settings.h | 4 ++++
|
||||
2 files changed, 41 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/st/st-settings.c b/src/st/st-settings.c
|
||||
index 17f2c466e..ebfd28480 100644
|
||||
--- a/src/st/st-settings.c
|
||||
+++ b/src/st/st-settings.c
|
||||
@@ -54,6 +54,7 @@ struct _StSettings
|
||||
|
||||
gchar *gtk_theme;
|
||||
gchar *gtk_icon_theme;
|
||||
+ int inhibit_animations_count;
|
||||
gboolean enable_animations;
|
||||
gboolean primary_paste;
|
||||
gboolean magnifier_active;
|
||||
@@ -62,6 +63,41 @@ struct _StSettings
|
||||
|
||||
G_DEFINE_TYPE (StSettings, st_settings, G_TYPE_OBJECT)
|
||||
|
||||
+static gboolean
|
||||
+get_enable_animations (StSettings *settings)
|
||||
+{
|
||||
+ if (settings->inhibit_animations_count > 0)
|
||||
+ return FALSE;
|
||||
+ else
|
||||
+ return settings->enable_animations;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+st_settings_inhibit_animations (StSettings *settings)
|
||||
+{
|
||||
+ gboolean enable_animations;
|
||||
+
|
||||
+ enable_animations = get_enable_animations (settings);
|
||||
+ settings->inhibit_animations_count++;
|
||||
+
|
||||
+ if (enable_animations != get_enable_animations (settings))
|
||||
+ g_object_notify_by_pspec (G_OBJECT (settings),
|
||||
+ props[PROP_ENABLE_ANIMATIONS]);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+st_settings_uninhibit_animations (StSettings *settings)
|
||||
+{
|
||||
+ gboolean enable_animations;
|
||||
+
|
||||
+ enable_animations = get_enable_animations (settings);
|
||||
+ settings->inhibit_animations_count--;
|
||||
+
|
||||
+ if (enable_animations != get_enable_animations (settings))
|
||||
+ g_object_notify_by_pspec (G_OBJECT (settings),
|
||||
+ props[PROP_ENABLE_ANIMATIONS]);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
st_settings_finalize (GObject *object)
|
||||
{
|
||||
@@ -95,7 +131,7 @@ st_settings_get_property (GObject *object,
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ENABLE_ANIMATIONS:
|
||||
- g_value_set_boolean (value, settings->enable_animations);
|
||||
+ g_value_set_boolean (value, get_enable_animations (settings));
|
||||
break;
|
||||
case PROP_PRIMARY_PASTE:
|
||||
g_value_set_boolean (value, settings->primary_paste);
|
||||
diff --git a/src/st/st-settings.h b/src/st/st-settings.h
|
||||
index c2c4fa23e..8b2549469 100644
|
||||
--- a/src/st/st-settings.h
|
||||
+++ b/src/st/st-settings.h
|
||||
@@ -33,6 +33,10 @@ G_DECLARE_FINAL_TYPE (StSettings, st_settings, ST, SETTINGS, GObject)
|
||||
|
||||
StSettings * st_settings_get (void);
|
||||
|
||||
+void st_settings_inhibit_animations (StSettings *settings);
|
||||
+
|
||||
+void st_settings_uninhibit_animations (StSettings *settings);
|
||||
+
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_SETTINGS_H__ */
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 80025388c44296b629c8f24ea673d77ffc4efc67 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 12:02:31 +0200
|
||||
Subject: [PATCH 07/11] main: Inhibit animations when software rendered
|
||||
|
||||
This was previously decided by gsd-xsettings.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
js/ui/main.js | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index 978f83c3f..c3230ff03 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -147,6 +147,8 @@ function _initializeUI() {
|
||||
_loadOskLayouts();
|
||||
_loadDefaultStylesheet();
|
||||
|
||||
+ new AnimationsSettings();
|
||||
+
|
||||
// Setup the stage hierarchy early
|
||||
layoutManager = new Layout.LayoutManager();
|
||||
|
||||
@@ -723,3 +725,13 @@ function showRestartMessage(message) {
|
||||
let restartMessage = new RestartMessage(message);
|
||||
restartMessage.open();
|
||||
}
|
||||
+
|
||||
+var AnimationsSettings = class {
|
||||
+ constructor() {
|
||||
+ let backend = Meta.get_backend();
|
||||
+ if (!backend.is_rendering_hardware_accelerated()) {
|
||||
+ St.Settings.get().inhibit_animations();
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+};
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 788ecb60e35d8a369f0747813f37e8b1ca27cb87 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 12:03:52 +0200
|
||||
Subject: [PATCH 08/11] main: Inhibit animations if X server advertises
|
||||
VNC-EXTENSION
|
||||
|
||||
This was previously done by gsd-xsettings to disable animations when
|
||||
running in Xvnc.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
js/ui/main.js | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index c3230ff03..ae7c3ffd0 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -733,5 +733,12 @@ var AnimationsSettings = class {
|
||||
St.Settings.get().inhibit_animations();
|
||||
return;
|
||||
}
|
||||
+
|
||||
+ let isXvnc = Shell.util_has_x11_display_extension(
|
||||
+ global.display, 'VNC-EXTENSION');
|
||||
+ if (isXvnc) {
|
||||
+ St.Settings.get().inhibit_animations();
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
};
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 1da5a7ce4cf0b95b96dd50b62ac6c1380fd88cb1 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 12:04:52 +0200
|
||||
Subject: [PATCH 09/11] main: Inhibit animations when there is a remote desktop
|
||||
session
|
||||
|
||||
If a remote desktop session asks for animations to be disabled, inhibit
|
||||
animations while the session is active.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
js/ui/main.js | 26 ++++++++++++++++++++++++++
|
||||
1 file changed, 26 insertions(+)
|
||||
|
||||
diff --git a/js/ui/main.js b/js/ui/main.js
|
||||
index ae7c3ffd0..1203b3c39 100644
|
||||
--- a/js/ui/main.js
|
||||
+++ b/js/ui/main.js
|
||||
@@ -740,5 +740,31 @@ var AnimationsSettings = class {
|
||||
St.Settings.get().inhibit_animations();
|
||||
return;
|
||||
}
|
||||
+
|
||||
+ let remoteAccessController = backend.get_remote_access_controller();
|
||||
+ if (!remoteAccessController)
|
||||
+ return;
|
||||
+
|
||||
+ this._handles = new Set();
|
||||
+ remoteAccessController.connect('new-handle',
|
||||
+ (_, handle) => this._onNewRemoteAccessHandle(handle));
|
||||
+ }
|
||||
+
|
||||
+ _onRemoteAccessHandleStopped(handle) {
|
||||
+ let settings = St.Settings.get();
|
||||
+
|
||||
+ settings.uninhibit_animations();
|
||||
+ this._handles.delete(handle);
|
||||
+ }
|
||||
+
|
||||
+ _onNewRemoteAccessHandle(handle) {
|
||||
+ if (!handle.get_disable_animations())
|
||||
+ return;
|
||||
+
|
||||
+ let settings = St.Settings.get();
|
||||
+
|
||||
+ settings.inhibit_animations();
|
||||
+ this._handles.add(handle);
|
||||
+ handle.connect('stopped', this._onRemoteAccessHandleStopped.bind(this));
|
||||
}
|
||||
};
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From ebfd46341a2d7a6338386e4be4a2807a6bc6e63c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 12:06:13 +0200
|
||||
Subject: [PATCH 10/11] introspect: Rename variable
|
||||
|
||||
It was too generic, and would conflict with a StSettings variable.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
js/misc/introspect.js | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index 6186754cd..8e68a7e4f 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -29,7 +29,9 @@ var IntrospectService = class {
|
||||
this._syncRunningApplications();
|
||||
});
|
||||
|
||||
- this._settings = new Gio.Settings({ schema_id: INTROSPECT_SCHEMA });
|
||||
+ this._introspectSettings = new Gio.Settings({
|
||||
+ schema_id: INTROSPECT_SCHEMA,
|
||||
+ });
|
||||
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
tracker.connect('notify::focus-app',
|
||||
@@ -57,7 +59,7 @@ var IntrospectService = class {
|
||||
}
|
||||
|
||||
_isIntrospectEnabled() {
|
||||
- return this._settings.get_boolean(INTROSPECT_KEY);
|
||||
+ return this._introspectSettings.get_boolean(INTROSPECT_KEY);
|
||||
}
|
||||
|
||||
_isSenderWhitelisted(sender) {
|
||||
--
|
||||
2.26.2
|
||||
|
||||
|
||||
From 343e7792fc84c296b331c3fcb142ed79d2ce9bd5 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
||||
Date: Tue, 1 Oct 2019 12:07:03 +0200
|
||||
Subject: [PATCH 11/11] introspect: Add AnimationsEnabled property
|
||||
|
||||
While the gsetting is available for all who needs it, the Shell might
|
||||
override it given various hueristics. Expose the decision made by the
|
||||
Shell via a new property.
|
||||
|
||||
Intended to be used by gsd-xsettings as well as xdg-desktop-portal-gtk.
|
||||
|
||||
This also add a version property to the API, so that semi external
|
||||
services (xdg-desktop-portal-gtk) can detect what API is expected to be
|
||||
present.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/757
|
||||
---
|
||||
.../org.gnome.Shell.Introspect.xml | 14 ++++++++++
|
||||
js/misc/introspect.js | 27 ++++++++++++++++++-
|
||||
2 files changed, 40 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/data/dbus-interfaces/org.gnome.Shell.Introspect.xml b/data/dbus-interfaces/org.gnome.Shell.Introspect.xml
|
||||
index 9508681af..d71f2414b 100644
|
||||
--- a/data/dbus-interfaces/org.gnome.Shell.Introspect.xml
|
||||
+++ b/data/dbus-interfaces/org.gnome.Shell.Introspect.xml
|
||||
@@ -57,5 +57,19 @@
|
||||
<method name="GetWindows">
|
||||
<arg name="windows" direction="out" type="a{ta{sv}}" />
|
||||
</method>
|
||||
+
|
||||
+ <!--
|
||||
+ AnimationsEnabled:
|
||||
+ @short_description: Whether the shell animations are enabled
|
||||
+
|
||||
+ By default determined by the org.gnome.desktop.interface enable-animations
|
||||
+ gsetting, but may be overridden, e.g. if there is an active screen cast or
|
||||
+ remote desktop session that asked for animations to be disabled.
|
||||
+
|
||||
+ Since: 2
|
||||
+ -->
|
||||
+ <property name="AnimationsEnabled" type="b" access="read"/>
|
||||
+
|
||||
+ <property name="version" type="u" access="read"/>
|
||||
</interface>
|
||||
</node>
|
||||
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
||||
index 8e68a7e4f..7c62113e5 100644
|
||||
--- a/js/misc/introspect.js
|
||||
+++ b/js/misc/introspect.js
|
||||
@@ -1,9 +1,11 @@
|
||||
-const { Gio, GLib, Meta, Shell } = imports.gi;
|
||||
+const { Gio, GLib, Meta, Shell, St } = imports.gi;
|
||||
|
||||
const INTROSPECT_SCHEMA = 'org.gnome.shell';
|
||||
const INTROSPECT_KEY = 'introspect';
|
||||
const APP_WHITELIST = ['org.freedesktop.impl.portal.desktop.gtk'];
|
||||
|
||||
+const INTROSPECT_DBUS_API_VERSION = 2;
|
||||
+
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
const IntrospectDBusIface = loadInterfaceXML('org.gnome.Shell.Introspect');
|
||||
@@ -21,6 +23,7 @@ var IntrospectService = class {
|
||||
this._runningApplicationsDirty = true;
|
||||
this._activeApplication = null;
|
||||
this._activeApplicationDirty = true;
|
||||
+ this._animationsEnabled = true;
|
||||
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appSystem.connect('app-state-changed',
|
||||
@@ -50,6 +53,11 @@ var IntrospectService = class {
|
||||
(conn, name, owner) => this._whitelistMap.set(name, owner),
|
||||
(conn, name) => this._whitelistMap.delete(name));
|
||||
});
|
||||
+
|
||||
+ this._settings = St.Settings.get();
|
||||
+ this._settings.connect('notify::enable-animations',
|
||||
+ this._syncAnimationsEnabled.bind(this));
|
||||
+ this._syncAnimationsEnabled();
|
||||
}
|
||||
|
||||
_isStandaloneApp(app) {
|
||||
@@ -191,4 +199,21 @@ var IntrospectService = class {
|
||||
}
|
||||
invocation.return_value(new GLib.Variant('(a{ta{sv}})', [windowsList]));
|
||||
}
|
||||
+
|
||||
+ _syncAnimationsEnabled() {
|
||||
+ let wasAnimationsEnabled = this._animationsEnabled;
|
||||
+ this._animationsEnabled = this._settings.enable_animations;
|
||||
+ if (wasAnimationsEnabled !== this._animationsEnabled) {
|
||||
+ let variant = new GLib.Variant('b', this._animationsEnabled);
|
||||
+ this._dbusImpl.emit_property_changed('AnimationsEnabled', variant);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ get AnimationsEnabled() {
|
||||
+ return this._animationsEnabled;
|
||||
+ }
|
||||
+
|
||||
+ get version() {
|
||||
+ return INTROSPECT_DBUS_API_VERSION;
|
||||
+ }
|
||||
};
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,227 @@
|
||||
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
|
||||
|
@ -1,176 +0,0 @@
|
||||
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…
Reference in new issue