diff --git a/0001-Do-not-change-Wacom-LEDs-through-g-s-d.patch b/0001-Do-not-change-Wacom-LEDs-through-g-s-d.patch deleted file mode 100644 index 9eb76be7ca868032e94ee3d70f3cebf9e322d1b5..0000000000000000000000000000000000000000 --- a/0001-Do-not-change-Wacom-LEDs-through-g-s-d.patch +++ /dev/null @@ -1,25 +0,0 @@ -From f5ddd0fc02e99597e4b8506ac35523a6fa8ac22f Mon Sep 17 00:00:00 2001 -From: 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 - diff --git a/0001-Revert-dash-Subtract-vertical-margins-from-availHeig.patch b/0001-Revert-dash-Subtract-vertical-margins-from-availHeig.patch new file mode 100644 index 0000000000000000000000000000000000000000..a62d76ed59540fac493d57eee0d8a21cfbe11cbc --- /dev/null +++ b/0001-Revert-dash-Subtract-vertical-margins-from-availHeig.patch @@ -0,0 +1,25 @@ +From a8c8b7ef31f7219157b94148b771f6f663928dea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +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 + diff --git a/0001-Update-generated-stylesheets.patch b/0001-Update-generated-stylesheets.patch new file mode 100644 index 0000000000000000000000000000000000000000..4133dd63e393766c843a51e790f77badfe530d63 --- /dev/null +++ b/0001-Update-generated-stylesheets.patch @@ -0,0 +1,364 @@ +From 678cdd9e0da851da78527fa827d71a80273510b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +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 + diff --git a/0001-a11y-Change-HC-icon-theme-first.patch b/0001-a11y-Change-HC-icon-theme-first.patch deleted file mode 100644 index f5eebd6378dd4b25101a59c35673ea8b83f3ccf8..0000000000000000000000000000000000000000 --- a/0001-a11y-Change-HC-icon-theme-first.patch +++ /dev/null @@ -1,58 +0,0 @@ -From a94260b4f2f72ea9328a0194b8656f1fb3e98675 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 - diff --git a/0001-animation-fix-unintentional-loop-while-polkit-dialog.patch b/0001-animation-fix-unintentional-loop-while-polkit-dialog.patch deleted file mode 100644 index 748b73fcc76a86bc60d1847d6ab7d6df55699c86..0000000000000000000000000000000000000000 --- a/0001-animation-fix-unintentional-loop-while-polkit-dialog.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 34e6bbeebef37ae688ca0527bde03fa26b143bb7 Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0001-app-Fall-back-to-window-title-instead-of-WM_CLASS.patch b/0001-app-Fall-back-to-window-title-instead-of-WM_CLASS.patch index 77f7cb12c29aee718060396a49e0aab781d91852..001e8966b4c19ae3b8b7060a90b2c80aabb18bed 100644 --- a/0001-app-Fall-back-to-window-title-instead-of-WM_CLASS.patch +++ b/0001-app-Fall-back-to-window-title-instead-of-WM_CLASS.patch @@ -1,4 +1,4 @@ -From 23755cc20f3c05b97f769e27553f2ab482d60137 Mon Sep 17 00:00:00 2001 +From afa3fc7be62cf70c9f6c6954e9cf5b49581269fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 20 May 2015 16:44:00 +0200 Subject: [PATCH] app: Fall back to window title instead of WM_CLASS @@ -11,10 +11,10 @@ a .desktop file ... 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell-app.c b/src/shell-app.c -index 10efa9135..7d40186c9 100644 +index 62ba2ec73..dc0e1c732 100644 --- a/src/shell-app.c +++ b/src/shell-app.c -@@ -259,7 +259,7 @@ shell_app_get_name (ShellApp *app) +@@ -293,7 +293,7 @@ shell_app_get_name (ShellApp *app) const char *name = NULL; if (window) @@ -24,5 +24,5 @@ index 10efa9135..7d40186c9 100644 name = C_("program", "Unknown"); return name; -- -2.21.0 +2.31.1 diff --git a/0001-appDisplay-Show-full-app-name-on-hover.patch b/0001-appDisplay-Show-full-app-name-on-hover.patch deleted file mode 100644 index ddd3d97f126f18fdc2dae55847a7739581f32114..0000000000000000000000000000000000000000 --- a/0001-appDisplay-Show-full-app-name-on-hover.patch +++ /dev/null @@ -1,111 +0,0 @@ -From a1c35ebb8f29103035526e6f48eba4ff37551964 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 - diff --git a/0001-background-refresh-after-suspend-on-wayland.patch b/0001-background-refresh-after-suspend-on-wayland.patch deleted file mode 100644 index ffcbca0ab2f4032f959b9794937aee605a8128d4..0000000000000000000000000000000000000000 --- a/0001-background-refresh-after-suspend-on-wayland.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 165fc5147cd2c9bf4bc10a1c5a9a940ec4ddd8d9 Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0001-data-install-process-working.svg-to-filesystem.patch b/0001-data-install-process-working.svg-to-filesystem.patch deleted file mode 100644 index 9782372857a058957897dd2577af12737ba30a91..0000000000000000000000000000000000000000 --- a/0001-data-install-process-working.svg-to-filesystem.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 1dcae7bbba222a1c8bdfc2d76a9f716e638b0334 Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0001-environment-reduce-calls-to-g_time_zone_new_local.patch b/0001-environment-reduce-calls-to-g_time_zone_new_local.patch deleted file mode 100644 index 3528e9dbefdac1ebd0f7567b45c9bda12bb9d9cb..0000000000000000000000000000000000000000 --- a/0001-environment-reduce-calls-to-g_time_zone_new_local.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 6e80934456f0b4cc48da6a7201700dc4386a3474 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 ---- - 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 - diff --git a/0001-extensionDownloader-Refuse-to-override-system-extens.patch b/0001-extensionDownloader-Refuse-to-override-system-extens.patch new file mode 100644 index 0000000000000000000000000000000000000000..58a3ee85d36c4c4eed434a488e8a892084670d67 --- /dev/null +++ b/0001-extensionDownloader-Refuse-to-override-system-extens.patch @@ -0,0 +1,36 @@ +From c18b7b7819f17f5d14be1ba2760653f3d93b81b1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +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 + diff --git a/0001-extensionSystem-Handle-added-or-removed-sessionMode-.patch b/0001-extensionSystem-Handle-added-or-removed-sessionMode-.patch deleted file mode 100644 index 2a8ff218a0caa603d0b5e12197877d6706894f1c..0000000000000000000000000000000000000000 --- a/0001-extensionSystem-Handle-added-or-removed-sessionMode-.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 1b6eb29ade832647510b36ddc13c9b88a25036df Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -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 - diff --git a/0001-extensions-Add-a-SESSION_MODE-extension-type.patch b/0001-extensions-Add-a-SESSION_MODE-extension-type.patch deleted file mode 100644 index dc7619bf7693f214842e3b03990eb766310b550f..0000000000000000000000000000000000000000 --- a/0001-extensions-Add-a-SESSION_MODE-extension-type.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 720eb83ba0b0e5e37185d7e7ed86fe9175cf18f4 Mon Sep 17 00:00:00 2001 -From: Rui Matos -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 - diff --git a/0001-gdm-add-AuthList-control.patch b/0001-gdm-add-AuthList-control.patch deleted file mode 100644 index 2bd503bd4e1a57494bbcc9223393b493c10b8176..0000000000000000000000000000000000000000 --- a/0001-gdm-add-AuthList-control.patch +++ /dev/null @@ -1,237 +0,0 @@ -From 592bf9b4ba879a365375a7edcb6c48258386e413 Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 . -+ */ -+ -+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 @@ - - - -+ gdm/authList.js - gdm/authPrompt.js - gdm/batch.js - gdm/fingerprint.js --- -2.21.0 - diff --git a/0001-kbdA11yDialog-Use-MetaKeyboardA11yFlags.patch b/0001-kbdA11yDialog-Use-MetaKeyboardA11yFlags.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ff43aac2c6ad0b0b402ae77c7833cd6018efb79 --- /dev/null +++ b/0001-kbdA11yDialog-Use-MetaKeyboardA11yFlags.patch @@ -0,0 +1,51 @@ +From bd4fef8354ff0730c1e96a47d77adbb4a4d7beaa Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +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: +--- + 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 + diff --git a/0001-keyboard-Only-enable-keyboard-if-ClutterDeviceManage.patch b/0001-keyboard-Only-enable-keyboard-if-ClutterDeviceManage.patch deleted file mode 100644 index a781d433fd9e2b4199f06b397cb5d08bd803b60e..0000000000000000000000000000000000000000 --- a/0001-keyboard-Only-enable-keyboard-if-ClutterDeviceManage.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 2acede02f30833c3fb891db8483f933f7b41508c Mon Sep 17 00:00:00 2001 -From: 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 - diff --git a/0001-layout-Make-the-hot-corner-optional.patch b/0001-layout-Make-the-hot-corner-optional.patch deleted file mode 100644 index c77310cebb1ef56b2016680eaa1e12332a23dd29..0000000000000000000000000000000000000000 --- a/0001-layout-Make-the-hot-corner-optional.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 35cbad572120125d3b823f37d2100b2beee4c1d8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 - diff --git a/0001-loginDialog-Reset-auth-prompt-on-vt-switch-before-fa.patch b/0001-loginDialog-Reset-auth-prompt-on-vt-switch-before-fa.patch deleted file mode 100644 index 85cdbbb0566bf5a44cc61513b5aba9ab4b8a896a..0000000000000000000000000000000000000000 --- a/0001-loginDialog-Reset-auth-prompt-on-vt-switch-before-fa.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 6d26b6f9f66e14843f175305441a2464dd255fd1 Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0001-loginDialog-make-info-messages-themed.patch b/0001-loginDialog-make-info-messages-themed.patch index 483f6154403635da6b21c0d58b72f1c684896834..761f06a8ac958fe2b5c3e4a53dda659eb06c3dac 100644 --- a/0001-loginDialog-make-info-messages-themed.patch +++ b/0001-loginDialog-make-info-messages-themed.patch @@ -1,4 +1,4 @@ -From 9cfa56d4f3c5fe513630c58c09bd2421f3ca580b Mon Sep 17 00:00:00 2001 +From 4ad30b5c506ab043c2091441021b6cf334e2412f Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 26 Jun 2017 14:35:05 -0400 Subject: [PATCH] loginDialog: make info messages themed @@ -6,27 +6,78 @@ Subject: [PATCH] loginDialog: make info messages themed They were lacking a definition before leading them to show up invisible. --- - data/theme/gnome-shell-sass/_common.scss | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) + data/theme/gnome-shell-sass/widgets/_login-dialog.scss | 4 ++++ + 1 file changed, 4 insertions(+) -diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss -index c2df28279..a382ce561 100644 ---- a/data/theme/gnome-shell-sass/_common.scss -+++ b/data/theme/gnome-shell-sass/_common.scss -@@ -1801,7 +1801,12 @@ StScrollBar { - .login-dialog-banner { color: darken($osd_fg_color,10%); } - .login-dialog-button-box { spacing: 5px; } - .login-dialog-message-warning { color: $warning_color; } -- .login-dialog-message-hint { padding-top: 0; padding-bottom: 20px; } -+ .login-dialog-message-hint, .login-dialog-message { -+ color: darken($osd_fg_color, 20%); -+ padding-top: 0; -+ padding-bottom: 20px; -+ min-height: 2.75em; -+ } - .login-dialog-user-selection-box { padding: 100px 0px; } - .login-dialog-not-listed-label { - padding-left: 2px; +diff --git a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss +index 1789beca9..84539342d 100644 +--- a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss ++++ b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss +@@ -66,60 +66,64 @@ + border-color: darken($selected_bg_color, 10%); + background-color: darken($selected_bg_color, 10%); + color: transparentize($selected_fg_color, 0.3); + } + } + } + + .cancel-button, + .switch-user-button, + .login-dialog-session-list-button { + padding: 0; + border-radius: 99px; + width: $base_icon_size * 2; + height: $base_icon_size * 2; + border-color: darken($system_bg_color, 3%); + background-color: darken($system_bg_color, 3%); + + StIcon { icon-size: $base_icon_size; } + } + + .caps-lock-warning-label, + .login-dialog-message-warning { + color: $osd_fg_color; + } + } + + .login-dialog-logo-bin { padding: 24px 0px; } + .login-dialog-banner { color: darken($osd_fg_color,10%); } + .login-dialog-button-box { width: 23em; spacing: 5px; } + .login-dialog-message { text-align: center; } ++.login-dialog-message-hint, .login-dialog-message { ++ color: darken($osd_fg_color, 20%); ++ min-height: 2.75em; ++} + .login-dialog-user-selection-box { padding: 100px 0px; } + .login-dialog-not-listed-label { + padding-left: 2px; + .login-dialog-not-listed-button:focus &, + .login-dialog-not-listed-button:hover & { + color: $osd_fg_color; + } + } + + .login-dialog-not-listed-label { + @include fontsize($base_font_size - 1); + font-weight: bold; + color: darken($osd_fg_color,30%); + padding-top: 1em; + } + + .login-dialog-user-list-view { -st-vfade-offset: 1em; } + .login-dialog-user-list { + spacing: 12px; + width: 23em; + &:expanded .login-dialog-user-list-item:selected { background-color: $selected_bg_color; color: $selected_fg_color; } + &:expanded .login-dialog-user-list-item:logged-in { border-right: 2px solid $selected_bg_color; } + } + + .login-dialog-user-list-item { + border-radius: $base_border_radius + 4px; + padding: 6px; + color: darken($osd_fg_color,30%); + &:ltr .user-widget { padding-right: 1em; } + &:rtl .user-widget { padding-left: 1em; } -- -2.21.0 +2.34.1 diff --git a/0001-main-Dump-stack-on-segfaults-by-default.patch b/0001-main-Dump-stack-on-segfaults-by-default.patch index 75b9b1a8dacfada3d23a83a23bedaa6db8e67f59..57dc9f06b37007669776b03f61122a0e8f8882b5 100644 --- a/0001-main-Dump-stack-on-segfaults-by-default.patch +++ b/0001-main-Dump-stack-on-segfaults-by-default.patch @@ -1,4 +1,4 @@ -From ba3ce64fbbce20192a55f9d438d1032c0bac0557 Mon Sep 17 00:00:00 2001 +From f54c3f9f66001c210e10fda6aa17b9218fb67dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 29 Oct 2020 18:21:06 +0100 Subject: [PATCH] main: Dump stack on segfaults by default @@ -8,10 +8,10 @@ Subject: [PATCH] main: Dump stack on segfaults by default 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c -index 245837783..788309de7 100644 +index 5d07a4301..ed0b78dcc 100644 --- a/src/main.c +++ b/src/main.c -@@ -39,6 +39,7 @@ static int caught_signal = 0; +@@ -38,6 +38,7 @@ static int caught_signal = 0; #define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 #define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 @@ -19,7 +19,7 @@ index 245837783..788309de7 100644 enum { SHELL_DEBUG_BACKTRACE_WARNINGS = 1, SHELL_DEBUG_BACKTRACE_SEGFAULTS = 2, -@@ -268,8 +269,11 @@ shell_init_debug (const char *debug_env) +@@ -279,8 +280,11 @@ shell_init_debug (const char *debug_env) { "backtrace-segfaults", SHELL_DEBUG_BACKTRACE_SEGFAULTS }, }; @@ -34,5 +34,5 @@ index 245837783..788309de7 100644 static void -- -2.29.2 +2.31.1 diff --git a/0001-main-Leak-the-GJS-context-and-ShellGlobal.patch b/0001-main-Leak-the-GJS-context-and-ShellGlobal.patch new file mode 100644 index 0000000000000000000000000000000000000000..250416d5e930fdab602288885dc3a982d81cba15 --- /dev/null +++ b/0001-main-Leak-the-GJS-context-and-ShellGlobal.patch @@ -0,0 +1,31 @@ +From a9e79b1657dc7c1b702d7acc4d322539d2b8b6aa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +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 + diff --git a/0001-networkAgent-add-support-for-SAE-secrets.patch b/0001-networkAgent-add-support-for-SAE-secrets.patch deleted file mode 100644 index dd05d56409af7706455f725e50bb45f213db43ae..0000000000000000000000000000000000000000 --- a/0001-networkAgent-add-support-for-SAE-secrets.patch +++ /dev/null @@ -1,29 +0,0 @@ -From bd4a3186dc21f2c8d3e0f851cf262a34ddb6b625 Mon Sep 17 00:00:00 2001 -From: Lubomir Rintel -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 - diff --git a/0001-padOsd-Re-query-action-labels-after-mode-switches.patch b/0001-padOsd-Re-query-action-labels-after-mode-switches.patch deleted file mode 100644 index bdbfc6584295297ed64e5beabc1046374a0955a2..0000000000000000000000000000000000000000 --- a/0001-padOsd-Re-query-action-labels-after-mode-switches.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 2bb826291c420dd1b601758c7a686ac48e1086a6 Mon Sep 17 00:00:00 2001 -From: Carlos Garnacho -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 - diff --git a/0001-panel-add-an-icon-to-the-ActivitiesButton.patch b/0001-panel-add-an-icon-to-the-ActivitiesButton.patch index 24c0d81eff83d417837989331c396af8f75874dc..8ebfc4621362c69b7d2646a6d4119028f64d791a 100644 --- a/0001-panel-add-an-icon-to-the-ActivitiesButton.patch +++ b/0001-panel-add-an-icon-to-the-ActivitiesButton.patch @@ -1,20 +1,20 @@ -From aadb0e19999c339ac1d6501a2e52b363e57e26ef Mon Sep 17 00:00:00 2001 +From b5db4d318546654f4e9c1e4999fa00456441f105 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 15 Jan 2014 16:45:34 -0500 Subject: [PATCH] panel: add an icon to the ActivitiesButton Requested by brand --- - data/theme/gnome-shell-sass/_common.scss | 5 +++++ - js/ui/panel.js | 9 ++++++++- - 2 files changed, 13 insertions(+), 1 deletion(-) + data/theme/gnome-shell-sass/widgets/_panel.scss | 5 +++++ + js/ui/panel.js | 11 ++++++++++- + 2 files changed, 15 insertions(+), 1 deletion(-) -diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss -index a382ce561..3b0d2bf04 100644 ---- a/data/theme/gnome-shell-sass/_common.scss -+++ b/data/theme/gnome-shell-sass/_common.scss -@@ -769,6 +769,11 @@ StScrollBar { - //dimensions of the icon are hardcoded +diff --git a/data/theme/gnome-shell-sass/widgets/_panel.scss b/data/theme/gnome-shell-sass/widgets/_panel.scss +index 1f4650773..5f323cbc8 100644 +--- a/data/theme/gnome-shell-sass/widgets/_panel.scss ++++ b/data/theme/gnome-shell-sass/widgets/_panel.scss +@@ -85,6 +85,11 @@ $panel_transition_duration: 250ms; // same as the overview transition duration + // dimensions of the icon are hardcoded } + .panel-logo-icon { @@ -22,33 +22,35 @@ index a382ce561..3b0d2bf04 100644 + icon-size: 1em; + } + - &:hover { - color: lighten($fg_color, 10%); + &#panelActivities { + -natural-hpadding: $base_padding * 3; } diff --git a/js/ui/panel.js b/js/ui/panel.js -index 16484850a..ede1c2b82 100644 +index 1474886ef..ad11f4ba2 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js -@@ -465,11 +465,18 @@ class ActivitiesButton extends PanelMenu.Button { +@@ -390,11 +390,20 @@ class ActivitiesButton extends PanelMenu.Button { - this.actor.name = 'panelActivities'; + this.name = 'panelActivities'; -+ let box = new St.BoxLayout(); -+ this.actor.add_actor(box); -+ let iconFile = Gio.File.new_for_path('/usr/share/icons/hicolor/scalable/apps/start-here.svg'); -+ this._icon = new St.Icon({ gicon: new Gio.FileIcon({ file: iconFile }), -+ style_class: 'panel-logo-icon' }); -+ box.add_actor(this._icon); ++ const box = new St.BoxLayout(); ++ this.add_child(box); ++ const iconFile = Gio.File.new_for_path('/usr/share/icons/hicolor/scalable/apps/start-here.svg'); ++ this._icon = new St.Icon({ ++ gicon: new Gio.FileIcon({ file: iconFile }), ++ style_class: 'panel-logo-icon', ++ }); ++ box.add_child(this._icon); + /* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */ this._label = new St.Label({ text: _("Activities"), y_align: Clutter.ActorAlign.CENTER }); -- this.actor.add_actor(this._label); -+ box.add_actor(this._label); +- this.add_actor(this._label); ++ box.add_child(this._label); - this.actor.label_actor = this._label; + this.label_actor = this._label; -- -2.21.0 +2.31.1 diff --git a/0001-popupMenu-Handle-keypress-if-numlock-is-enabled.patch b/0001-popupMenu-Handle-keypress-if-numlock-is-enabled.patch deleted file mode 100644 index e6fed236be0f56b75e872e75680caf9184ae63c2..0000000000000000000000000000000000000000 --- a/0001-popupMenu-Handle-keypress-if-numlock-is-enabled.patch +++ /dev/null @@ -1,36 +0,0 @@ -From fb0a9a60ab8f1c0dd96e789969ab9b6e48a9fce4 Mon Sep 17 00:00:00 2001 -From: Olivier Fourdan -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 - diff --git a/0001-screenShield-unblank-when-inserting-smartcard.patch b/0001-screenShield-unblank-when-inserting-smartcard.patch index 3dc3cb98a37fe0fd89a0aa240f4b29f0234579eb..3a1ac18cfd332dae7361b99222203621e43d3032 100644 --- a/0001-screenShield-unblank-when-inserting-smartcard.patch +++ b/0001-screenShield-unblank-when-inserting-smartcard.patch @@ -1,4 +1,4 @@ -From cacce594f07295bb1b9e0685913a287e3cea2453 Mon Sep 17 00:00:00 2001 +From 1e4e9248ef6bcdd95ec3b91c8c8e94c4587a876b Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 3 Jul 2015 13:54:36 -0400 Subject: [PATCH] screenShield: unblank when inserting smartcard @@ -13,21 +13,21 @@ action to get the screen to unblank. 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index a005a206b..cd38f11fc 100644 +index 9a64fc32c..bc1a0fba7 100644 --- a/js/ui/screenShield.js +++ b/js/ui/screenShield.js -@@ -513,8 +513,10 @@ var ScreenShield = class { +@@ -85,8 +85,10 @@ var ScreenShield = class { this._smartcardManager = SmartcardManager.getSmartcardManager(); this._smartcardManager.connect('smartcard-inserted', (manager, token) => { - if (this._isLocked && token.UsedToLogin) + if (this._isLocked && token.UsedToLogin) { + this._wakeUpScreen(); - this._liftShield(true, 0); + this._activateDialog(); + } }); this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager(); -- -2.21.0 +2.31.1 diff --git a/0001-screencast-Stop-recording-when-screen-size-or-resour.patch b/0001-screencast-Stop-recording-when-screen-size-or-resour.patch deleted file mode 100644 index 582ff4eaeb82f64a821b687c7d5981a83e39862c..0000000000000000000000000000000000000000 --- a/0001-screencast-Stop-recording-when-screen-size-or-resour.patch +++ /dev/null @@ -1,253 +0,0 @@ -From 67a4506d4d8a0cbbaca5df4adfc309e54e557aee Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20=C3=85dahl?= -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 - diff --git a/0001-shell-app-Handle-workspace-from-startup-notification.patch b/0001-shell-app-Handle-workspace-from-startup-notification.patch deleted file mode 100644 index e7f0db87b59496edea37029a9536a61597d15d90..0000000000000000000000000000000000000000 --- a/0001-shell-app-Handle-workspace-from-startup-notification.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 391f262aee82ac12fcf99951d6b2df362f734b31 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 - diff --git a/0001-shellDBus-Add-a-DBus-method-to-load-a-single-extensi.patch b/0001-shellDBus-Add-a-DBus-method-to-load-a-single-extensi.patch deleted file mode 100644 index 5649937b1c0e8d66d9024fc074c998c25f08abdf..0000000000000000000000000000000000000000 --- a/0001-shellDBus-Add-a-DBus-method-to-load-a-single-extensi.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 660ebe0125b591355116934ee57b08010e05246c Mon Sep 17 00:00:00 2001 -From: Rui Matos -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 @@ - --> - - -+ -+ -+ -+ -+ -+ -+ - - - -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 - diff --git a/0001-shellEntry-Determine-if-password-entry-from-content-.patch b/0001-shellEntry-Determine-if-password-entry-from-content-.patch deleted file mode 100644 index 4d5bbe1c7ccb8f8e439344a878ec7380e4e156e8..0000000000000000000000000000000000000000 --- a/0001-shellEntry-Determine-if-password-entry-from-content-.patch +++ /dev/null @@ -1,91 +0,0 @@ -From e6cd96a9f6a89f77ca0fab72aff8c56354b59f38 Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0001-shellEntry-Disconnect-handler-on-destroy.patch b/0001-shellEntry-Disconnect-handler-on-destroy.patch deleted file mode 100644 index abf32bd6384a592ba8ed9b15831e6953b160475f..0000000000000000000000000000000000000000 --- a/0001-shellEntry-Disconnect-handler-on-destroy.patch +++ /dev/null @@ -1,36 +0,0 @@ -From fd8c4dc073b121b1093d68472cac3292d2c6605c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 - diff --git a/0001-st-texture-cache-Cancel-pending-requests-on-icon-the.patch b/0001-st-texture-cache-Cancel-pending-requests-on-icon-the.patch deleted file mode 100644 index a6f6fdc81d9f2bb2bba3347f337f52626db66888..0000000000000000000000000000000000000000 --- a/0001-st-texture-cache-Cancel-pending-requests-on-icon-the.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 1bf28eea64056846547ec33d783c7f2e0dad78a4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 - diff --git a/0003-st-texture-cache-purge-on-resume.patch b/0001-st-texture-cache-purge-on-resume.patch similarity index 83% rename from 0003-st-texture-cache-purge-on-resume.patch rename to 0001-st-texture-cache-purge-on-resume.patch index 41c288d4f8e12798d9315a3c1e73a7499599eb68..1a32fc77c135b96bd4159772d54509127d873b3e 100644 --- a/0003-st-texture-cache-purge-on-resume.patch +++ b/0001-st-texture-cache-purge-on-resume.patch @@ -1,7 +1,7 @@ -From 2ebeda3385fb679df4bc13ba4b80bdeba5e2ad13 Mon Sep 17 00:00:00 2001 +From 483f0340bb64767bd8d6d95788058270dfdb5def Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 15 Jan 2019 12:54:32 -0500 -Subject: [PATCH 3/4] st-texture-cache: purge on resume +Subject: [PATCH] st-texture-cache: purge on resume With the proprietary nvidia driver, textures get garbled on suspend, so the texture cache needs to evict all textures in that situation. @@ -12,10 +12,10 @@ so the texture cache needs to evict all textures in that situation. 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/js/ui/main.js b/js/ui/main.js -index 061303cf3..8d1755cf1 100644 +index 979fcefa5..dbf3a32d3 100644 --- a/js/ui/main.js +++ b/js/ui/main.js -@@ -200,7 +200,11 @@ function _initializeUI() { +@@ -249,7 +249,11 @@ function _initializeUI() { return true; }); @@ -29,10 +29,10 @@ index 061303cf3..8d1755cf1 100644 // Provide the bus object for gnome-session to // initiate logouts. diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c -index cbe3afaba..40a11dd6d 100644 +index b7b547a78..583c3f7d2 100644 --- a/src/st/st-texture-cache.c +++ b/src/st/st-texture-cache.c -@@ -113,6 +113,16 @@ st_texture_cache_class_init (StTextureCacheClass *klass) +@@ -130,6 +130,16 @@ st_texture_cache_class_init (StTextureCacheClass *klass) G_TYPE_NONE, 1, G_TYPE_FILE); } @@ -50,7 +50,7 @@ index cbe3afaba..40a11dd6d 100644 static void st_texture_cache_evict_icons (StTextureCache *cache) diff --git a/src/st/st-texture-cache.h b/src/st/st-texture-cache.h -index 11d1c4e64..9079d1fda 100644 +index 55d84952d..948915c30 100644 --- a/src/st/st-texture-cache.h +++ b/src/st/st-texture-cache.h @@ -53,6 +53,7 @@ typedef enum { @@ -62,5 +62,5 @@ index 11d1c4e64..9079d1fda 100644 ClutterActor * st_texture_cache_load_sliced_image (StTextureCache *cache, -- -2.21.0 +2.31.1 diff --git a/0001-status-network-Use-wwan-settings-panel-for-GSM-LTE-M.patch b/0001-status-network-Use-wwan-settings-panel-for-GSM-LTE-M.patch new file mode 100644 index 0000000000000000000000000000000000000000..b910c436d3f5e63e005814961df9e2d693d2a5f6 --- /dev/null +++ b/0001-status-network-Use-wwan-settings-panel-for-GSM-LTE-M.patch @@ -0,0 +1,58 @@ +From 7e94d682985ac4ff422da73b5878f4f005eff67b Mon Sep 17 00:00:00 2001 +From: Mohammed Sadiq +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: +--- + 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 + diff --git a/0001-status-volume-Hide-sliders-initially.patch b/0001-status-volume-Hide-sliders-initially.patch new file mode 100644 index 0000000000000000000000000000000000000000..1600ab92a524df202d99011056bd4934d232df9c --- /dev/null +++ b/0001-status-volume-Hide-sliders-initially.patch @@ -0,0 +1,30 @@ +From b212b973175be1cbefa1da2c5ed4f58fae032c73 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 11 May 2022 02:34:21 +0200 +Subject: [PATCH] status/volume: Hide sliders initially + +We update the visibility on state or stream changes, but those +changes may never happen if pipewire-pulse/pulseaudio isn't +available (for example when running as root). + +Hiding the sliders is preferable in that case to showing non-working +controls. +--- + js/ui/status/volume.js | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/js/ui/status/volume.js b/js/ui/status/volume.js +index 7164e1054..f623ee680 100644 +--- a/js/ui/status/volume.js ++++ b/js/ui/status/volume.js +@@ -34,6 +34,7 @@ var StreamSlider = class { + this._control = control; + + this.item = new PopupMenu.PopupBaseMenuItem({ activate: false }); ++ this.item.hide(); + + this._inDrag = false; + this._notifyVolumeChangeId = 0; +-- +2.35.1 + diff --git a/0001-theme-Update-window-preview-style.patch b/0001-theme-Update-window-preview-style.patch deleted file mode 100644 index 2871e6064cfea1cc08215d79e2fb0f5f848ff392..0000000000000000000000000000000000000000 --- a/0001-theme-Update-window-preview-style.patch +++ /dev/null @@ -1,76 +0,0 @@ -From c68fd3c94c6debdbf11020940c5a6aaee8bc230d Mon Sep 17 00:00:00 2001 -From: Feichtmeier -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 - diff --git a/0001-welcomeDialog-Adapt-dialog-title.patch b/0001-welcomeDialog-Adapt-dialog-title.patch new file mode 100644 index 0000000000000000000000000000000000000000..dd812c74c85f5c91c47a799f12d2c2b2d153db14 --- /dev/null +++ b/0001-welcomeDialog-Adapt-dialog-title.patch @@ -0,0 +1,38 @@ +From 79049292451b9bb23ad92c572a438585ca37246b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +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 + diff --git a/0001-windowMenu-Bring-back-workspaces-submenu-for-static-.patch b/0001-windowMenu-Bring-back-workspaces-submenu-for-static-.patch index 810a27a7006fc4f32da49d70dc983d5d7568c6d5..980f60775422619cb15c6ff783c835052adc5054 100644 --- a/0001-windowMenu-Bring-back-workspaces-submenu-for-static-.patch +++ b/0001-windowMenu-Bring-back-workspaces-submenu-for-static-.patch @@ -1,4 +1,4 @@ -From 20640a92f98e2145b9b6581209c978e9f6f78801 Mon Sep 17 00:00:00 2001 +From 34a7bfdade939e39c2a01cc1b0737a7bdccddd5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 14 Mar 2017 17:04:36 +0100 Subject: [PATCH] windowMenu: Bring back workspaces submenu for static @@ -13,10 +13,10 @@ are used. 1 file changed, 17 insertions(+) diff --git a/js/ui/windowMenu.js b/js/ui/windowMenu.js -index 628f145ea..f8eb4398c 100644 +index bb6a8df7b..3449f759d 100644 --- a/js/ui/windowMenu.js +++ b/js/ui/windowMenu.js -@@ -115,6 +115,23 @@ var WindowMenu = class extends PopupMenu.PopupMenu { +@@ -116,6 +116,23 @@ var WindowMenu = class extends PopupMenu.PopupMenu { window.change_workspace(workspace.get_neighbor(dir)); }); } @@ -41,5 +41,5 @@ index 628f145ea..f8eb4398c 100644 } -- -2.21.0 +2.31.1 diff --git a/0001-workspace-Pass-device-to-startDrag.patch b/0001-workspace-Pass-device-to-startDrag.patch deleted file mode 100644 index 7b4afba59707988d83cc36b6ffbf33c3eac9da63..0000000000000000000000000000000000000000 --- a/0001-workspace-Pass-device-to-startDrag.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 9115f6e7962b97c3ee2fbef7b195b7116e62c070 Mon Sep 17 00:00:00 2001 -From: Carlos Garnacho -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 - diff --git a/0001-workspacesView-Work-around-spurious-allocation-chang.patch b/0001-workspacesView-Work-around-spurious-allocation-chang.patch deleted file mode 100644 index f51e8e27c2a0e3ed64a36f230ae154dcefbd8373..0000000000000000000000000000000000000000 --- a/0001-workspacesView-Work-around-spurious-allocation-chang.patch +++ /dev/null @@ -1,37 +0,0 @@ -From b69b404118852f7955f60d1814f5e19ad61ce449 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 - diff --git a/0002-background-rebuild-background-not-just-animation-on-.patch b/0002-background-rebuild-background-not-just-animation-on-.patch deleted file mode 100644 index de5f77ab8464ff460f86f089dcca02fd99fccb71..0000000000000000000000000000000000000000 --- a/0002-background-rebuild-background-not-just-animation-on-.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 1a546d4df199f498b838efdccf081ada8ed1960b Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 15 Jan 2019 12:52:49 -0500 -Subject: [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 06e038816..75b76a57e 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 = this._settings.connect('changed', () => { --- -2.21.0 - diff --git a/0002-environment-Fix-date-conversion.patch b/0002-environment-Fix-date-conversion.patch deleted file mode 100644 index 2f6b5bdd3b8bd7fb65a0164ea1ee0aa51023944b..0000000000000000000000000000000000000000 --- a/0002-environment-Fix-date-conversion.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 189add05c07fe9d9bed6c1399b30e51a4a934bd3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 - diff --git a/0002-extensionSystem-Get-rid-of-_enabled-boolean-optimiza.patch b/0002-extensionSystem-Get-rid-of-_enabled-boolean-optimiza.patch deleted file mode 100644 index 5dba07a99b38d461dbf6633d123963f30b60e512..0000000000000000000000000000000000000000 --- a/0002-extensionSystem-Get-rid-of-_enabled-boolean-optimiza.patch +++ /dev/null @@ -1,237 +0,0 @@ -From b70cf463e08bff43b242b851fc7c79244f54e76b Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0002-gdmUtil-enable-support-for-GDM-s-ChoiceList-PAM-exte.patch b/0002-gdmUtil-enable-support-for-GDM-s-ChoiceList-PAM-exte.patch deleted file mode 100644 index b396e1ca106e6c67fa4cc71c5bd218d00b1c8066..0000000000000000000000000000000000000000 --- a/0002-gdmUtil-enable-support-for-GDM-s-ChoiceList-PAM-exte.patch +++ /dev/null @@ -1,267 +0,0 @@ -From c3ab03f8721ea96df6ac91c0393ed13ba750ab7e Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0002-shellEntry-Give-password-menu-item-text-when-it-s-cr.patch b/0002-shellEntry-Give-password-menu-item-text-when-it-s-cr.patch deleted file mode 100644 index 55b3c6fe1599e29fdeb1ae3909b4dcbb8f0c023d..0000000000000000000000000000000000000000 --- a/0002-shellEntry-Give-password-menu-item-text-when-it-s-cr.patch +++ /dev/null @@ -1,92 +0,0 @@ -From de7df6c7248c39d7cce1c70485df72a398da92a3 Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0003-extensionSystem-Allow-extensions-to-run-on-the-login.patch b/0003-extensionSystem-Allow-extensions-to-run-on-the-login.patch deleted file mode 100644 index c2dcedb169244bef0d83c55526f4bc98b6c58b68..0000000000000000000000000000000000000000 --- a/0003-extensionSystem-Allow-extensions-to-run-on-the-login.patch +++ /dev/null @@ -1,393 +0,0 @@ -From 7300ae2eac743fa06f40f6459ac8fbf739ab28ea Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0003-shell-app-system-Monitor-for-icon-theme-changes.patch b/0003-shell-app-system-Monitor-for-icon-theme-changes.patch deleted file mode 100644 index 89a3a80a124ad6a22c8427a3be15dab38a1d57d1..0000000000000000000000000000000000000000 --- a/0003-shell-app-system-Monitor-for-icon-theme-changes.patch +++ /dev/null @@ -1,152 +0,0 @@ -From c9277326055c96185a80b68d4228eee360bb0e7c Mon Sep 17 00:00:00 2001 -From: Georges Basile Stavracas Neto -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 - diff --git a/0003-shellEntry-Handle-password-item-from-dedication-func.patch b/0003-shellEntry-Handle-password-item-from-dedication-func.patch deleted file mode 100644 index 46afc47adc7e93c380017db24f118bcf1ac459a5..0000000000000000000000000000000000000000 --- a/0003-shellEntry-Handle-password-item-from-dedication-func.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 39cf97176e2a92506081ee151ea546e2c6cf213a Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0004-background-refresh-background-on-gl-video-memory-pur.patch b/0004-background-refresh-background-on-gl-video-memory-pur.patch deleted file mode 100644 index 0f81f4797777f20267c6e96008a22148e87ffc9c..0000000000000000000000000000000000000000 --- a/0004-background-refresh-background-on-gl-video-memory-pur.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 055bc14c70af66fe1893dcd4c42c65662ae1f9d0 Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0004-global-force-fsync-to-worker-thread-when-saving-stat.patch b/0004-global-force-fsync-to-worker-thread-when-saving-stat.patch deleted file mode 100644 index 22713112d670d4a332fdd9549c759b13a391e956..0000000000000000000000000000000000000000 --- a/0004-global-force-fsync-to-worker-thread-when-saving-stat.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 2a4f33df723d4b9ce68e5948b568a89675d37411 Mon Sep 17 00:00:00 2001 -From: Christian Hergert -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 - diff --git a/0004-sessionMode-Allow-extensions-at-the-login-and-unlock.patch b/0004-sessionMode-Allow-extensions-at-the-login-and-unlock.patch deleted file mode 100644 index f19fecd624568a7de62baf91e80f20f278932af7..0000000000000000000000000000000000000000 --- a/0004-sessionMode-Allow-extensions-at-the-login-and-unlock.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 5fad989ca773f9e0ff6fdbeb0cb7c9cb70cc6148 Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0004-shellEntry-Support-lockdown-of-Show-Text-menu-in-pas.patch b/0004-shellEntry-Support-lockdown-of-Show-Text-menu-in-pas.patch deleted file mode 100644 index 8d8a7d7fb09af9a59a60f25cfc32fe97a019e134..0000000000000000000000000000000000000000 --- a/0004-shellEntry-Support-lockdown-of-Show-Text-menu-in-pas.patch +++ /dev/null @@ -1,116 +0,0 @@ -From ee64cd773bdeef845d02dc84063f926d77090dec Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/0005-app-cache-add-ShellAppCache-for-GAppInfo-caching.patch b/0005-app-cache-add-ShellAppCache-for-GAppInfo-caching.patch deleted file mode 100644 index 1f19cb0d5a3bddcac506d7415ab3d4eba389fff8..0000000000000000000000000000000000000000 --- a/0005-app-cache-add-ShellAppCache-for-GAppInfo-caching.patch +++ /dev/null @@ -1,674 +0,0 @@ -From a3fc35a2b452855d004549afbec57d1b4f36c917 Mon Sep 17 00:00:00 2001 -From: Christian Hergert -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 -+#include -+ -+#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 - #include - -+#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 - #include - -+#include "shell-app-cache-private.h" - #include "shell-util.h" - #include - #include -@@ -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 - diff --git a/0005-shellEntry-Only-mask-text-in-password-entries.patch b/0005-shellEntry-Only-mask-text-in-password-entries.patch deleted file mode 100644 index a87a3270d7aaad63d103646f7e2513aa45f52235..0000000000000000000000000000000000000000 --- a/0005-shellEntry-Only-mask-text-in-password-entries.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 7a264550c5f3a98b1786b1a75cff01cde1d084eb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 - diff --git a/0006-js-Always-use-AppSystem-to-lookup-apps.patch b/0006-js-Always-use-AppSystem-to-lookup-apps.patch deleted file mode 100644 index 73080e8b4f415e77b806b3b58966a54ba847701b..0000000000000000000000000000000000000000 --- a/0006-js-Always-use-AppSystem-to-lookup-apps.patch +++ /dev/null @@ -1,66 +0,0 @@ -From a0df79f8de4c13c36ed3b22cfdbb78e324424ef1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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 - diff --git a/add-power-profiles-menu.patch b/add-power-profiles-menu.patch new file mode 100644 index 0000000000000000000000000000000000000000..289a80bbfb7b5277a7d569c8c3342e95be33e8b8 --- /dev/null +++ b/add-power-profiles-menu.patch @@ -0,0 +1,333 @@ +From 2103c5fcf994bb6aebd978553b338436e85fa7ed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +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: +--- + .../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 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +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 @@ + + + ++ net.hadess.PowerProfiles.xml + net.hadess.SensorProxy.xml + net.reactivated.Fprint.Device.xml + net.reactivated.Fprint.Manager.xml +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 @@ + ui/status/nightLight.js + ui/status/network.js + ui/status/power.js ++ ui/status/powerProfiles.js + ui/status/rfkill.js + ui/status/volume.js + ui/status/bluetooth.js +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?= +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: +--- + 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 + diff --git a/allow-timed-login-with-no-user-list.patch b/allow-timed-login-with-no-user-list.patch deleted file mode 100644 index 040e507b2fd6d925a5f042cb138cd7990bb0bbb1..0000000000000000000000000000000000000000 --- a/allow-timed-login-with-no-user-list.patch +++ /dev/null @@ -1,159 +0,0 @@ -From 3252f05b8745a5d3118986474793fe3ecc2b041c Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 - diff --git a/caps-lock-warning.patch b/caps-lock-warning.patch deleted file mode 100644 index d3c2daa12e104d1515e6d4da16f426c6d4ac3f14..0000000000000000000000000000000000000000 --- a/caps-lock-warning.patch +++ /dev/null @@ -1,488 +0,0 @@ -From 7b514e637837e00372e20fa52f841e993966b734 Mon Sep 17 00:00:00 2001 -From: Umang Jain -Date: Fri, 13 Dec 2019 13:36:14 +0530 -Subject: [PATCH 1/7] shellEntry: Add CapsLockWarning class - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/619 ---- - data/theme/gnome-shell-sass/_common.scss | 5 +++ - js/ui/shellEntry.js | 39 +++++++++++++++++++++++- - 2 files changed, 43 insertions(+), 1 deletion(-) - -diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss -index b1eeb0ce97..19a736ab7d 100644 ---- a/data/theme/gnome-shell-sass/_common.scss -+++ b/data/theme/gnome-shell-sass/_common.scss -@@ -391,6 +391,11 @@ StScrollBar { - padding-bottom: 8px; - } - -+ .prompt-dialog-caps-lock-warning { -+ @extend .prompt-dialog-error-label; -+ padding-left: 6.2em; -+ } -+ - .prompt-dialog-info-label { - font-size: 10pt; - padding-bottom: 8px; -diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js -index 79f1aad3e7..c1738c4064 100644 ---- a/js/ui/shellEntry.js -+++ b/js/ui/shellEntry.js -@@ -1,6 +1,6 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - --const { Clutter, Shell, St } = imports.gi; -+const { Clutter, GObject, Pango, Shell, St } = imports.gi; - - const BoxPointer = imports.ui.boxpointer; - const Main = imports.ui.main; -@@ -170,3 +170,40 @@ function addContextMenu(entry, params) { - entry._menuManager = null; - }); - } -+ -+var CapsLockWarning = GObject.registerClass( -+class CapsLockWarning extends St.Label { -+ _init(params) { -+ let defaultParams = { style_class: 'prompt-dialog-error-label' }; -+ super._init(Object.assign(defaultParams, params)); -+ -+ this.text = _('Caps lock is on.'); -+ -+ this._keymap = Clutter.get_default_backend().get_keymap(); -+ -+ this.connect('notify::mapped', () => { -+ if (this.is_mapped()) { -+ this.stateChangedId = this._keymap.connect('state-changed', -+ this._updateCapsLockWarningOpacity.bind(this)); -+ } else { -+ this._keymap.disconnect(this.stateChangedId); -+ this.stateChangedId = 0; -+ } -+ -+ this._updateCapsLockWarningOpacity(); -+ }); -+ -+ this.connect('destroy', () => { -+ if (this.stateChangedId > 0) -+ this._keymap.disconnect(this.stateChangedId); -+ }); -+ -+ this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; -+ this.clutter_text.line_wrap = true; -+ } -+ -+ _updateCapsLockWarningOpacity() { -+ let capsLockOn = this._keymap.get_caps_lock_state(); -+ this.opacity = capsLockOn ? 255 : 0; -+ } -+}); --- -2.21.1 - - -From aa4938f261454f85c782e59e40d4e5a9e1a01dbc Mon Sep 17 00:00:00 2001 -From: Umang Jain -Date: Wed, 18 Dec 2019 01:33:45 +0530 -Subject: [PATCH 2/7] js: Add caps-lock Warning to the dialogs - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/619 ---- - js/gdm/authPrompt.js | 4 ++++ - js/ui/components/keyring.js | 6 ++++++ - js/ui/components/networkAgent.js | 8 ++++++++ - js/ui/components/polkitAgent.js | 2 ++ - js/ui/shellMountOperation.js | 3 +++ - 5 files changed, 23 insertions(+) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index 71069e93b8..3ce9fd0d01 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -113,6 +113,9 @@ var AuthPrompt = class { - - this._entry.grab_key_focus(); - -+ this._capsLockWarningLabel = new ShellEntry.CapsLockWarning(); -+ this.actor.add_child(this._capsLockWarningLabel); -+ - this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator', - scale_x: 0 }); - -@@ -432,6 +435,7 @@ var AuthPrompt = class { - setPasswordChar(passwordChar) { - this._entry.clutter_text.set_password_char(passwordChar); - this._entry.menu.isPassword = passwordChar != ''; -+ this._capsLockWarningLabel.visible = passwordChar !== ''; - } - - setQuestion(question) { -diff --git a/js/ui/components/keyring.js b/js/ui/components/keyring.js -index 0d9f1e4663..3512fb63b1 100644 ---- a/js/ui/components/keyring.js -+++ b/js/ui/components/keyring.js -@@ -128,6 +128,12 @@ var KeyringDialog = class extends ModalDialog.ModalDialog { - this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null); - this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null); - -+ if (this._passwordEntry || this._confirmEntry) { -+ this._capsLockWarningLabel = new ShellEntry.CapsLockWarning(); -+ layout.attach(this._capsLockWarningLabel, 1, row, 1, 1); -+ row++; -+ } -+ - if (this.prompt.choice_visible) { - let choice = new CheckBox.CheckBox(); - this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE); -diff --git a/js/ui/components/networkAgent.js b/js/ui/components/networkAgent.js -index f871c732d9..32d40fb2b9 100644 ---- a/js/ui/components/networkAgent.js -+++ b/js/ui/components/networkAgent.js -@@ -95,6 +95,14 @@ var NetworkSecretDialog = class extends ModalDialog.ModalDialog { - secret.entry.clutter_text.set_password_char('\u25cf'); - } - -+ if (this._content.secrets.some(s => s.password)) { -+ this._capsLockWarningLabel = new ShellEntry.CapsLockWarning(); -+ if (rtl) -+ layout.attach(this._capsLockWarningLabel, 0, pos, 1, 1); -+ else -+ layout.attach(this._capsLockWarningLabel, 1, pos, 1, 1); -+ } -+ - contentBox.messageBox.add(secretTable); - - if (flags & NM.SecretAgentGetSecretsFlags.WPS_PBC_ACTIVE) { -diff --git a/js/ui/components/polkitAgent.js b/js/ui/components/polkitAgent.js -index 21feb40903..734a217335 100644 ---- a/js/ui/components/polkitAgent.js -+++ b/js/ui/components/polkitAgent.js -@@ -108,6 +108,8 @@ var AuthenticationDialog = class extends ModalDialog.ModalDialog { - - this.setInitialKeyFocus(this._passwordEntry); - this._passwordBox.hide(); -+ this._capsLockWarningLabel = new ShellEntry.CapsLockWarning({ style_class: 'prompt-dialog-caps-lock-warning' }); -+ content.messageBox.add(this._capsLockWarningLabel); - - this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' }); - this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; -diff --git a/js/ui/shellMountOperation.js b/js/ui/shellMountOperation.js -index f976f400f4..3a2377ddaf 100644 ---- a/js/ui/shellMountOperation.js -+++ b/js/ui/shellMountOperation.js -@@ -305,6 +305,9 @@ var ShellMountPasswordDialog = class extends ModalDialog.ModalDialog { - this._passwordBox.add(this._passwordEntry, {expand: true }); - this.setInitialKeyFocus(this._passwordEntry); - -+ this._capsLockWarningLabel = new ShellEntry.CapsLockWarning(); -+ content.messageBox.add(this._capsLockWarningLabel); -+ - this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label', - text: _("Sorry, that didn’t work. Please try again.") }); - this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; --- -2.21.1 - - -From 016cbd971711665844d40ec678d2779c160f791b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 23 Jan 2020 22:37:06 +0100 -Subject: [PATCH 3/7] shellEntry: Make signal id variable private - -Signal connection IDs should be private variables, so make this one -private. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/952 ---- - js/ui/shellEntry.js | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js -index c1738c4064..cd7c9a6c88 100644 ---- a/js/ui/shellEntry.js -+++ b/js/ui/shellEntry.js -@@ -183,19 +183,19 @@ class CapsLockWarning extends St.Label { - - this.connect('notify::mapped', () => { - if (this.is_mapped()) { -- this.stateChangedId = this._keymap.connect('state-changed', -+ this._stateChangedId = this._keymap.connect('state-changed', - this._updateCapsLockWarningOpacity.bind(this)); - } else { -- this._keymap.disconnect(this.stateChangedId); -- this.stateChangedId = 0; -+ this._keymap.disconnect(this._stateChangedId); -+ this._stateChangedId = 0; - } - - this._updateCapsLockWarningOpacity(); - }); - - this.connect('destroy', () => { -- if (this.stateChangedId > 0) -- this._keymap.disconnect(this.stateChangedId); -+ if (this._stateChangedId > 0) -+ this._keymap.disconnect(this._stateChangedId); - }); - - this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; --- -2.21.1 - - -From ba65f9066d72731e345a5aced61f35d39c1c1376 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 23 Jan 2020 23:26:45 +0100 -Subject: [PATCH 4/7] theme: Move caps-lock warning to entry widget stylesheet - -The caps-lock warning is more related to entries than dialogs and is -also used in gdm, which is not realated to dialogs at all. Rename the -css class to caps-lock-warning-label and move it to the entry -stylesheet. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/952 ---- - data/theme/gnome-shell-sass/_common.scss | 12 +++++++----- - js/ui/shellEntry.js | 2 +- - 2 files changed, 8 insertions(+), 6 deletions(-) - -diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss -index 19a736ab7d..4661533de2 100644 ---- a/data/theme/gnome-shell-sass/_common.scss -+++ b/data/theme/gnome-shell-sass/_common.scss -@@ -94,6 +94,13 @@ StEntry { - } - } - -+.caps-lock-warning-label { -+ padding-left: 6.2em; -+ @include fontsize($font-size - 1); -+ color: $warning_color; -+} -+ -+ - - /* Scrollbars */ - -@@ -391,11 +398,6 @@ StScrollBar { - padding-bottom: 8px; - } - -- .prompt-dialog-caps-lock-warning { -- @extend .prompt-dialog-error-label; -- padding-left: 6.2em; -- } -- - .prompt-dialog-info-label { - font-size: 10pt; - padding-bottom: 8px; -diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js -index cd7c9a6c88..46eba88d54 100644 ---- a/js/ui/shellEntry.js -+++ b/js/ui/shellEntry.js -@@ -174,7 +174,7 @@ function addContextMenu(entry, params) { - var CapsLockWarning = GObject.registerClass( - class CapsLockWarning extends St.Label { - _init(params) { -- let defaultParams = { style_class: 'prompt-dialog-error-label' }; -+ let defaultParams = { style_class: 'caps-lock-warning-label' }; - super._init(Object.assign(defaultParams, params)); - - this.text = _('Caps lock is on.'); --- -2.21.1 - - -From afd764c82febe21aec70bdfc19d256f3401530e1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 23 Jan 2020 22:36:09 +0100 -Subject: [PATCH 5/7] shellEntry: Hide caps lock warning and use animation to - show it - -Since the caps-lock warning adds a lot of spacing to dialogs and the -lock screen, hide it by default and only show it when necessary. To make -the transition smooth instead of just showing the label, animate it in -using the height and opacity. - -Also add some bottom padding to the label so we can show or hide that -padding, too. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/952 ---- - data/theme/gnome-shell-sass/_common.scss | 1 + - js/ui/shellEntry.js | 33 ++++++++++++++++++------ - 2 files changed, 26 insertions(+), 8 deletions(-) - -diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss -index 4661533de2..9e0751c8c5 100644 ---- a/data/theme/gnome-shell-sass/_common.scss -+++ b/data/theme/gnome-shell-sass/_common.scss -@@ -95,6 +95,7 @@ StEntry { - } - - .caps-lock-warning-label { -+ padding-bottom: 8px; - padding-left: 6.2em; - @include fontsize($font-size - 1); - color: $warning_color; -diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js -index 46eba88d54..fc8ee37a9a 100644 ---- a/js/ui/shellEntry.js -+++ b/js/ui/shellEntry.js -@@ -6,6 +6,7 @@ const BoxPointer = imports.ui.boxpointer; - const Main = imports.ui.main; - const Params = imports.misc.params; - const PopupMenu = imports.ui.popupMenu; -+const Tweener = imports.ui.tweener; - - var EntryMenu = class extends PopupMenu.PopupMenu { - constructor(entry) { -@@ -179,31 +180,47 @@ class CapsLockWarning extends St.Label { - - this.text = _('Caps lock is on.'); - -+ this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; -+ this.clutter_text.line_wrap = true; -+ - this._keymap = Clutter.get_default_backend().get_keymap(); - - this.connect('notify::mapped', () => { - if (this.is_mapped()) { - this._stateChangedId = this._keymap.connect('state-changed', -- this._updateCapsLockWarningOpacity.bind(this)); -+ () => this._sync(true)); - } else { - this._keymap.disconnect(this._stateChangedId); - this._stateChangedId = 0; - } - -- this._updateCapsLockWarningOpacity(); -+ this._sync(false); - }); - - this.connect('destroy', () => { -- if (this._stateChangedId > 0) -+ if (this._stateChangedId) - this._keymap.disconnect(this._stateChangedId); - }); -- -- this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; -- this.clutter_text.line_wrap = true; - } - -- _updateCapsLockWarningOpacity() { -+ _sync(animate) { - let capsLockOn = this._keymap.get_caps_lock_state(); -- this.opacity = capsLockOn ? 255 : 0; -+ -+ Tweener.removeTweens(this); -+ -+ this.natural_height_set = false; -+ let [, height] = this.get_preferred_height(-1); -+ this.natural_height_set = true; -+ -+ Tweener.addTween(this, { -+ height: capsLockOn ? height : 0, -+ opacity: capsLockOn ? 255 : 0, -+ time: animate ? 0.2 : 0, -+ transition: 'easeOutQuad', -+ onComplete: () => { -+ if (capsLockOn) -+ this.height = -1; -+ }, -+ }); - } - }); --- -2.21.1 - - -From 1ef3dafb51da380c54635d0565dc098e40bbb3e1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 29 Jan 2020 17:48:57 +0100 -Subject: [PATCH 6/7] js: Initialize some properties - -Otherwise those can result in the (harmless) "reference to undefined -property" warnings. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/970 ---- - js/ui/overview.js | 1 + - js/ui/shellEntry.js | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/js/ui/overview.js b/js/ui/overview.js -index dc6ad1821b..5bad4cbd62 100644 ---- a/js/ui/overview.js -+++ b/js/ui/overview.js -@@ -80,6 +80,7 @@ var Overview = class { - constructor() { - this._overviewCreated = false; - this._initCalled = false; -+ this._visible = false; - - Main.sessionMode.connect('updated', this._sessionUpdated.bind(this)); - this._sessionUpdated(); -diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js -index fc8ee37a9a..55267e7c87 100644 ---- a/js/ui/shellEntry.js -+++ b/js/ui/shellEntry.js -@@ -184,6 +184,7 @@ class CapsLockWarning extends St.Label { - this.clutter_text.line_wrap = true; - - this._keymap = Clutter.get_default_backend().get_keymap(); -+ this._stateChangedId = 0; - - this.connect('notify::mapped', () => { - if (this.is_mapped()) { --- -2.21.1 - - -From 273f7adb43cfee907342d017e1454ea90d42d262 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 21 Feb 2020 19:38:53 +0100 -Subject: [PATCH 7/7] shellEntry: Restore natural-height-set instead of forcing - it - -If we are transitioning the label from 0 to its natural height, we -must set natural-height-set again after querying the preferred height, -otherwise Clutter would skip the transition. - -However when transitioning in the opposite direction, setting the -property to true can go horribly wrong: -If the actor hasn't been allocated before, it will store a fixed -natural height of 0. But as there is no fixed min-height, we can -end up with min-height > natural-height, which is a fatal error. - -(This isn't an issue when *actually* setting a fixed height, as -that will set both natural and minimum height) - -So instead of always setting natural-height-set to true, restore -its previous value to fix the issue. - -https://gitlab.gnome.org/GNOME/gnome-shell/issues/2255 ---- - js/ui/shellEntry.js | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js -index 55267e7c87..4a30b22f7a 100644 ---- a/js/ui/shellEntry.js -+++ b/js/ui/shellEntry.js -@@ -209,9 +209,10 @@ class CapsLockWarning extends St.Label { - - Tweener.removeTweens(this); - -+ const naturalHeightSet = this.natural_height_set; - this.natural_height_set = false; - let [, height] = this.get_preferred_height(-1); -- this.natural_height_set = true; -+ this.natural_height_set = naturalHeightSet; - - Tweener.addTween(this, { - height: capsLockOn ? height : 0, --- -2.21.1 - diff --git a/disable-unlock-entry-until-question.patch b/disable-unlock-entry-until-question.patch index d238ae81955ba2c5ce3746f283a9cdfb64dd0113..20980c5de58ec8c99d2e817cfa5f04672909c76d 100644 --- a/disable-unlock-entry-until-question.patch +++ b/disable-unlock-entry-until-question.patch @@ -1,4 +1,4 @@ -From a57132816ac7bd93d6875fee0a6c5b273177ac8d Mon Sep 17 00:00:00 2001 +From 6739f213965c2b6a41c21b446095f393f9d86e43 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 30 Sep 2015 12:51:24 -0400 Subject: [PATCH 1/3] authPrompt: don't fade out auth messages if user types @@ -12,50 +12,59 @@ front, before a password is asked. 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index d7f53a92e..d421a8856 100644 +index 4844b9ee0..149e5ad4a 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js -@@ -169,7 +169,7 @@ var AuthPrompt = class { - this._updateNextButtonSensitivity(this._entry.text.length > 0); +@@ -179,7 +179,7 @@ var AuthPrompt = GObject.registerClass({ - this._entry.clutter_text.connect('text-changed', () => { -- if (!this._userVerifier.hasPendingMessages) -+ if (!this._userVerifier.hasPendingMessages && this._queryingService && !this._preemptiveAnswer) - this._fadeOutMessage(); + [this._textEntry, this._passwordEntry].forEach(entry => { + entry.clutter_text.connect('text-changed', () => { +- if (!this._userVerifier.hasPendingMessages) ++ if (!this._userVerifier.hasPendingMessages && this._queryingService && !this._preemptiveAnswer) + this._fadeOutMessage(); + }); - this._updateNextButtonSensitivity(this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING); -- -2.21.0 +2.31.1 -From 50af703ea95f2b73733c38e66c9c251663a51744 Mon Sep 17 00:00:00 2001 +From 2b84c3d611120ae2f60386d5c637b84d1958398d Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 30 Sep 2015 14:36:33 -0400 Subject: [PATCH 2/3] authPrompt: don't spin unless answering question --- - js/gdm/authPrompt.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) + js/gdm/authPrompt.js | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index d421a8856..62c5bd078 100644 +index 149e5ad4a..c5643d046 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js -@@ -60,8 +60,8 @@ var AuthPrompt = class { +@@ -243,13 +243,14 @@ var AuthPrompt = GObject.registerClass({ + this.verificationStatus = AuthPromptStatus.VERIFICATION_IN_PROGRESS; + this.updateSensitivity(false); - this.connect('next', () => { - this.updateSensitivity(false); -- this.startSpinning(); - if (this._queryingService) { -+ this.startSpinning(); - this._userVerifier.answerQuery(this._queryingService, this._entry.text); - } else { - this._preemptiveAnswer = this._entry.text; +- if (shouldSpin) +- this.startSpinning(); ++ if (this._queryingService) { ++ if (shouldSpin) ++ this.startSpinning(); + +- if (this._queryingService) + this._userVerifier.answerQuery(this._queryingService, this._entry.text); +- else ++ } else { + this._preemptiveAnswer = this._entry.text; ++ } + + this.emit('next'); + } -- -2.21.0 +2.31.1 -From b89be880936ad9dd145eb43890ac72d03c37785d Mon Sep 17 00:00:00 2001 +From 56360c872e01b0554b4d8b53dddba5407d4e889b Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 5 Oct 2015 15:26:18 -0400 Subject: [PATCH 3/3] authPrompt: stop accepting preemptive answer if user @@ -69,43 +78,32 @@ Typing ahead the password is just a convenience for users who don't want to manually lift the shift before typing their passwords, after all. --- - js/gdm/authPrompt.js | 37 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 37 insertions(+) + js/gdm/authPrompt.js | 37 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index 62c5bd078..27eb31a89 100644 +index c5643d046..84c608b2f 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js -@@ -6,6 +6,7 @@ const Signals = imports.signals; +@@ -1,7 +1,7 @@ + // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + /* exported AuthPrompt */ + +-const { Clutter, GLib, GObject, Pango, Shell, St } = imports.gi; ++const { Clutter, GLib, GObject, Meta, Pango, Shell, St } = imports.gi; + const Animation = imports.ui.animation; const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; -+const Meta = imports.gi.Meta; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; -@@ -41,6 +42,8 @@ var AuthPrompt = class { - this._gdmClient = gdmClient; - this._mode = mode; +@@ -63,6 +63,8 @@ var AuthPrompt = GObject.registerClass({ + this._defaultButtonWellActor = null; + this._cancelledRetries = 0; + this._idleMonitor = Meta.IdleMonitor.get_core(); + let reauthenticationOnly; if (this._mode == AuthPromptMode.UNLOCK_ONLY) reauthenticationOnly = true; -@@ -65,6 +68,11 @@ var AuthPrompt = class { - this._userVerifier.answerQuery(this._queryingService, this._entry.text); - } else { - this._preemptiveAnswer = this._entry.text; -+ -+ if (this._preemptiveAnswerWatchId) { -+ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); -+ this._preemptiveAnswerWatchId = 0; -+ } - } - }); - -@@ -128,6 +136,11 @@ var AuthPrompt = class { +@@ -119,6 +121,11 @@ var AuthPrompt = GObject.registerClass({ } _onDestroy() { @@ -117,7 +115,19 @@ index 62c5bd078..27eb31a89 100644 this._userVerifier.destroy(); this._userVerifier = null; } -@@ -342,6 +355,11 @@ var AuthPrompt = class { +@@ -250,6 +257,11 @@ var AuthPrompt = GObject.registerClass({ + this._userVerifier.answerQuery(this._queryingService, this._entry.text); + } else { + this._preemptiveAnswer = this._entry.text; ++ ++ if (this._preemptiveAnswerWatchId) { ++ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); ++ this._preemptiveAnswerWatchId = 0; ++ } + } + + this.emit('next'); +@@ -429,6 +441,11 @@ var AuthPrompt = GObject.registerClass({ } setQuestion(question) { @@ -126,11 +136,11 @@ index 62c5bd078..27eb31a89 100644 + this._preemptiveAnswerWatchId = 0; + } + - this._label.set_text(question); + this._entry.hint_text = question; - this._label.show(); -@@ -427,6 +445,19 @@ var AuthPrompt = class { - } + this._entry.show(); +@@ -530,6 +547,19 @@ var AuthPrompt = GObject.registerClass({ + this._updateEntry(false); } + _onUserStoppedTypePreemptiveAnswer() { @@ -149,19 +159,18 @@ index 62c5bd078..27eb31a89 100644 reset() { let oldStatus = this.verificationStatus; this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; -@@ -434,6 +465,12 @@ var AuthPrompt = class { - this.nextButton.label = _("Next"); +@@ -537,6 +567,11 @@ var AuthPrompt = GObject.registerClass({ + this.cancelButton.can_focus = this._hasCancelButton; this._preemptiveAnswer = null; -+ if (this._preemptiveAnswerWatchId) { ++ if (this._preemptiveAnswerWatchId) + this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); -+ } -+ this._preemptiveAnswerWatchId = this._idleMonitor.add_idle_watch (500, -+ this._onUserStoppedTypePreemptiveAnswer.bind(this)); ++ this._preemptiveAnswerWatchId = this._idleMonitor.add_idle_watch(500, ++ this._onUserStoppedTypePreemptiveAnswer.bind(this)); + if (this._userVerifier) this._userVerifier.cancel(); -- -2.21.0 +2.31.1 diff --git a/dist b/dist new file mode 100644 index 0000000000000000000000000000000000000000..89c1faffc18349bb12eee2371e9dc43bf419b95c --- /dev/null +++ b/dist @@ -0,0 +1 @@ +an9 diff --git a/download b/download index 3c41cba5c68d9915423ff5f2452cf6c0bcb96629..6f65bce85b8fa38f0a17c6e523cc34ccf6ea0283 100644 --- a/download +++ b/download @@ -1 +1 @@ -632b67075ebdc183f94461fa05a8505b gnome-shell-3.32.2.tar.xz +2625d20efa1bcacc4624c5fe9e474a88 gnome-shell-40.10.tar.xz diff --git a/enforce-smartcard-at-unlock.patch b/enforce-smartcard-at-unlock.patch index 60274e517fd85d904d6a257d7a910eb9af1e0be8..ffe231636b3cd811e097f015915d8ec0ff4cc8a6 100644 --- a/enforce-smartcard-at-unlock.patch +++ b/enforce-smartcard-at-unlock.patch @@ -1,4 +1,4 @@ -From 8ce91c85fe052d1a9f4fed0743bceae7d9654aa0 Mon Sep 17 00:00:00 2001 +From d2c12a372ea0ccbe6ba682c553d8b83b3253169f Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 28 Sep 2015 10:57:02 -0400 Subject: [PATCH 1/3] smartcardManager: add way to detect if user logged using @@ -16,27 +16,27 @@ This commit adds the necessary api to detect that case. 1 file changed, 7 insertions(+) diff --git a/js/misc/smartcardManager.js b/js/misc/smartcardManager.js -index fda782d1e..bb43c96e7 100644 +index d9b6ff474..26f9f5aaa 100644 --- a/js/misc/smartcardManager.js +++ b/js/misc/smartcardManager.js -@@ -112,5 +112,12 @@ var SmartcardManager = class { +@@ -111,5 +111,12 @@ var SmartcardManager = class { + return true; } - ++ + loggedInWithToken() { + if (this._loginToken) + return true; + + return false; + } -+ }; Signals.addSignalMethods(SmartcardManager.prototype); -- -2.21.0 +2.31.1 -From 6decf5560d309579760e10048533d3bd9bc56c3c Mon Sep 17 00:00:00 2001 +From 98393eef884edc9e685b712c71356751acdd552f Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 28 Sep 2015 19:56:53 -0400 Subject: [PATCH 2/3] gdm: only unlock with smartcard, if smartcard used for @@ -49,18 +49,18 @@ gets used for unlock, too. 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/js/gdm/util.js b/js/gdm/util.js -index 2e9935250..2b80e1dd9 100644 +index 72561daab..6b92e3564 100644 --- a/js/gdm/util.js +++ b/js/gdm/util.js -@@ -126,7 +126,6 @@ var ShellUserVerifier = class { +@@ -149,7 +149,6 @@ var ShellUserVerifier = class { this._settings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA }); this._settings.connect('changed', this._updateDefaultService.bind(this)); - this._updateDefaultService(); - this._fprintManager = Fprint.FprintManager(); - this._smartcardManager = SmartcardManager.getSmartcardManager(); -@@ -138,6 +137,8 @@ var ShellUserVerifier = class { + this._fprintManager = new FprintManagerProxy(Gio.DBus.system, + 'net.reactivated.Fprint', +@@ -166,6 +165,8 @@ var ShellUserVerifier = class { this.smartcardDetected = false; this._checkForSmartcard(); @@ -69,7 +69,7 @@ index 2e9935250..2b80e1dd9 100644 this._smartcardInsertedId = this._smartcardManager.connect('smartcard-inserted', this._checkForSmartcard.bind(this)); this._smartcardRemovedId = this._smartcardManager.connect('smartcard-removed', -@@ -407,7 +408,9 @@ var ShellUserVerifier = class { +@@ -527,7 +528,9 @@ var ShellUserVerifier = class { } _updateDefaultService() { @@ -81,10 +81,10 @@ index 2e9935250..2b80e1dd9 100644 else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY)) this._defaultService = SMARTCARD_SERVICE_NAME; -- -2.21.0 +2.31.1 -From dd844c98c3450dd1b21bcc580b51162c1b00ed2a Mon Sep 17 00:00:00 2001 +From 57ca969a0af6f65e71dc1158163b9c826bdb7079 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 28 Sep 2015 19:57:36 -0400 Subject: [PATCH 3/3] gdm: update default service when smartcard inserted @@ -97,10 +97,10 @@ after we get a smartcard insertion event. 1 file changed, 2 insertions(+) diff --git a/js/gdm/util.js b/js/gdm/util.js -index 2b80e1dd9..6e940d2ab 100644 +index 6b92e3564..e62114cb1 100644 --- a/js/gdm/util.js +++ b/js/gdm/util.js -@@ -327,6 +327,8 @@ var ShellUserVerifier = class { +@@ -420,6 +420,8 @@ var ShellUserVerifier = class { else if (this._preemptingService == SMARTCARD_SERVICE_NAME) this._preemptingService = null; @@ -110,5 +110,5 @@ index 2b80e1dd9..6e940d2ab 100644 } } -- -2.21.0 +2.31.1 diff --git a/extension-updates.patch b/extension-updates.patch deleted file mode 100644 index acc7826db8ab1d209daf9830d01b45abd7266b9d..0000000000000000000000000000000000000000 --- a/extension-updates.patch +++ /dev/null @@ -1,3810 +0,0 @@ -From ab3a275e20c36cc21e529bb2c4328ea36024ecba Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Sat, 6 Jul 2019 15:31:57 +0200 -Subject: [PATCH 01/26] extensionUtils: Move ExtensionState definition here - -It makes sense to keep extension-related enums in the same module instead -of spreading them between ExtensionSystem and ExtensionUtils. - -More importantly, this will make the type available to the extensions-prefs -tool (which runs in a different process and therefore only has access to -a limited set of modules). - -https://bugzilla.gnome.org/show_bug.cgi?id=789852 ---- - js/misc/extensionUtils.js | 13 +++++++++++++ - js/ui/extensionSystem.js | 13 +------------ - js/ui/lookingGlass.js | 14 ++++++++------ - 3 files changed, 22 insertions(+), 18 deletions(-) - -diff --git a/js/misc/extensionUtils.js b/js/misc/extensionUtils.js -index fb1e2b506..dc6e74cf8 100644 ---- a/js/misc/extensionUtils.js -+++ b/js/misc/extensionUtils.js -@@ -17,6 +17,19 @@ var ExtensionType = { - SESSION_MODE: 3 - }; - -+var ExtensionState = { -+ ENABLED: 1, -+ DISABLED: 2, -+ ERROR: 3, -+ OUT_OF_DATE: 4, -+ DOWNLOADING: 5, -+ INITIALIZED: 6, -+ -+ // Used as an error state for operations on unknown extensions, -+ // should never be in a real extensionMeta object. -+ UNINSTALLED: 99 -+}; -+ - // Maps uuid -> metadata object - var extensions = {}; - -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 9ffdb4f3d..3091af2ba 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -6,18 +6,7 @@ const Signals = imports.signals; - const ExtensionUtils = imports.misc.extensionUtils; - const Main = imports.ui.main; - --var ExtensionState = { -- ENABLED: 1, -- DISABLED: 2, -- ERROR: 3, -- OUT_OF_DATE: 4, -- DOWNLOADING: 5, -- INITIALIZED: 6, -- -- // Used as an error state for operations on unknown extensions, -- // should never be in a real extensionMeta object. -- UNINSTALLED: 99 --}; -+const { ExtensionState } = ExtensionUtils; - - // Arrays of uuids - var enabledExtensions; -diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js -index 958211df0..fefb3f731 100644 ---- a/js/ui/lookingGlass.js -+++ b/js/ui/lookingGlass.js -@@ -14,6 +14,8 @@ const Tweener = imports.ui.tweener; - const Main = imports.ui.main; - const JsParse = imports.misc.jsParse; - -+const { ExtensionState } = ExtensionUtils; -+ - const CHEVRON = '>>> '; - - /* Imports...feel free to add here as needed */ -@@ -684,16 +686,16 @@ var Extensions = class Extensions { - - _stateToString(extensionState) { - switch (extensionState) { -- case ExtensionSystem.ExtensionState.ENABLED: -+ case ExtensionState.ENABLED: - return _("Enabled"); -- case ExtensionSystem.ExtensionState.DISABLED: -- case ExtensionSystem.ExtensionState.INITIALIZED: -+ case ExtensionState.DISABLED: -+ case ExtensionState.INITIALIZED: - return _("Disabled"); -- case ExtensionSystem.ExtensionState.ERROR: -+ case ExtensionState.ERROR: - return _("Error"); -- case ExtensionSystem.ExtensionState.OUT_OF_DATE: -+ case ExtensionState.OUT_OF_DATE: - return _("Out of date"); -- case ExtensionSystem.ExtensionState.DOWNLOADING: -+ case ExtensionState.DOWNLOADING: - return _("Downloading"); - } - return 'Unknown'; // Not translated, shouldn't appear --- -2.29.2 - - -From c16d1589d093dac4e0efe21c7f1aeb635afabd0f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Thu, 7 Mar 2019 01:45:45 +0100 -Subject: [PATCH 02/26] extensionSystem: Turn into a class - -The extension system started out as a set of simple functions, but -gained more state later, and even some hacks to emit signals without -having an object to emit them on. - -There is no good reason for that weirdness, so rather than imitating an -object, wrap the existing system into a real ExtensionManager object. - -https://bugzilla.gnome.org/show_bug.cgi?id=789852 ---- - js/ui/extensionDownloader.js | 17 +- - js/ui/extensionSystem.js | 569 +++++++++++++++++------------------ - js/ui/lookingGlass.js | 5 +- - js/ui/main.js | 3 +- - js/ui/shellDBus.js | 7 +- - 5 files changed, 297 insertions(+), 304 deletions(-) - -diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js -index 9aed29c69..fe37463f2 100644 ---- a/js/ui/extensionDownloader.js -+++ b/js/ui/extensionDownloader.js -@@ -6,6 +6,7 @@ const Config = imports.misc.config; - const ExtensionUtils = imports.misc.extensionUtils; - const ExtensionSystem = imports.ui.extensionSystem; - const FileUtils = imports.misc.fileUtils; -+const Main = imports.ui.main; - const ModalDialog = imports.ui.modalDialog; - - const _signals = ExtensionSystem._signals; -@@ -25,7 +26,7 @@ function installExtension(uuid, invocation) { - - _httpSession.queue_message(message, (session, message) => { - if (message.status_code != Soup.KnownStatusCode.OK) { -- ExtensionSystem.logExtensionError(uuid, 'downloading info: ' + message.status_code); -+ Main.extensionManager.logExtensionError(uuid, 'downloading info: ' + message.status_code); - invocation.return_dbus_error('org.gnome.Shell.DownloadInfoError', message.status_code.toString()); - return; - } -@@ -34,7 +35,7 @@ function installExtension(uuid, invocation) { - try { - info = JSON.parse(message.response_body.data); - } catch (e) { -- ExtensionSystem.logExtensionError(uuid, 'parsing info: ' + e); -+ Main.extensionManager.logExtensionError(uuid, 'parsing info: ' + e); - invocation.return_dbus_error('org.gnome.Shell.ParseInfoError', e.toString()); - return; - } -@@ -53,7 +54,7 @@ function uninstallExtension(uuid) { - if (extension.type != ExtensionUtils.ExtensionType.PER_USER) - return false; - -- if (!ExtensionSystem.unloadExtension(extension)) -+ if (!Main.extensionManager.unloadExtension(extension)) - return false; - - FileUtils.recursivelyDeleteDir(extension.dir, true); -@@ -117,7 +118,7 @@ function updateExtension(uuid) { - let oldExtension = ExtensionUtils.extensions[uuid]; - let extensionDir = oldExtension.dir; - -- if (!ExtensionSystem.unloadExtension(oldExtension)) -+ if (!Main.extensionManager.unloadExtension(oldExtension)) - return; - - FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir); -@@ -127,10 +128,10 @@ function updateExtension(uuid) { - - try { - extension = ExtensionUtils.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER); -- ExtensionSystem.loadExtension(extension); -+ Main.extensionManager.loadExtension(extension); - } catch(e) { - if (extension) -- ExtensionSystem.unloadExtension(extension); -+ Main.extensionManager.unloadExtension(extension); - - logError(e, 'Error loading extension %s'.format(uuid)); - -@@ -139,7 +140,7 @@ function updateExtension(uuid) { - - // Restore what was there before. We can't do much if we - // fail here. -- ExtensionSystem.loadExtension(oldExtension); -+ Main.extensionManager.loadExtension(oldExtension); - return; - } - -@@ -239,7 +240,7 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog { - - try { - let extension = ExtensionUtils.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER); -- ExtensionSystem.loadExtension(extension); -+ Main.extensionManager.loadExtension(extension); - } catch(e) { - uninstallExtension(uuid); - errback('LoadExtensionError', e); -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 3091af2ba..b7e908223 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -8,358 +8,351 @@ const Main = imports.ui.main; - - const { ExtensionState } = ExtensionUtils; - --// Arrays of uuids --var enabledExtensions; --// Contains the order that extensions were enabled in. --var extensionOrder = []; -- --// We don't really have a class to add signals on. So, create --// a simple dummy object, add the signal methods, and export those --// publically. --var _signals = {}; --Signals.addSignalMethods(_signals); -- --var connect = _signals.connect.bind(_signals); --var disconnect = _signals.disconnect.bind(_signals); -- - const ENABLED_EXTENSIONS_KEY = 'enabled-extensions'; - const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions'; - const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation'; - --var initted = false; --var enabled; -+var ExtensionManager = class { -+ constructor() { -+ this._initted = false; -+ this._enabled = false; - --function disableExtension(uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -- if (!extension) -- return; -+ this._enabledExtensions = []; -+ this._extensionOrder = []; - -- if (extension.state != ExtensionState.ENABLED) -- return; -+ Main.sessionMode.connect('updated', this._sessionUpdated.bind(this)); -+ this._sessionUpdated(); -+ } - -- // "Rebase" the extension order by disabling and then enabling extensions -- // in order to help prevent conflicts. -+ disableExtension(uuid) { -+ let extension = ExtensionUtils.extensions[uuid]; -+ if (!extension) -+ return; - -- // Example: -- // order = [A, B, C, D, E] -- // user disables C -- // this should: disable E, disable D, disable C, enable D, enable E -+ if (extension.state != ExtensionState.ENABLED) -+ return; - -- let orderIdx = extensionOrder.indexOf(uuid); -- let order = extensionOrder.slice(orderIdx + 1); -- let orderReversed = order.slice().reverse(); -+ // "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 { -+ ExtensionUtils.extensions[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; -+ } - -- for (let i = 0; i < orderReversed.length; i++) { -- let uuid = orderReversed[i]; - try { -- ExtensionUtils.extensions[uuid].stateObj.disable(); -+ extension.stateObj.disable(); - } catch(e) { -- logExtensionError(uuid, 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; -- } -+ for (let i = 0; i < order.length; i++) { -+ let uuid = order[i]; -+ try { -+ ExtensionUtils.extensions[uuid].stateObj.enable(); -+ } catch (e) { -+ this.logExtensionError(uuid, e); -+ } -+ } - -- try { -- extension.stateObj.disable(); -- } catch(e) { -- logExtensionError(uuid, e); -- } -+ this._extensionOrder.splice(orderIdx, 1); - -- for (let i = 0; i < order.length; i++) { -- let uuid = order[i]; -- try { -- ExtensionUtils.extensions[uuid].stateObj.enable(); -- } catch(e) { -- logExtensionError(uuid, e); -+ if (extension.state != ExtensionState.ERROR) { -+ extension.state = ExtensionState.DISABLED; -+ this.emit('extension-state-changed', extension); - } - } - -- extensionOrder.splice(orderIdx, 1); -- -- if ( extension.state != ExtensionState.ERROR ) { -- extension.state = ExtensionState.DISABLED; -- _signals.emit('extension-state-changed', extension); -- } --} -+ enableExtension(uuid) { -+ let extension = ExtensionUtils.extensions[uuid]; -+ if (!extension) -+ return; - --function enableExtension(uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -- if (!extension) -- return; -+ if (extension.state == ExtensionState.INITIALIZED) -+ this.initExtension(uuid); - -- if (extension.state == ExtensionState.INITIALIZED) -- initExtension(uuid); -+ if (extension.state != ExtensionState.DISABLED) -+ return; - -- if (extension.state != ExtensionState.DISABLED) -- return; -+ this._extensionOrder.push(uuid); - -- 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; -+ } -+ } - -- 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; -+ extension.stateObj.enable(); -+ extension.state = ExtensionState.ENABLED; -+ this.emit('extension-state-changed', extension); -+ return; - } 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}`); -+ if (extension.stylesheet) { -+ theme.unload_stylesheet(extension.stylesheet); -+ delete extension.stylesheet; -+ } -+ this.logExtensionError(uuid, e); - return; - } - } - -- try { -- extension.stateObj.enable(); -- extension.state = ExtensionState.ENABLED; -- _signals.emit('extension-state-changed', extension); -- return; -- } catch(e) { -- if (extension.stylesheet) { -- theme.unload_stylesheet(extension.stylesheet); -- delete extension.stylesheet; -- } -- logExtensionError(uuid, e); -- return; -- } --} -- --function logExtensionError(uuid, error) { -- let extension = ExtensionUtils.extensions[uuid]; -- if (!extension) -- return; -+ logExtensionError(uuid, error) { -+ let extension = ExtensionUtils.extensions[uuid]; -+ if (!extension) -+ return; - -- let message = '' + error; -+ let message = '' + error; - -- extension.state = ExtensionState.ERROR; -- if (!extension.errors) -- extension.errors = []; -- extension.errors.push(message); -+ extension.state = ExtensionState.ERROR; -+ if (!extension.errors) -+ extension.errors = []; -+ extension.errors.push(message); - -- log('Extension "%s" had error: %s'.format(uuid, message)); -- _signals.emit('extension-state-changed', { uuid: uuid, -+ log('Extension "%s" had error: %s'.format(uuid, message)); -+ this.emit('extension-state-changed', { uuid: uuid, - error: message, - state: extension.state }); --} -+ } - --function loadExtension(extension) { -- // Default to error, we set success as the last step -- extension.state = ExtensionState.ERROR; -+ 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); -+ 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 = enabledExtensions.indexOf(extension.uuid) != -1; -- if (enabled) { -- if (!initExtension(extension.uuid)) -- return; -- if (extension.state == ExtensionState.DISABLED) -- enableExtension(extension.uuid); -+ if (checkVersion && ExtensionUtils.isOutOfDate(extension)) { -+ extension.state = ExtensionState.OUT_OF_DATE; - } else { -- extension.state = ExtensionState.INITIALIZED; -+ let enabled = this._enabledExtensions.includes(extension.uuid); -+ if (enabled) { -+ if (!this.initExtension(extension.uuid)) -+ return; -+ if (extension.state == ExtensionState.DISABLED) -+ this.enableExtension(extension.uuid); -+ } else { -+ extension.state = ExtensionState.INITIALIZED; -+ } - } -+ -+ this.emit('extension-state-changed', extension); - } - -- _signals.emit('extension-state-changed', extension); --} -- --function unloadExtension(extension) { -- // Try to disable it -- if it's ERROR'd, we can't guarantee that, -- // but it will be removed on next reboot, and hopefully nothing -- // broke too much. -- disableExtension(extension.uuid); -- -- extension.state = ExtensionState.UNINSTALLED; -- _signals.emit('extension-state-changed', extension); -- -- delete ExtensionUtils.extensions[extension.uuid]; -- return true; --} -- --function 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. -- unloadExtension(oldExtension); -- -- // Now, recreate the extension and load it. -- let newExtension; -- try { -- newExtension = ExtensionUtils.createExtensionObject(uuid, dir, type); -- } catch(e) { -- logExtensionError(uuid, e); -- return; -+ unloadExtension(extension) { -+ // Try to disable it -- if it's ERROR'd, we can't guarantee that, -+ // but it will be removed on next reboot, and hopefully nothing -+ // broke too much. -+ this.disableExtension(extension.uuid); -+ -+ extension.state = ExtensionState.UNINSTALLED; -+ this.emit('extension-state-changed', extension); -+ -+ delete ExtensionUtils.extensions[extension.uuid]; -+ return true; - } - -- loadExtension(newExtension); --} -+ reloadExtension(oldExtension) { -+ // Grab the things we'll need to pass to createExtensionObject -+ // to reload it. -+ let { uuid: uuid, dir: dir, type: type } = oldExtension; - --function initExtension(uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -- let dir = extension.dir; -+ // Then unload the old extension. -+ this.unloadExtension(oldExtension); - -- if (!extension) -- throw new Error("Extension was not properly created. Call loadExtension first"); -+ // Now, recreate the extension and load it. -+ let newExtension; -+ try { -+ newExtension = ExtensionUtils.createExtensionObject(uuid, dir, type); -+ } catch (e) { -+ this.logExtensionError(uuid, e); -+ return; -+ } - -- let extensionJs = dir.get_child('extension.js'); -- if (!extensionJs.query_exists(null)) { -- logExtensionError(uuid, new Error('Missing extension.js')); -- return false; -+ this.loadExtension(newExtension); - } - -- let extensionModule; -- let extensionState = null; -+ initExtension(uuid) { -+ let extension = ExtensionUtils.extensions[uuid]; -+ let dir = extension.dir; - -- ExtensionUtils.installImporter(extension); -- try { -- extensionModule = extension.imports.extension; -- } catch(e) { -- logExtensionError(uuid, e); -- return false; -- } -+ 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; - -- if (extensionModule.init) { -+ ExtensionUtils.installImporter(extension); - try { -- extensionState = extensionModule.init(extension); -+ extensionModule = extension.imports.extension; - } catch(e) { -- logExtensionError(uuid, e); -+ this.logExtensionError(uuid, e); - return false; - } -+ -+ if (extensionModule.init) { -+ try { -+ extensionState = extensionModule.init(extension); -+ } catch (e) { -+ this.logExtensionError(uuid, e); -+ return false; -+ } -+ } -+ -+ if (!extensionState) -+ extensionState = extensionModule; -+ extension.stateObj = extensionState; -+ -+ extension.state = ExtensionState.DISABLED; -+ this.emit('extension-loaded', uuid); -+ return true; - } - -- if (!extensionState) -- extensionState = extensionModule; -- extension.stateObj = extensionState; -- -- extension.state = ExtensionState.DISABLED; -- _signals.emit('extension-loaded', uuid); -- return true; --} -- --function getEnabledExtensions() { -- let extensions; -- if (Array.isArray(Main.sessionMode.enabledExtensions)) -- extensions = Main.sessionMode.enabledExtensions; -- else -- extensions = []; -- -- if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY)) -- return extensions; -- -- return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY)); --} -- --function onEnabledExtensionsChanged() { -- let newEnabledExtensions = getEnabledExtensions(); -- -- if (!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 => !enabledExtensions.includes(uuid) -- ).forEach(uuid => { -- enableExtension(uuid); -- }); -- -- // Find and disable all the newly disabled extensions: UUIDs found in the -- // old setting, but not in the new one. -- enabledExtensions.filter( -- item => !newEnabledExtensions.includes(item) -- ).forEach(uuid => { -- disableExtension(uuid); -- }); -- -- enabledExtensions = newEnabledExtensions; --} -- --function _onVersionValidationChanged() { -- // we want to reload all extensions, but only enable -- // extensions when allowed by the sessionMode, so -- // temporarily disable them all -- enabledExtensions = []; -- for (let uuid in ExtensionUtils.extensions) -- reloadExtension(ExtensionUtils.extensions[uuid]); -- enabledExtensions = getEnabledExtensions(); -- -- if (Main.sessionMode.allowExtensions) { -- enabledExtensions.forEach(uuid => { -- enableExtension(uuid); -- }); -+ _getEnabledExtensions() { -+ let extensions; -+ if (Array.isArray(Main.sessionMode.enabledExtensions)) -+ extensions = Main.sessionMode.enabledExtensions; -+ else -+ extensions = []; -+ -+ if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY)) -+ return extensions; -+ -+ return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY)); - } --} -- --function _loadExtensions() { -- global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged); -- global.settings.connect('changed::' + DISABLE_USER_EXTENSIONS_KEY, onEnabledExtensionsChanged); -- global.settings.connect('changed::' + EXTENSION_DISABLE_VERSION_CHECK_KEY, _onVersionValidationChanged); -- -- enabledExtensions = getEnabledExtensions(); -- -- 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(); --} -- --function enableAllExtensions() { -- if (enabled) -- return; -- -- if (!initted) { -- _loadExtensions(); -- initted = true; -- } else { -- enabledExtensions.forEach(uuid => { -- enableExtension(uuid); -+ -+ _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.enableExtension(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.disableExtension(uuid); -+ }); -+ -+ this._enabledExtensions = newEnabledExtensions; -+ } -+ -+ _onVersionValidationChanged() { -+ // we want to reload all extensions, but only enable -+ // extensions when allowed by the sessionMode, so -+ // temporarily disable them all -+ this._enabledExtensions = []; -+ for (let uuid in ExtensionUtils.extensions) -+ this.reloadExtension(ExtensionUtils.extensions[uuid]); -+ this._enabledExtensions = this._getEnabledExtensions(); -+ -+ if (Main.sessionMode.allowExtensions) { -+ this._enabledExtensions.forEach(uuid => { -+ this.enableExtension(uuid); -+ }); -+ } - } -- enabled = true; --} - --function disableAllExtensions() { -- if (!enabled) -- return; -+ _loadExtensions() { -+ global.settings.connect(`changed::${ENABLED_EXTENSIONS_KEY}`, -+ this._onEnabledExtensionsChanged.bind(this)); -+ global.settings.connect(`changed::${DISABLE_USER_EXTENSIONS_KEY}`, -+ this._onEnabledExtensionsChanged.bind(this)); -+ global.settings.connect(`changed::${EXTENSION_DISABLE_VERSION_CHECK_KEY}`, -+ this._onVersionValidationChanged.bind(this)); -+ -+ this._enabledExtensions = this._getEnabledExtensions(); - -- if (initted) { -- extensionOrder.slice().reverse().forEach(uuid => { -- disableExtension(uuid); -+ let finder = new ExtensionUtils.ExtensionFinder(); -+ finder.connect('extension-found', (finder, extension) => { -+ this.loadExtension(extension); - }); -+ finder.scanExtensions(); -+ } -+ -+ enableAllExtensions() { -+ if (this._enabled) -+ return; -+ -+ if (!this._initted) { -+ this._loadExtensions(); -+ this._initted = true; -+ } else { -+ this._enabledExtensions.forEach(uuid => { -+ this.enableExtension(uuid); -+ }); -+ } -+ this._enabled = true; - } - -- enabled = false; --} -- --function _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 (initted) -- enabledExtensions = getEnabledExtensions(); -- enableAllExtensions(); -- } else { -- disableAllExtensions(); -+ disableAllExtensions() { -+ if (!this._enabled) -+ return; -+ -+ if (this._initted) { -+ this._extensionOrder.slice().reverse().forEach(uuid => { -+ this.disableExtension(uuid); -+ }); -+ } -+ -+ this._enabled = false; - } --} - --function init() { -- Main.sessionMode.connect('updated', _sessionUpdated); -- _sessionUpdated(); --} -+ _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(); -+ this.enableAllExtensions(); -+ } else { -+ this.disableAllExtensions(); -+ } -+ } -+}; -+Signals.addSignalMethods(ExtensionManager.prototype); -diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js -index fefb3f731..e947574f2 100644 ---- a/js/ui/lookingGlass.js -+++ b/js/ui/lookingGlass.js -@@ -7,7 +7,6 @@ const Signals = imports.signals; - const System = imports.system; - - const History = imports.misc.history; --const ExtensionSystem = imports.ui.extensionSystem; - const ExtensionUtils = imports.misc.extensionUtils; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; -@@ -624,8 +623,8 @@ var Extensions = class Extensions { - for (let uuid in ExtensionUtils.extensions) - this._loadExtension(null, uuid); - -- ExtensionSystem.connect('extension-loaded', -- this._loadExtension.bind(this)); -+ Main.extensionManager.connect('extension-loaded', -+ this._loadExtension.bind(this)); - } - - _loadExtension(o, uuid) { -diff --git a/js/ui/main.js b/js/ui/main.js -index 8dde95bf9..7bfbce497 100644 ---- a/js/ui/main.js -+++ b/js/ui/main.js -@@ -43,6 +43,7 @@ const STICKY_KEYS_ENABLE = 'stickykeys-enable'; - const GNOMESHELL_STARTED_MESSAGE_ID = 'f3ea493c22934e26811cd62abe8e203a'; - - var componentManager = null; -+var extensionManager = null; - var panel = null; - var overview = null; - var runDialog = null; -@@ -218,7 +219,7 @@ function _initializeUI() { - _startDate = new Date(); - - ExtensionDownloader.init(); -- ExtensionSystem.init(); -+ extensionManager = new ExtensionSystem.ExtensionManager(); - - if (sessionMode.isGreeter && screenShield) { - layoutManager.connect('startup-prepared', () => { -diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js -index 112d60feb..4b04e68ac 100644 ---- a/js/ui/shellDBus.js -+++ b/js/ui/shellDBus.js -@@ -4,7 +4,6 @@ const { Gio, GLib, Meta, Shell } = imports.gi; - const Lang = imports.lang; - - const Config = imports.misc.config; --const ExtensionSystem = imports.ui.extensionSystem; - const ExtensionDownloader = imports.ui.extensionDownloader; - const ExtensionUtils = imports.misc.extensionUtils; - const Main = imports.ui.main; -@@ -250,8 +249,8 @@ var GnomeShellExtensions = class { - constructor() { - this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellExtensionsIface, this); - this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell'); -- ExtensionSystem.connect('extension-state-changed', -- this._extensionStateChanged.bind(this)); -+ Main.extensionManager.connect('extension-state-changed', -+ this._extensionStateChanged.bind(this)); - } - - ListExtensions() { -@@ -334,7 +333,7 @@ var GnomeShellExtensions = class { - if (!extension) - return; - -- ExtensionSystem.reloadExtension(extension); -+ Main.extensionManager.reloadExtension(extension); - } - - CheckForUpdates() { --- -2.29.2 - - -From 7419ee28b5b568dd4478db7f3c890ff01678637a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 8 Jul 2019 02:53:32 +0200 -Subject: [PATCH 03/26] extensionSystem: Make methods to call extension - functions private - -While public methods to enable/disable extensions make sense for an -extension manager, the existing ones are only used internally. Make -them private and rename them, so that we can re-use the current -names for more useful public methods. - -https://bugzilla.gnome.org/show_bug.cgi?id=789852 ---- - js/ui/extensionSystem.js | 32 ++++++++++++++++---------------- - 1 file changed, 16 insertions(+), 16 deletions(-) - -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index b7e908223..c5fb007ae 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -24,7 +24,7 @@ var ExtensionManager = class { - this._sessionUpdated(); - } - -- disableExtension(uuid) { -+ _callExtensionDisable(uuid) { - let extension = ExtensionUtils.extensions[uuid]; - if (!extension) - return; -@@ -82,13 +82,13 @@ var ExtensionManager = class { - } - } - -- enableExtension(uuid) { -+ _callExtensionEnable(uuid) { - let extension = ExtensionUtils.extensions[uuid]; - if (!extension) - return; - - if (extension.state == ExtensionState.INITIALIZED) -- this.initExtension(uuid); -+ this._callExtensionInit(uuid); - - if (extension.state != ExtensionState.DISABLED) - return; -@@ -155,10 +155,10 @@ var ExtensionManager = class { - } else { - let enabled = this._enabledExtensions.includes(extension.uuid); - if (enabled) { -- if (!this.initExtension(extension.uuid)) -+ if (!this._callExtensionInit(extension.uuid)) - return; - if (extension.state == ExtensionState.DISABLED) -- this.enableExtension(extension.uuid); -+ this._callExtensionEnable(extension.uuid); - } else { - extension.state = ExtensionState.INITIALIZED; - } -@@ -171,7 +171,7 @@ var ExtensionManager = class { - // Try to disable it -- if it's ERROR'd, we can't guarantee that, - // but it will be removed on next reboot, and hopefully nothing - // broke too much. -- this.disableExtension(extension.uuid); -+ this._callExtensionDisable(extension.uuid); - - extension.state = ExtensionState.UNINSTALLED; - this.emit('extension-state-changed', extension); -@@ -200,7 +200,7 @@ var ExtensionManager = class { - this.loadExtension(newExtension); - } - -- initExtension(uuid) { -+ _callExtensionInit(uuid) { - let extension = ExtensionUtils.extensions[uuid]; - let dir = extension.dir; - -@@ -266,7 +266,7 @@ var ExtensionManager = class { - newEnabledExtensions.filter( - uuid => !this._enabledExtensions.includes(uuid) - ).forEach(uuid => { -- this.enableExtension(uuid); -+ this._callExtensionEnable(uuid); - }); - - // Find and disable all the newly disabled extensions: UUIDs found in the -@@ -274,7 +274,7 @@ var ExtensionManager = class { - this._enabledExtensions.filter( - item => !newEnabledExtensions.includes(item) - ).forEach(uuid => { -- this.disableExtension(uuid); -+ this._callExtensionDisable(uuid); - }); - - this._enabledExtensions = newEnabledExtensions; -@@ -291,7 +291,7 @@ var ExtensionManager = class { - - if (Main.sessionMode.allowExtensions) { - this._enabledExtensions.forEach(uuid => { -- this.enableExtension(uuid); -+ this._callExtensionEnable(uuid); - }); - } - } -@@ -313,7 +313,7 @@ var ExtensionManager = class { - finder.scanExtensions(); - } - -- enableAllExtensions() { -+ _enableAllExtensions() { - if (this._enabled) - return; - -@@ -322,19 +322,19 @@ var ExtensionManager = class { - this._initted = true; - } else { - this._enabledExtensions.forEach(uuid => { -- this.enableExtension(uuid); -+ this._callExtensionEnable(uuid); - }); - } - this._enabled = true; - } - -- disableAllExtensions() { -+ _disableAllExtensions() { - if (!this._enabled) - return; - - if (this._initted) { - this._extensionOrder.slice().reverse().forEach(uuid => { -- this.disableExtension(uuid); -+ this._callExtensionDisable(uuid); - }); - } - -@@ -349,9 +349,9 @@ var ExtensionManager = class { - if (Main.sessionMode.allowExtensions) { - if (this._initted) - this._enabledExtensions = this._getEnabledExtensions(); -- this.enableAllExtensions(); -+ this._enableAllExtensions(); - } else { -- this.disableAllExtensions(); -+ this._disableAllExtensions(); - } - } - }; --- -2.29.2 - - -From e88419278531b136984f9f05a8c056145d03edba Mon Sep 17 00:00:00 2001 -From: Didier Roche -Date: Wed, 17 Jan 2018 13:43:11 +0100 -Subject: [PATCH 04/26] extensionSystem: Add methods to enable/disable - extensions - -Extensions are currently enabled or disabled by directly changing the -list in the 'enabled-extensions' GSettings key. As we will soon add -an overriding 'disabled-extensions' key as well, it makes sense to -offer explicit API for enabling/disabling to avoid duplicating the -logic. - -For the corresponding D-Bus API, the methods were even mentioned in -the GSettings schema, albeit unimplemented until now. - -https://bugzilla.gnome.org/show_bug.cgi?id=789852 ---- - .../org.gnome.Shell.Extensions.xml | 24 +++++++++++++++++ - js/ui/extensionDownloader.js | 12 ++------- - js/ui/extensionSystem.js | 26 +++++++++++++++++++ - js/ui/shellDBus.js | 8 ++++++ - 4 files changed, 60 insertions(+), 10 deletions(-) - -diff --git a/data/dbus-interfaces/org.gnome.Shell.Extensions.xml b/data/dbus-interfaces/org.gnome.Shell.Extensions.xml -index ce69439fc..22273f889 100644 ---- a/data/dbus-interfaces/org.gnome.Shell.Extensions.xml -+++ b/data/dbus-interfaces/org.gnome.Shell.Extensions.xml -@@ -173,6 +173,30 @@ - - - -+ -+ \ -+ \ -+ \ -+ \ -+ -+ -+ \ -+ \ -+ \ -+ \ -+ - - - - -diff --git a/js/extensionPrefs/main.js b/js/extensionPrefs/main.js -index 43efa95e9..2b4ce5753 100644 ---- a/js/extensionPrefs/main.js -+++ b/js/extensionPrefs/main.js -@@ -241,7 +241,7 @@ var Application = class { - this._mainStack.add_named(new EmptyPlaceholder(), 'placeholder'); - - this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell'); -- this._shellProxy.connectSignal('ExtensionStatusChanged', (proxy, senderName, [uuid, state, error]) => { -+ this._shellProxy.connectSignal('ExtensionStateChanged', (proxy, senderName, [uuid, state]) => { - if (ExtensionUtils.extensions[uuid] !== undefined) - this._scanExtensions(); - }); -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 8ff0fa56f..98eaf5259 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -159,15 +159,14 @@ var ExtensionManager = class { - - let message = '' + error; - -+ extension.error = message; - extension.state = ExtensionState.ERROR; - if (!extension.errors) - extension.errors = []; - extension.errors.push(message); - - log('Extension "%s" had error: %s'.format(uuid, message)); -- this.emit('extension-state-changed', { uuid: uuid, -- error: message, -- state: extension.state }); -+ this.emit('extension-state-changed', extension); - } - - loadExtension(extension) { -diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js -index af5889789..23274c0a3 100644 ---- a/js/ui/shellDBus.js -+++ b/js/ui/shellDBus.js -@@ -335,6 +335,10 @@ var GnomeShellExtensions = class { - } - - _extensionStateChanged(_, newState) { -+ let state = ExtensionUtils.serializeExtension(newState); -+ this._dbusImpl.emit_signal('ExtensionStateChanged', -+ new GLib.Variant('(sa{sv})', [newState.uuid, state])); -+ - this._dbusImpl.emit_signal('ExtensionStatusChanged', - GLib.Variant.new('(sis)', [newState.uuid, newState.state, newState.error])); - } --- -2.29.2 - - -From 47d185f8964f9e04430f4ef97d6d712faaf32078 Mon Sep 17 00:00:00 2001 -From: Didier Roche -Date: Tue, 4 Dec 2018 09:31:27 +0100 -Subject: [PATCH 07/26] extensionSystem: Add canChange property to extensions - -Whether or not an extension can be enabled/disabled depends on various -factors: Whether the extension is in error state, whether user extensions -are disabled and whether the underlying GSettings keys are writable. - -This is complex enough to share the logic, so add it to the extension -properties that are exposed over D-Bus. - -https://bugzilla.gnome.org/show_bug.cgi?id=789852 ---- - js/misc/extensionUtils.js | 3 ++- - js/ui/extensionSystem.js | 44 +++++++++++++++++++++++++++++++++------ - 2 files changed, 40 insertions(+), 7 deletions(-) - -diff --git a/js/misc/extensionUtils.js b/js/misc/extensionUtils.js -index bc9c36f4e..025cd042e 100644 ---- a/js/misc/extensionUtils.js -+++ b/js/misc/extensionUtils.js -@@ -31,7 +31,7 @@ var ExtensionState = { - UNINSTALLED: 99 - }; - --const SERIALIZED_PROPERTIES = ['type', 'state', 'path', 'error', 'hasPrefs']; -+const SERIALIZED_PROPERTIES = ['type', 'state', 'path', 'error', 'hasPrefs', 'canChange']; - - // Maps uuid -> metadata object - var extensions = {}; -@@ -222,6 +222,7 @@ function createExtensionObject(uuid, dir, type) { - extension.path = dir.get_path(); - extension.error = ''; - extension.hasPrefs = dir.get_child('prefs.js').query_exists(null); -+ extension.canChange = false; - - extensions[uuid] = extension; - -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 98eaf5259..a83e53c83 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -189,6 +189,7 @@ var ExtensionManager = class { - } - } - -+ this._updateCanChange(extension); - this.emit('extension-state-changed', extension); - } - -@@ -267,12 +268,28 @@ var ExtensionManager = class { - return true; - } - -- _getEnabledExtensions() { -- let extensions; -+ _getModeExtensions() { - if (Array.isArray(Main.sessionMode.enabledExtensions)) -- extensions = Main.sessionMode.enabledExtensions; -- else -- extensions = []; -+ return Main.sessionMode.enabledExtensions; -+ return []; -+ } -+ -+ _updateCanChange(extension) { -+ 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; -@@ -280,6 +297,11 @@ var ExtensionManager = class { - return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY)); - } - -+ _onUserExtensionsEnabledChanged() { -+ this._onEnabledExtensionsChanged(); -+ this._onSettingsWritableChanged(); -+ } -+ - _onEnabledExtensionsChanged() { - let newEnabledExtensions = this._getEnabledExtensions(); - -@@ -305,6 +327,14 @@ var ExtensionManager = class { - this._enabledExtensions = newEnabledExtensions; - } - -+ _onSettingsWritableChanged() { -+ for (let uuid in ExtensionUtils.extensions) { -+ let extension = ExtensionUtils.extensions[uuid]; -+ 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 -@@ -325,9 +355,11 @@ var ExtensionManager = class { - global.settings.connect(`changed::${ENABLED_EXTENSIONS_KEY}`, - this._onEnabledExtensionsChanged.bind(this)); - global.settings.connect(`changed::${DISABLE_USER_EXTENSIONS_KEY}`, -- this._onEnabledExtensionsChanged.bind(this)); -+ this._onUserExtensionsEnabledChanged.bind(this)); - global.settings.connect(`changed::${EXTENSION_DISABLE_VERSION_CHECK_KEY}`, - this._onVersionValidationChanged.bind(this)); -+ global.settings.connect(`writable-changed::${ENABLED_EXTENSIONS_KEY}`, -+ this._onSettingsWritableChanged.bind(this)); - - this._enabledExtensions = this._getEnabledExtensions(); - --- -2.29.2 - - -From ce14c00ca0707c78dc920ede3a157b7c9d55fff5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= -Date: Tue, 28 May 2019 23:22:37 +0200 -Subject: [PATCH 08/26] extensionPrefs: Inherit from Gtk.Application - -Extension preferences Application class is just a container for a GtkApplication -so instead of using composition we can inherit from the base GObject class. - -Also replace signal connections with vfunc's. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/631 ---- - js/extensionPrefs/main.js | 35 +++++++++++++++++------------------ - 1 file changed, 17 insertions(+), 18 deletions(-) - -diff --git a/js/extensionPrefs/main.js b/js/extensionPrefs/main.js -index 2b4ce5753..94a5b12fe 100644 ---- a/js/extensionPrefs/main.js -+++ b/js/extensionPrefs/main.js -@@ -17,18 +17,16 @@ function stripPrefix(string, prefix) { - return string; - } - --var Application = class { -- constructor() { -+var Application = GObject.registerClass({ -+ GTypeName: 'ExtensionPrefs_Application' -+}, class Application extends Gtk.Application { -+ _init() { - GLib.set_prgname('gnome-shell-extension-prefs'); -- this.application = new Gtk.Application({ -+ super._init({ - application_id: 'org.gnome.shell.ExtensionPrefs', - flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE - }); - -- this.application.connect('activate', this._onActivate.bind(this)); -- this.application.connect('command-line', this._onCommandLine.bind(this)); -- this.application.connect('startup', this._onStartup.bind(this)); -- - this._extensionPrefsModules = {}; - - this._startupUuid = null; -@@ -84,7 +82,7 @@ var Application = class { - visible: true })); - - if (this._skipMainWindow) { -- this.application.add_window(dialog); -+ this.add_window(dialog); - if (this._window) - this._window.destroy(); - this._window = dialog; -@@ -206,8 +204,8 @@ var Application = class { - return scroll; - } - -- _buildUI(app) { -- this._window = new Gtk.ApplicationWindow({ application: app, -+ _buildUI() { -+ this._window = new Gtk.ApplicationWindow({ application: this, - window_position: Gtk.WindowPosition.CENTER }); - - this._window.set_default_size(800, 500); -@@ -295,17 +293,19 @@ var Application = class { - this._loaded = true; - } - -- _onActivate() { -+ vfunc_activate() { - this._window.present(); - } - -- _onStartup(app) { -- this._buildUI(app); -+ vfunc_startup() { -+ super.vfunc_startup(); -+ -+ this._buildUI(); - this._scanExtensions(); - } - -- _onCommandLine(app, commandLine) { -- app.activate(); -+ vfunc_command_line(commandLine) { -+ this.activate(); - let args = commandLine.get_arguments(); - - if (args.length) { -@@ -325,7 +325,7 @@ var Application = class { - } - return 0; - } --}; -+}); - - var Expander = GObject.registerClass({ - Properties: { -@@ -631,6 +631,5 @@ function main(argv) { - Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR); - Gettext.textdomain(Config.GETTEXT_PACKAGE); - -- let app = new Application(); -- app.application.run(argv); -+ new Application().run(argv); - } --- -2.29.2 - - -From ea202d21b65c027db03e773a51bd8fecf4a2fb0a Mon Sep 17 00:00:00 2001 -From: Didier Roche -Date: Thu, 1 Nov 2018 13:50:30 +0100 -Subject: [PATCH 09/26] extensionPrefs: Attach extension object to each row - -Each row represents an extension, so it makes sense to associate the -rows with the actual extensions instead of linking rows and extensions -by looking up the UUID in the external extensions map in ExtensionUtils. - -This will also make it much easier to stop using the shared extension -loading / map in favor of the extension D-Bus API. - -https://bugzilla.gnome.org/show_bug.cgi?id=789852 ---- - js/extensionPrefs/main.js | 120 +++++++++++++++++++------------------- - 1 file changed, 60 insertions(+), 60 deletions(-) - -diff --git a/js/extensionPrefs/main.js b/js/extensionPrefs/main.js -index 94a5b12fe..7e7b2dcc7 100644 ---- a/js/extensionPrefs/main.js -+++ b/js/extensionPrefs/main.js -@@ -34,52 +34,31 @@ var Application = GObject.registerClass({ - this._skipMainWindow = false; - } - -- _extensionAvailable(uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -- -- if (!extension) -- return false; -+ _showPrefs(uuid) { -+ let row = this._extensionSelector.get_children().find(c => { -+ return c.uuid === uuid && c.hasPrefs; -+ }); - -- if (!extension.dir.get_child('prefs.js').query_exists(null)) -+ if (!row) - return false; - -- return true; -- } -- -- _getExtensionPrefsModule(extension) { -- let uuid = extension.metadata.uuid; -- -- if (this._extensionPrefsModules.hasOwnProperty(uuid)) -- return this._extensionPrefsModules[uuid]; -- -- ExtensionUtils.installImporter(extension); -- -- let prefsModule = extension.imports.prefs; -- prefsModule.init(extension.metadata); -- -- this._extensionPrefsModules[uuid] = prefsModule; -- return prefsModule; -- } -- -- _selectExtension(uuid) { -- if (!this._extensionAvailable(uuid)) -- return; -- -- let extension = ExtensionUtils.extensions[uuid]; - let widget; - - try { -- let prefsModule = this._getExtensionPrefsModule(extension); -- widget = prefsModule.buildPrefsWidget(); -+ widget = row.prefsModule.buildPrefsWidget(); - } catch (e) { -- widget = this._buildErrorUI(extension, e); -+ widget = this._buildErrorUI(row, e); - } - -- let dialog = new Gtk.Window({ modal: !this._skipMainWindow, -- type_hint: Gdk.WindowTypeHint.DIALOG }); -- dialog.set_titlebar(new Gtk.HeaderBar({ show_close_button: true, -- title: extension.metadata.name, -- visible: true })); -+ let dialog = new Gtk.Window({ -+ modal: !this._skipMainWindow, -+ type_hint: Gdk.WindowTypeHint.DIALOG -+ }); -+ dialog.set_titlebar(new Gtk.HeaderBar({ -+ show_close_button: true, -+ title: row.name, -+ visible: true -+ })); - - if (this._skipMainWindow) { - this.add_window(dialog); -@@ -96,7 +75,7 @@ var Application = GObject.registerClass({ - dialog.show(); - } - -- _buildErrorUI(extension, exc) { -+ _buildErrorUI(row, exc) { - let scroll = new Gtk.ScrolledWindow({ - hscrollbar_policy: Gtk.PolicyType.NEVER, - propagate_natural_height: true -@@ -183,13 +162,13 @@ var Application = GObject.registerClass({ - label: _("Homepage"), - tooltip_text: _("Visit extension homepage"), - no_show_all: true, -- visible: extension.metadata.url != null -+ visible: row.url != null - }); - toolbar.add(urlButton); - - urlButton.connect('clicked', w => { - let context = w.get_display().get_app_launch_context(); -- Gio.AppInfo.launch_default_for_uri(extension.metadata.url, context); -+ Gio.AppInfo.launch_default_for_uri(row.url, context); - }); - - let expandedBox = new Gtk.Box({ -@@ -248,9 +227,7 @@ var Application = GObject.registerClass({ - } - - _sortList(row1, row2) { -- let name1 = ExtensionUtils.extensions[row1.uuid].metadata.name; -- let name2 = ExtensionUtils.extensions[row2.uuid].metadata.name; -- return name1.localeCompare(name2); -+ return row1.name.localeCompare(row2.name); - } - - _updateHeader(row, before) { -@@ -269,11 +246,10 @@ var Application = GObject.registerClass({ - } - - _extensionFound(finder, extension) { -- let row = new ExtensionRow(extension.uuid); -+ let row = new ExtensionRow(extension); - -- row.prefsButton.visible = this._extensionAvailable(row.uuid); - row.prefsButton.connect('clicked', () => { -- this._selectExtension(row.uuid); -+ this._showPrefs(row.uuid); - }); - - row.show_all(); -@@ -286,8 +262,8 @@ var Application = GObject.registerClass({ - else - this._mainStack.visible_child_name = 'placeholder'; - -- if (this._startupUuid && this._extensionAvailable(this._startupUuid)) -- this._selectExtension(this._startupUuid); -+ if (this._startupUuid) -+ this._showPrefs(this._startupUuid); - this._startupUuid = null; - this._skipMainWindow = false; - this._loaded = true; -@@ -316,11 +292,9 @@ var Application = GObject.registerClass({ - // Strip off "extension:///" prefix which fakes a URI, if it exists - uuid = stripPrefix(uuid, "extension:///"); - -- if (this._extensionAvailable(uuid)) -- this._selectExtension(uuid); -- else if (!this._loaded) -+ if (!this._loaded) - this._startupUuid = uuid; -- else -+ else if (!this._showPrefs(uuid)) - this._skipMainWindow = false; - } - return 0; -@@ -504,10 +478,11 @@ class DescriptionLabel extends Gtk.Label { - - var ExtensionRow = GObject.registerClass( - class ExtensionRow extends Gtk.ListBoxRow { -- _init(uuid) { -+ _init(extension) { - super._init(); - -- this.uuid = uuid; -+ this._extension = extension; -+ this._prefsModule = null; - - this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' }); - this._settings.connect('changed::enabled-extensions', () => { -@@ -525,9 +500,23 @@ class ExtensionRow extends Gtk.ListBoxRow { - this._buildUI(); - } - -- _buildUI() { -- let extension = ExtensionUtils.extensions[this.uuid]; -+ get uuid() { -+ return this._extension.uuid; -+ } -+ -+ get name() { -+ return this._extension.metadata.name; -+ } -+ -+ get hasPrefs() { -+ return this._extension.hasPrefs; -+ } - -+ get url() { -+ return this._extension.metadata.url; -+ } -+ -+ _buildUI() { - let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, - hexpand: true, margin_end: 24, spacing: 24, - margin: 12 }); -@@ -537,19 +526,20 @@ class ExtensionRow extends Gtk.ListBoxRow { - spacing: 6, hexpand: true }); - hbox.add(vbox); - -- let name = GLib.markup_escape_text(extension.metadata.name, -1); -+ let name = GLib.markup_escape_text(this.name, -1); - let label = new Gtk.Label({ label: '' + name + '', - use_markup: true, - halign: Gtk.Align.START }); - vbox.add(label); - -- let desc = extension.metadata.description.split('\n')[0]; -+ let desc = this._extension.metadata.description.split('\n')[0]; - label = new DescriptionLabel({ label: desc, wrap: true, lines: 2, - ellipsize: Pango.EllipsizeMode.END, - xalign: 0, yalign: 0 }); - vbox.add(label); - - let button = new Gtk.Button({ valign: Gtk.Align.CENTER, -+ visible: this.hasPrefs, - no_show_all: true }); - button.set_image(new Gtk.Image({ icon_name: 'emblem-system-symbolic', - icon_size: Gtk.IconSize.BUTTON, -@@ -573,11 +563,10 @@ class ExtensionRow extends Gtk.ListBoxRow { - } - - _canEnable() { -- let extension = ExtensionUtils.extensions[this.uuid]; - let checkVersion = !this._settings.get_boolean('disable-extension-version-validation'); - - return !this._settings.get_boolean('disable-user-extensions') && -- !(checkVersion && ExtensionUtils.isOutOfDate(extension)); -+ !(checkVersion && ExtensionUtils.isOutOfDate(this._extension)); - } - - _isEnabled() { -@@ -605,6 +594,17 @@ class ExtensionRow extends Gtk.ListBoxRow { - } while (pos != -1); - this._settings.set_strv('enabled-extensions', extensions); - } -+ -+ get prefsModule() { -+ if (!this._prefsModule) { -+ ExtensionUtils.installImporter(this._extension); -+ -+ this._prefsModule = this._extension.imports.prefs; -+ this._prefsModule.init(this._extension.metadata); -+ } -+ -+ return this._prefsModule; -+ } - }); - - function initEnvironment() { --- -2.29.2 - - -From 8d80e6667ded38dac53fe245a10191b5d4a3150b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Sat, 6 Jul 2019 01:48:05 +0200 -Subject: [PATCH 10/26] extensionPrefs: Override getCurrentExtension() for - extensions - -Extensions are used to calling the getCurrentExtension() utility function, -both from the extension itself and from its preferences. For the latter, -that relies on the extensions map in ExtensionUtils being populated from -the separated extension-prefs process just like from gnome-shell. - -This won't be the case anymore when we switch to the extensions D-Bus API, -but as we know which extension we are showing the prefs dialog for, we -can patch in a simple replacement that gives extensions the expected API. - -https://bugzilla.gnome.org/show_bug.cgi?id=789852 ---- - js/extensionPrefs/main.js | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/js/extensionPrefs/main.js b/js/extensionPrefs/main.js -index 7e7b2dcc7..29de8202a 100644 ---- a/js/extensionPrefs/main.js -+++ b/js/extensionPrefs/main.js -@@ -599,6 +599,9 @@ class ExtensionRow extends Gtk.ListBoxRow { - if (!this._prefsModule) { - ExtensionUtils.installImporter(this._extension); - -+ // give extension prefs access to their own extension object -+ ExtensionUtils.getCurrentExtension = () => this._extension; -+ - this._prefsModule = this._extension.imports.prefs; - this._prefsModule.init(this._extension.metadata); - } --- -2.29.2 - - -From e03a21b1f768405050bbfda1eb2bbf2ffcf7b4ca Mon Sep 17 00:00:00 2001 -From: Didier Roche -Date: Thu, 1 Nov 2018 13:55:17 +0100 -Subject: [PATCH 11/26] extensionPrefs: Switch to D-Bus API to get extension - live state - -By direclty using the underlying GSetting, whether or not an extension -appears as enabled or disabled currently depends only on whether it is -included in the 'enabled-extensions' list or not. - -However this doesn't necessarily reflect the real extension state, as an -extension may be in error state, or enabled via the session mode. - -Switch to the extensions D-Bus API to ensure that the list of extensions -and each extension's state correctly reflects the state in gnome-shell. - -https://bugzilla.gnome.org/show_bug.cgi?id=789852 ---- - js/extensionPrefs/main.js | 166 +++++++++++++++++++++++++------------- - 1 file changed, 110 insertions(+), 56 deletions(-) - -diff --git a/js/extensionPrefs/main.js b/js/extensionPrefs/main.js -index 29de8202a..f1b732e85 100644 ---- a/js/extensionPrefs/main.js -+++ b/js/extensionPrefs/main.js -@@ -8,6 +8,8 @@ const Config = imports.misc.config; - const ExtensionUtils = imports.misc.extensionUtils; - const { loadInterfaceXML } = imports.misc.fileUtils; - -+const { ExtensionState } = ExtensionUtils; -+ - const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions'); - const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface); - -@@ -32,6 +34,11 @@ var Application = GObject.registerClass({ - this._startupUuid = null; - this._loaded = false; - this._skipMainWindow = false; -+ this._shellProxy = null; -+ } -+ -+ get shellProxy() { -+ return this._shellProxy; - } - - _showPrefs(uuid) { -@@ -218,10 +225,8 @@ var Application = GObject.registerClass({ - this._mainStack.add_named(new EmptyPlaceholder(), 'placeholder'); - - this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell'); -- this._shellProxy.connectSignal('ExtensionStateChanged', (proxy, senderName, [uuid, state]) => { -- if (ExtensionUtils.extensions[uuid] !== undefined) -- this._scanExtensions(); -- }); -+ this._shellProxy.connectSignal('ExtensionStateChanged', -+ this._onExtensionStateChanged.bind(this)); - - this._window.show_all(); - } -@@ -238,14 +243,51 @@ var Application = GObject.registerClass({ - row.set_header(sep); - } - -+ _findExtensionRow(uuid) { -+ return this._extensionSelector.get_children().find(c => c.uuid === uuid); -+ } -+ -+ _onExtensionStateChanged(proxy, senderName, [uuid, newState]) { -+ let row = this._findExtensionRow(uuid); -+ if (row) { -+ let { state } = ExtensionUtils.deserializeExtension(newState); -+ if (state == ExtensionState.UNINSTALLED) -+ row.destroy(); -+ return; // we only deal with new and deleted extensions here -+ } -+ -+ this._shellProxy.GetExtensionInfoRemote(uuid, ([serialized]) => { -+ let extension = ExtensionUtils.deserializeExtension(serialized); -+ if (!extension) -+ return; -+ // check the extension wasn't added in between -+ if (this._findExtensionRow(uuid) != null) -+ return; -+ this._addExtensionRow(extension); -+ }); -+ } -+ - _scanExtensions() { -- let finder = new ExtensionUtils.ExtensionFinder(); -- finder.connect('extension-found', this._extensionFound.bind(this)); -- finder.scanExtensions(); -- this._extensionsLoaded(); -+ this._shellProxy.ListExtensionsRemote(([extensionsMap], e) => { -+ if (e) { -+ if (e instanceof Gio.DBusError) { -+ log(`Failed to connect to shell proxy: ${e}`); -+ this._mainStack.add_named(new NoShellPlaceholder(), 'noshell'); -+ this._mainStack.visible_child_name = 'noshell'; -+ } else -+ throw e; -+ return; -+ } -+ -+ for (let uuid in extensionsMap) { -+ let extension = ExtensionUtils.deserializeExtension(extensionsMap[uuid]); -+ this._addExtensionRow(extension); -+ } -+ this._extensionsLoaded(); -+ }); - } - -- _extensionFound(finder, extension) { -+ _addExtensionRow(extension) { - let row = new ExtensionRow(extension); - - row.prefsButton.connect('clicked', () => { -@@ -466,6 +508,35 @@ class EmptyPlaceholder extends Gtk.Box { - } - }); - -+var NoShellPlaceholder = GObject.registerClass( -+class NoShellPlaceholder extends Gtk.Box { -+ _init() { -+ super._init({ -+ orientation: Gtk.Orientation.VERTICAL, -+ spacing: 12, -+ margin: 100, -+ margin_bottom: 60 -+ }); -+ -+ let label = new Gtk.Label({ -+ label: '%s'.format( -+ _("Something’s gone wrong")), -+ use_markup: true -+ }); -+ label.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL); -+ this.add(label); -+ -+ label = new Gtk.Label({ -+ label: _("We’re very sorry, but it was not possible to get the list of installed extensions. Make sure you are logged into GNOME and try again."), -+ justify: Gtk.Justification.CENTER, -+ wrap: true -+ }); -+ this.add(label); -+ -+ this.show_all(); -+ } -+}); -+ - var DescriptionLabel = GObject.registerClass( - class DescriptionLabel extends Gtk.Label { - vfunc_get_preferred_height_for_width(width) { -@@ -481,22 +552,23 @@ class ExtensionRow extends Gtk.ListBoxRow { - _init(extension) { - super._init(); - -+ this._app = Gio.Application.get_default(); - this._extension = extension; - this._prefsModule = null; - -- this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' }); -- this._settings.connect('changed::enabled-extensions', () => { -- this._switch.state = this._isEnabled(); -- }); -- this._settings.connect('changed::disable-extension-version-validation', -- () => { -- this._switch.sensitive = this._canEnable(); -- }); -- this._settings.connect('changed::disable-user-extensions', -- () => { -- this._switch.sensitive = this._canEnable(); -+ this._extensionStateChangedId = this._app.shellProxy.connectSignal( -+ 'ExtensionStateChanged', (p, sender, [uuid, newState]) => { -+ if (this.uuid !== uuid) -+ return; -+ -+ this._extension = ExtensionUtils.deserializeExtension(newState); -+ let state = (this._extension.state == ExtensionState.ENABLED); -+ this._switch.state = state; -+ this._switch.sensitive = this._canToggle(); - }); - -+ this.connect('destroy', this._onDestroy.bind(this)); -+ - this._buildUI(); - } - -@@ -516,6 +588,15 @@ class ExtensionRow extends Gtk.ListBoxRow { - return this._extension.metadata.url; - } - -+ _onDestroy() { -+ if (!this._app.shellProxy) -+ return; -+ -+ if (this._extensionStateChangedId) -+ this._app.shellProxy.disconnectSignal(this._extensionStateChangedId); -+ this._extensionStateChangedId = 0; -+ } -+ - _buildUI() { - let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, - hexpand: true, margin_end: 24, spacing: 24, -@@ -549,50 +630,23 @@ class ExtensionRow extends Gtk.ListBoxRow { - - this.prefsButton = button; - -- this._switch = new Gtk.Switch({ valign: Gtk.Align.CENTER, -- sensitive: this._canEnable(), -- state: this._isEnabled() }); -+ this._switch = new Gtk.Switch({ -+ valign: Gtk.Align.CENTER, -+ sensitive: this._canToggle(), -+ state: this._extension.state === ExtensionState.ENABLED -+ }); - this._switch.connect('notify::active', () => { - if (this._switch.active) -- this._enable(); -+ this._app.shellProxy.EnableExtensionRemote(this.uuid); - else -- this._disable(); -+ this._app.shellProxy.DisableExtensionRemote(this.uuid); - }); - this._switch.connect('state-set', () => true); - hbox.add(this._switch); - } - -- _canEnable() { -- let checkVersion = !this._settings.get_boolean('disable-extension-version-validation'); -- -- return !this._settings.get_boolean('disable-user-extensions') && -- !(checkVersion && ExtensionUtils.isOutOfDate(this._extension)); -- } -- -- _isEnabled() { -- let extensions = this._settings.get_strv('enabled-extensions'); -- return extensions.indexOf(this.uuid) != -1; -- } -- -- _enable() { -- let extensions = this._settings.get_strv('enabled-extensions'); -- if (extensions.indexOf(this.uuid) != -1) -- return; -- -- extensions.push(this.uuid); -- this._settings.set_strv('enabled-extensions', extensions); -- } -- -- _disable() { -- let extensions = this._settings.get_strv('enabled-extensions'); -- let pos = extensions.indexOf(this.uuid); -- if (pos == -1) -- return; -- do { -- extensions.splice(pos, 1); -- pos = extensions.indexOf(this.uuid); -- } while (pos != -1); -- this._settings.set_strv('enabled-extensions', extensions); -+ _canToggle() { -+ return this._extension.canChange; - } - - get prefsModule() { --- -2.29.2 - - -From 9baf77dcae765618902d958549801276156f1255 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Sun, 7 Jul 2019 23:38:27 +0200 -Subject: [PATCH 12/26] extensionSystem: Move extension loading into - ExtensionManager - -Now that extension loading and the extensions map are no longer shared -between the gnome-shell and gnome-shell-extension-prefs processes, we -can move both into the ExtensionManager which makes much more sense -conceptually. - -https://bugzilla.gnome.org/show_bug.cgi?id=789852 ---- - js/misc/extensionUtils.js | 95 ++---------------------------- - js/ui/extensionDownloader.js | 12 ++-- - js/ui/extensionSystem.js | 110 +++++++++++++++++++++++++++++------ - js/ui/lookingGlass.js | 4 +- - js/ui/main.js | 1 + - js/ui/shellDBus.js | 8 +-- - 6 files changed, 111 insertions(+), 119 deletions(-) - -diff --git a/js/misc/extensionUtils.js b/js/misc/extensionUtils.js -index 025cd042e..c513ebc06 100644 ---- a/js/misc/extensionUtils.js -+++ b/js/misc/extensionUtils.js -@@ -7,10 +7,8 @@ const { Gio, GLib } = imports.gi; - - const Gettext = imports.gettext; - const Lang = imports.lang; --const Signals = imports.signals; - - const Config = imports.misc.config; --const FileUtils = imports.misc.fileUtils; - - var ExtensionType = { - SYSTEM: 1, -@@ -33,9 +31,6 @@ var ExtensionState = { - - const SERIALIZED_PROPERTIES = ['type', 'state', 'path', 'error', 'hasPrefs', 'canChange']; - --// Maps uuid -> metadata object --var extensions = {}; -- - /** - * getCurrentExtension: - * -@@ -66,13 +61,17 @@ function getCurrentExtension() { - if (!match) - return null; - -+ // local import, as the module is used from outside the gnome-shell process -+ // as well (not this function though) -+ let extensionManager = imports.ui.main.extensionManager; -+ - let path = match[1]; - let file = Gio.File.new_for_path(path); - - // Walk up the directory tree, looking for an extension with - // the same UUID as a directory name. - while (file != null) { -- let extension = extensions[file.get_basename()]; -+ let extension = extensionManager.extensions[file.get_basename()]; - if (extension !== undefined) - return extension; - file = file.get_parent(); -@@ -178,57 +177,6 @@ function isOutOfDate(extension) { - return false; - } - --function createExtensionObject(uuid, dir, type) { -- let info; -- -- let metadataFile = dir.get_child('metadata.json'); -- if (!metadataFile.query_exists(null)) { -- throw new Error('Missing metadata.json'); -- } -- -- let metadataContents, success, tag; -- try { -- [success, metadataContents, tag] = metadataFile.load_contents(null); -- if (metadataContents instanceof Uint8Array) -- metadataContents = imports.byteArray.toString(metadataContents); -- } catch (e) { -- 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 = {}; -- -- extension.metadata = meta; -- extension.uuid = meta.uuid; -- extension.type = type; -- extension.dir = dir; -- extension.path = dir.get_path(); -- extension.error = ''; -- extension.hasPrefs = dir.get_child('prefs.js').query_exists(null); -- extension.canChange = false; -- -- extensions[uuid] = extension; -- -- return extension; --} -- - function serializeExtension(extension) { - let obj = {}; - Lang.copyProperties(extension.metadata, obj); -@@ -283,36 +231,3 @@ function installImporter(extension) { - extension.imports = imports[extension.uuid]; - imports.searchPath = oldSearchPath; - } -- --var ExtensionFinder = class { -- _loadExtension(extensionDir, info, perUserDir) { -- let fileType = info.get_file_type(); -- if (fileType != Gio.FileType.DIRECTORY) -- return; -- let uuid = info.get_name(); -- let existing = extensions[uuid]; -- if (existing) { -- log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path())); -- return; -- } -- -- let extension; -- let type = extensionDir.has_prefix(perUserDir) ? ExtensionType.PER_USER -- : ExtensionType.SYSTEM; -- try { -- extension = createExtensionObject(uuid, extensionDir, type); -- } catch(e) { -- logError(e, 'Could not load extension %s'.format(uuid)); -- return; -- } -- this.emit('extension-found', extension); -- } -- -- scanExtensions() { -- let perUserDir = Gio.File.new_for_path(global.userdatadir); -- FileUtils.collectFromDatadirs('extensions', true, (dir, info) => { -- this._loadExtension(dir, info, perUserDir); -- }); -- } --}; --Signals.addSignalMethods(ExtensionFinder.prototype); -diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js -index de52edfa6..1d92a5740 100644 ---- a/js/ui/extensionDownloader.js -+++ b/js/ui/extensionDownloader.js -@@ -43,7 +43,7 @@ function installExtension(uuid, invocation) { - } - - function uninstallExtension(uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -+ let extension = Main.extensionManager.extensions[uuid]; - if (!extension) - return false; - -@@ -112,7 +112,7 @@ function updateExtension(uuid) { - - _httpSession.queue_message(message, (session, message) => { - gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, () => { -- let oldExtension = ExtensionUtils.extensions[uuid]; -+ let oldExtension = Main.extensionManager.extensions[uuid]; - let extensionDir = oldExtension.dir; - - if (!Main.extensionManager.unloadExtension(oldExtension)) -@@ -124,7 +124,7 @@ function updateExtension(uuid) { - let extension = null; - - try { -- extension = ExtensionUtils.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER); -+ extension = Main.extensionManager.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER); - Main.extensionManager.loadExtension(extension); - } catch(e) { - if (extension) -@@ -150,8 +150,8 @@ function updateExtension(uuid) { - - function checkForUpdates() { - let metadatas = {}; -- for (let uuid in ExtensionUtils.extensions) { -- metadatas[uuid] = ExtensionUtils.extensions[uuid].metadata; -+ for (let uuid in Main.extensionManager.extensions) { -+ metadatas[uuid] = Main.extensionManager.extensions[uuid].metadata; - } - - let params = { shell_version: Config.PACKAGE_VERSION, -@@ -229,7 +229,7 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog { - - function callback() { - try { -- let extension = ExtensionUtils.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER); -+ let extension = Main.extensionManager.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER); - Main.extensionManager.loadExtension(extension); - if (!Main.extensionManager.enableExtension(uuid)) - throw new Error(`Cannot add ${uuid} to enabled extensions gsettings key`); -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index a83e53c83..0fd49c5ca 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -4,9 +4,10 @@ const { Gio, St } = imports.gi; - const Signals = imports.signals; - - const ExtensionUtils = imports.misc.extensionUtils; -+const FileUtils = imports.misc.fileUtils; - const Main = imports.ui.main; - --const { ExtensionState } = ExtensionUtils; -+const { ExtensionState, ExtensionType } = ExtensionUtils; - - const ENABLED_EXTENSIONS_KEY = 'enabled-extensions'; - const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions'; -@@ -17,15 +18,23 @@ var ExtensionManager = class { - this._initted = false; - this._enabled = false; - -+ this._extensions = {}; - this._enabledExtensions = []; - this._extensionOrder = []; - - Main.sessionMode.connect('updated', this._sessionUpdated.bind(this)); -+ } -+ -+ init() { - this._sessionUpdated(); - } - -+ get extensions() { -+ return this._extensions; -+ } -+ - _callExtensionDisable(uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -+ let extension = this._extensions[uuid]; - if (!extension) - return; - -@@ -47,7 +56,7 @@ var ExtensionManager = class { - for (let i = 0; i < orderReversed.length; i++) { - let uuid = orderReversed[i]; - try { -- ExtensionUtils.extensions[uuid].stateObj.disable(); -+ this._extensions[uuid].stateObj.disable(); - } catch (e) { - this.logExtensionError(uuid, e); - } -@@ -68,7 +77,7 @@ var ExtensionManager = class { - for (let i = 0; i < order.length; i++) { - let uuid = order[i]; - try { -- ExtensionUtils.extensions[uuid].stateObj.enable(); -+ this._extensions[uuid].stateObj.enable(); - } catch (e) { - this.logExtensionError(uuid, e); - } -@@ -83,7 +92,7 @@ var ExtensionManager = class { - } - - _callExtensionEnable(uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -+ let extension = this._extensions[uuid]; - if (!extension) - return; - -@@ -127,7 +136,7 @@ var ExtensionManager = class { - } - - enableExtension(uuid) { -- if (!ExtensionUtils.extensions[uuid]) -+ if (!this._extensions[uuid]) - return false; - - let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY); -@@ -140,7 +149,7 @@ var ExtensionManager = class { - } - - disableExtension(uuid) { -- if (!ExtensionUtils.extensions[uuid]) -+ if (!this._extensions[uuid]) - return false; - - let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY); -@@ -153,7 +162,7 @@ var ExtensionManager = class { - } - - logExtensionError(uuid, error) { -- let extension = ExtensionUtils.extensions[uuid]; -+ let extension = this._extensions[uuid]; - if (!extension) - return; - -@@ -169,6 +178,54 @@ var ExtensionManager = class { - this.emit('extension-state-changed', extension); - } - -+ createExtensionObject(uuid, dir, type) { -+ let metadataFile = dir.get_child('metadata.json'); -+ if (!metadataFile.query_exists(null)) { -+ throw new Error('Missing metadata.json'); -+ } -+ -+ let metadataContents, success; -+ try { -+ [success, metadataContents] = metadataFile.load_contents(null); -+ if (metadataContents instanceof Uint8Array) -+ metadataContents = imports.byteArray.toString(metadataContents); -+ } catch (e) { -+ 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), -+ canChange: false -+ }; -+ this._extensions[uuid] = extension; -+ -+ return extension; -+ } -+ - loadExtension(extension) { - // Default to error, we set success as the last step - extension.state = ExtensionState.ERROR; -@@ -202,7 +259,7 @@ var ExtensionManager = class { - extension.state = ExtensionState.UNINSTALLED; - this.emit('extension-state-changed', extension); - -- delete ExtensionUtils.extensions[extension.uuid]; -+ delete this._extensions[extension.uuid]; - return true; - } - -@@ -217,7 +274,7 @@ var ExtensionManager = class { - // Now, recreate the extension and load it. - let newExtension; - try { -- newExtension = ExtensionUtils.createExtensionObject(uuid, dir, type); -+ newExtension = this.createExtensionObject(uuid, dir, type); - } catch (e) { - this.logExtensionError(uuid, e); - return; -@@ -227,7 +284,7 @@ var ExtensionManager = class { - } - - _callExtensionInit(uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -+ let extension = this._extensions[uuid]; - let dir = extension.dir; - - if (!extension) -@@ -328,7 +385,7 @@ var ExtensionManager = class { - } - - _onSettingsWritableChanged() { -- for (let uuid in ExtensionUtils.extensions) { -+ for (let uuid in this._extensions) { - let extension = ExtensionUtils.extensions[uuid]; - this._updateCanChange(extension); - this.emit('extension-state-changed', extension); -@@ -340,8 +397,8 @@ var ExtensionManager = class { - // extensions when allowed by the sessionMode, so - // temporarily disable them all - this._enabledExtensions = []; -- for (let uuid in ExtensionUtils.extensions) -- this.reloadExtension(ExtensionUtils.extensions[uuid]); -+ for (let uuid in this._extensions) -+ this.reloadExtension(this._extensions[uuid]); - this._enabledExtensions = this._getEnabledExtensions(); - - if (Main.sessionMode.allowExtensions) { -@@ -363,11 +420,30 @@ var ExtensionManager = class { - - this._enabledExtensions = this._getEnabledExtensions(); - -- let finder = new ExtensionUtils.ExtensionFinder(); -- finder.connect('extension-found', (finder, extension) => { -+ 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._extensions[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); - }); -- finder.scanExtensions(); - } - - _enableAllExtensions() { -diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js -index e947574f2..b8f8b14c9 100644 ---- a/js/ui/lookingGlass.js -+++ b/js/ui/lookingGlass.js -@@ -620,7 +620,7 @@ var Extensions = class Extensions { - this._extensionsList.add(this._noExtensions); - this.actor.add(this._extensionsList); - -- for (let uuid in ExtensionUtils.extensions) -+ for (let uuid in Main.extensionManager.extensions) - this._loadExtension(null, uuid); - - Main.extensionManager.connect('extension-loaded', -@@ -628,7 +628,7 @@ var Extensions = class Extensions { - } - - _loadExtension(o, uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -+ let extension = Main.extensionManager.extensions[uuid]; - // There can be cases where we create dummy extension metadata - // that's not really a proper extension. Don't bother with these. - if (!extension.metadata.name) -diff --git a/js/ui/main.js b/js/ui/main.js -index 7bfbce497..5fa5a8077 100644 ---- a/js/ui/main.js -+++ b/js/ui/main.js -@@ -220,6 +220,7 @@ function _initializeUI() { - - ExtensionDownloader.init(); - extensionManager = new ExtensionSystem.ExtensionManager(); -+ extensionManager.init(); - - if (sessionMode.isGreeter && screenShield) { - layoutManager.connect('startup-prepared', () => { -diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js -index 23274c0a3..dc3a61df6 100644 ---- a/js/ui/shellDBus.js -+++ b/js/ui/shellDBus.js -@@ -254,7 +254,7 @@ var GnomeShellExtensions = class { - - ListExtensions() { - let out = {}; -- for (let uuid in ExtensionUtils.extensions) { -+ for (let uuid in Main.extensionManager.extensions) { - let dbusObj = this.GetExtensionInfo(uuid); - out[uuid] = dbusObj; - } -@@ -262,12 +262,12 @@ var GnomeShellExtensions = class { - } - - GetExtensionInfo(uuid) { -- let extension = ExtensionUtils.extensions[uuid] || {}; -+ let extension = Main.extensionManager.extensions[uuid] || {}; - return ExtensionUtils.serializeExtension(extension); - } - - GetExtensionErrors(uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -+ let extension = Main.extensionManager.extensions[uuid]; - if (!extension) - return []; - -@@ -303,7 +303,7 @@ var GnomeShellExtensions = class { - } - - ReloadExtension(uuid) { -- let extension = ExtensionUtils.extensions[uuid]; -+ let extension = Main.extensionManager.extensions[uuid]; - if (!extension) - return; - --- -2.29.2 - - -From 776b82542aa705ea527dfbdd1a6d3fb1588092e2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 8 Jul 2019 00:01:11 +0200 -Subject: [PATCH 13/26] extensionSystem: Store extensions in a Map - -After making the extensions map private to the ExtensionManager, we can -switch it to a proper hash table which is more appropriate. - -https://bugzilla.gnome.org/show_bug.cgi?id=789852 ---- - js/misc/extensionUtils.js | 2 +- - js/ui/extensionDownloader.js | 8 +++---- - js/ui/extensionSystem.js | 42 ++++++++++++++++++++---------------- - js/ui/lookingGlass.js | 5 +++-- - js/ui/shellDBus.js | 10 ++++----- - 5 files changed, 37 insertions(+), 30 deletions(-) - -diff --git a/js/misc/extensionUtils.js b/js/misc/extensionUtils.js -index c513ebc06..62b25d46c 100644 ---- a/js/misc/extensionUtils.js -+++ b/js/misc/extensionUtils.js -@@ -71,7 +71,7 @@ function getCurrentExtension() { - // Walk up the directory tree, looking for an extension with - // the same UUID as a directory name. - while (file != null) { -- let extension = extensionManager.extensions[file.get_basename()]; -+ let extension = extensionManager.lookup(file.get_basename()); - if (extension !== undefined) - return extension; - file = file.get_parent(); -diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js -index 1d92a5740..77d013ffb 100644 ---- a/js/ui/extensionDownloader.js -+++ b/js/ui/extensionDownloader.js -@@ -43,7 +43,7 @@ function installExtension(uuid, invocation) { - } - - function uninstallExtension(uuid) { -- let extension = Main.extensionManager.extensions[uuid]; -+ let extension = Main.extensionManager.lookup(uuid); - if (!extension) - return false; - -@@ -112,7 +112,7 @@ function updateExtension(uuid) { - - _httpSession.queue_message(message, (session, message) => { - gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, () => { -- let oldExtension = Main.extensionManager.extensions[uuid]; -+ let oldExtension = Main.extensionManager.lookup(uuid); - let extensionDir = oldExtension.dir; - - if (!Main.extensionManager.unloadExtension(oldExtension)) -@@ -150,9 +150,9 @@ function updateExtension(uuid) { - - function checkForUpdates() { - let metadatas = {}; -- for (let uuid in Main.extensionManager.extensions) { -+ Main.extensionManager.getUuids().forEach(uuid => { - metadatas[uuid] = Main.extensionManager.extensions[uuid].metadata; -- } -+ }); - - let params = { shell_version: Config.PACKAGE_VERSION, - installed: JSON.stringify(metadatas) }; -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 0fd49c5ca..cd3e78301 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -18,7 +18,7 @@ var ExtensionManager = class { - this._initted = false; - this._enabled = false; - -- this._extensions = {}; -+ this._extensions = new Map(); - this._enabledExtensions = []; - this._extensionOrder = []; - -@@ -29,12 +29,16 @@ var ExtensionManager = class { - this._sessionUpdated(); - } - -- get extensions() { -- return this._extensions; -+ lookup(uuid) { -+ return this._extensions.get(uuid); -+ } -+ -+ getUuids() { -+ return [...this._extensions.keys()]; - } - - _callExtensionDisable(uuid) { -- let extension = this._extensions[uuid]; -+ let extension = this.lookup(uuid); - if (!extension) - return; - -@@ -56,7 +60,7 @@ var ExtensionManager = class { - for (let i = 0; i < orderReversed.length; i++) { - let uuid = orderReversed[i]; - try { -- this._extensions[uuid].stateObj.disable(); -+ this.lookup(uuid).stateObj.disable(); - } catch (e) { - this.logExtensionError(uuid, e); - } -@@ -77,7 +81,7 @@ var ExtensionManager = class { - for (let i = 0; i < order.length; i++) { - let uuid = order[i]; - try { -- this._extensions[uuid].stateObj.enable(); -+ this.lookup(uuid).stateObj.enable(); - } catch (e) { - this.logExtensionError(uuid, e); - } -@@ -92,7 +96,7 @@ var ExtensionManager = class { - } - - _callExtensionEnable(uuid) { -- let extension = this._extensions[uuid]; -+ let extension = this.lookup(uuid); - if (!extension) - return; - -@@ -136,7 +140,7 @@ var ExtensionManager = class { - } - - enableExtension(uuid) { -- if (!this._extensions[uuid]) -+ if (!this._extensions.has(uuid)) - return false; - - let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY); -@@ -149,7 +153,7 @@ var ExtensionManager = class { - } - - disableExtension(uuid) { -- if (!this._extensions[uuid]) -+ if (!this._extensions.has(uuid)) - return false; - - let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY); -@@ -162,7 +166,7 @@ var ExtensionManager = class { - } - - logExtensionError(uuid, error) { -- let extension = this._extensions[uuid]; -+ let extension = this.lookup(uuid); - if (!extension) - return; - -@@ -221,7 +225,7 @@ var ExtensionManager = class { - hasPrefs: dir.get_child('prefs.js').query_exists(null), - canChange: false - }; -- this._extensions[uuid] = extension; -+ this._extensions.set(uuid, extension); - - return extension; - } -@@ -259,7 +263,7 @@ var ExtensionManager = class { - extension.state = ExtensionState.UNINSTALLED; - this.emit('extension-state-changed', extension); - -- delete this._extensions[extension.uuid]; -+ this._extensions.delete(extension.uuid); - return true; - } - -@@ -284,7 +288,7 @@ var ExtensionManager = class { - } - - _callExtensionInit(uuid) { -- let extension = this._extensions[uuid]; -+ let extension = this.lookup(uuid); - let dir = extension.dir; - - if (!extension) -@@ -385,8 +389,7 @@ var ExtensionManager = class { - } - - _onSettingsWritableChanged() { -- for (let uuid in this._extensions) { -- let extension = ExtensionUtils.extensions[uuid]; -+ for (let extension of this._extensions.values()) { - this._updateCanChange(extension); - this.emit('extension-state-changed', extension); - } -@@ -397,8 +400,11 @@ var ExtensionManager = class { - // extensions when allowed by the sessionMode, so - // temporarily disable them all - this._enabledExtensions = []; -- for (let uuid in this._extensions) -- this.reloadExtension(this._extensions[uuid]); -+ -+ // 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) { -@@ -426,7 +432,7 @@ var ExtensionManager = class { - if (fileType != Gio.FileType.DIRECTORY) - return; - let uuid = info.get_name(); -- let existing = this._extensions[uuid]; -+ let existing = this.lookup(uuid); - if (existing) { - log(`Extension ${uuid} already installed in ${existing.path}. ${dir.get_path()} will not be loaded`); - return; -diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js -index b8f8b14c9..9196959bd 100644 ---- a/js/ui/lookingGlass.js -+++ b/js/ui/lookingGlass.js -@@ -620,15 +620,16 @@ var Extensions = class Extensions { - this._extensionsList.add(this._noExtensions); - this.actor.add(this._extensionsList); - -- for (let uuid in Main.extensionManager.extensions) -+ Main.extensionManager.getUuids().forEach(uuid => { - this._loadExtension(null, uuid); -+ }); - - Main.extensionManager.connect('extension-loaded', - this._loadExtension.bind(this)); - } - - _loadExtension(o, uuid) { -- let extension = Main.extensionManager.extensions[uuid]; -+ let extension = Main.extensionManager.lookup(uuid); - // There can be cases where we create dummy extension metadata - // that's not really a proper extension. Don't bother with these. - if (!extension.metadata.name) -diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js -index dc3a61df6..be9b10491 100644 ---- a/js/ui/shellDBus.js -+++ b/js/ui/shellDBus.js -@@ -254,20 +254,20 @@ var GnomeShellExtensions = class { - - ListExtensions() { - let out = {}; -- for (let uuid in Main.extensionManager.extensions) { -+ Main.extensionManager.getUuids().forEach(uuid => { - let dbusObj = this.GetExtensionInfo(uuid); - out[uuid] = dbusObj; -- } -+ }); - return out; - } - - GetExtensionInfo(uuid) { -- let extension = Main.extensionManager.extensions[uuid] || {}; -+ let extension = Main.extensionManager.lookup(uuid) || {}; - return ExtensionUtils.serializeExtension(extension); - } - - GetExtensionErrors(uuid) { -- let extension = Main.extensionManager.extensions[uuid]; -+ let extension = Main.extensionManager.lookup(uuid); - if (!extension) - return []; - -@@ -303,7 +303,7 @@ var GnomeShellExtensions = class { - } - - ReloadExtension(uuid) { -- let extension = Main.extensionManager.extensions[uuid]; -+ let extension = Main.extensionManager.lookup(uuid); - if (!extension) - return; - --- -2.29.2 - - -From 2cc95ba7c93c04bae0006b7d018928600d9cbb13 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 22 Jan 2020 14:45:15 +0100 -Subject: [PATCH 14/26] extensionSystem: Add hasUpdate state - -The current support for extension updates is half-baked at best. -We are about to change that, and implement offline updates similar -to gnome-software. - -As a first step, add a hasUpdate property to the extension state -which will communicate available updates. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945 ---- - js/misc/extensionUtils.js | 10 +++++++++- - js/ui/extensionSystem.js | 10 ++++++++++ - 2 files changed, 19 insertions(+), 1 deletion(-) - -diff --git a/js/misc/extensionUtils.js b/js/misc/extensionUtils.js -index 62b25d46c..a812acdb1 100644 ---- a/js/misc/extensionUtils.js -+++ b/js/misc/extensionUtils.js -@@ -29,7 +29,15 @@ var ExtensionState = { - UNINSTALLED: 99 - }; - --const SERIALIZED_PROPERTIES = ['type', 'state', 'path', 'error', 'hasPrefs', 'canChange']; -+const SERIALIZED_PROPERTIES = [ -+ 'type', -+ 'state', -+ 'path', -+ 'error', -+ 'hasPrefs', -+ 'hasUpdate', -+ 'canChange', -+]; - - /** - * getCurrentExtension: -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index cd3e78301..93faf48d4 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -165,6 +165,15 @@ var ExtensionManager = class { - return true; - } - -+ notifyExtensionUpdate(uuid) { -+ let extension = this.lookup(uuid); -+ if (!extension) -+ return; -+ -+ extension.hasUpdate = true; -+ this.emit('extension-state-changed', extension); -+ } -+ - logExtensionError(uuid, error) { - let extension = this.lookup(uuid); - if (!extension) -@@ -223,6 +232,7 @@ var ExtensionManager = class { - path: dir.get_path(), - error: '', - hasPrefs: dir.get_child('prefs.js').query_exists(null), -+ hasUpdate: false, - canChange: false - }; - this._extensions.set(uuid, extension); --- -2.29.2 - - -From 07330eaac64fc115851ec9d5a0969bd046599e12 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 22 Jan 2020 15:07:45 +0100 -Subject: [PATCH 15/26] extensionDownloader: Make checkForUpdates() check for - updates - -Currently the method installs updates instead of merely checking for -them (or it would do, if it actually worked). - -This is not just surprising considering the method name, the whole idea -of live updates is problematic and will not work properly more often -than not: - - imports are cached, so any local modules will stay at their - original version until a shell restart - - GTypes cannot be unregistered - -So change the method to only download available updates, and set the -extensions' hasUpdate state accordingly. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945 ---- - js/ui/extensionDownloader.js | 51 +++++++----------------------------- - 1 file changed, 9 insertions(+), 42 deletions(-) - -diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js -index 77d013ffb..66cb13d56 100644 ---- a/js/ui/extensionDownloader.js -+++ b/js/ui/extensionDownloader.js -@@ -97,53 +97,20 @@ function gotExtensionZipFile(session, message, uuid, dir, callback, errback) { - }); - } - --function updateExtension(uuid) { -- // This gets a bit tricky. We want the update to be seamless - -- // if we have any error during downloading or extracting, we -- // want to not unload the current version. -- -- let oldExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension'); -- let newExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension'); -+function downloadExtensionUpdate(uuid) { -+ let dir = Gio.File.new_for_path( -+ GLib.build_filenamev([global.userdatadir, 'extension-updates', uuid])); - - let params = { shell_version: Config.PACKAGE_VERSION }; - - let url = REPOSITORY_URL_DOWNLOAD.format(uuid); - let message = Soup.form_request_new_from_hash('GET', url, params); - -- _httpSession.queue_message(message, (session, message) => { -- gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, () => { -- let oldExtension = Main.extensionManager.lookup(uuid); -- let extensionDir = oldExtension.dir; -- -- if (!Main.extensionManager.unloadExtension(oldExtension)) -- return; -- -- FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir); -- FileUtils.recursivelyMoveDir(newExtensionTmpDir, extensionDir); -- -- let extension = null; -- -- try { -- extension = Main.extensionManager.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER); -- Main.extensionManager.loadExtension(extension); -- } catch(e) { -- if (extension) -- Main.extensionManager.unloadExtension(extension); -- -- logError(e, 'Error loading extension %s'.format(uuid)); -- -- FileUtils.recursivelyDeleteDir(extensionDir, false); -- FileUtils.recursivelyMoveDir(oldExtensionTmpDir, extensionDir); -- -- // Restore what was there before. We can't do much if we -- // fail here. -- Main.extensionManager.loadExtension(oldExtension); -- return; -- } -- -- FileUtils.recursivelyDeleteDir(oldExtensionTmpDir, true); -- }, (code, message) => { -- log('Error while updating extension %s: %s (%s)'.format(uuid, code, message ? message : '')); -+ _httpSession.queue_message(message, session => { -+ gotExtensionZipFile(session, message, uuid, dir, () => { -+ Main.extensionManager.notifyExtensionUpdate(uuid); -+ }, (code, msg) => { -+ log(`Error while downloading update for extension ${uuid}: ${code} (${msg})`); - }); - }); - } -@@ -169,7 +136,7 @@ function checkForUpdates() { - if (operation == 'blacklist') - uninstallExtension(uuid); - else if (operation == 'upgrade' || operation == 'downgrade') -- updateExtension(uuid); -+ downloadExtensionUpdate(uuid); - } - }); - } --- -2.29.2 - - -From 49eaf28202787f0802663aa609ee9f87eb548b03 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 22 Jan 2020 15:42:06 +0100 -Subject: [PATCH 16/26] extensionDownloader: Only check updates for user - extensions - -System extensions cannot be updated through the website, so don't -even try. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945 ---- - js/ui/extensionDownloader.js | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js -index 66cb13d56..c8f6735c5 100644 ---- a/js/ui/extensionDownloader.js -+++ b/js/ui/extensionDownloader.js -@@ -118,7 +118,10 @@ function downloadExtensionUpdate(uuid) { - function checkForUpdates() { - let metadatas = {}; - Main.extensionManager.getUuids().forEach(uuid => { -- metadatas[uuid] = Main.extensionManager.extensions[uuid].metadata; -+ let extension = Main.extensionManager.lookup(uuid); -+ if (extension.type !== ExtensionUtils.ExtensionType.PER_USER) -+ return; -+ metadatas[uuid] = extension.metadata; - }); - - let params = { shell_version: Config.PACKAGE_VERSION, --- -2.29.2 - - -From 67d709de14b083a013b3b1160e5cc451cf96bfde Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 27 Jan 2020 01:13:49 +0100 -Subject: [PATCH 17/26] extensionDownloader: Exclude extensions with pending - updates from check - -While it is possible that an extension has a newer version available -than the previously downloaded update, it's more likely that we end up -downloading the same archive again. That would be a bit silly despite -the usually small size, so we can either use the metadata from the -update, or exclude the extension from the check. - -The latter is much easier, so let's go with that for now. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945 ---- - js/ui/extensionDownloader.js | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js -index c8f6735c5..ede276c37 100644 ---- a/js/ui/extensionDownloader.js -+++ b/js/ui/extensionDownloader.js -@@ -121,6 +121,8 @@ function checkForUpdates() { - let extension = Main.extensionManager.lookup(uuid); - if (extension.type !== ExtensionUtils.ExtensionType.PER_USER) - return; -+ if (extension.hasUpdate) -+ return; - metadatas[uuid] = extension.metadata; - }); - --- -2.29.2 - - -From 2fa19162c71787fbb9aa9af1d35e0e9cab11c1d1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 22 Jan 2020 16:53:32 +0100 -Subject: [PATCH 18/26] extensionDownloader: Include version validation in - update check - -The extensions website will consider the setting to find the best suitable -extension version, so we should transmit the parameter for better results. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945 ---- - js/ui/extensionDownloader.js | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js -index ede276c37..f957c6c62 100644 ---- a/js/ui/extensionDownloader.js -+++ b/js/ui/extensionDownloader.js -@@ -126,8 +126,13 @@ function checkForUpdates() { - metadatas[uuid] = extension.metadata; - }); - -- let params = { shell_version: Config.PACKAGE_VERSION, -- installed: JSON.stringify(metadatas) }; -+ let versionCheck = global.settings.get_boolean( -+ 'disable-extension-version-validation'); -+ let params = { -+ shell_version: Config.PACKAGE_VERSION, -+ installed: JSON.stringify(metadatas), -+ disable_version_validation: `${versionCheck}`, -+ }; - - let url = REPOSITORY_URL_UPDATE; - let message = Soup.form_request_new_from_hash('GET', url, params); --- -2.29.2 - - -From ccb0095b1981233ca980d44c260c0d36eef910bd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 22 Jan 2020 15:09:05 +0100 -Subject: [PATCH 19/26] extensionSystem: Install pending updates on startup - -Now that we have a way to check for updates and download them, we -should actually apply them as well. Do this on startup before any -extensions are initialized, to make sure we don't run into any -conflicts with a previously loaded version. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/945 ---- - js/ui/extensionSystem.js | 18 +++++++++++++++++- - 1 file changed, 17 insertions(+), 1 deletion(-) - -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 93faf48d4..36a248dc1 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -1,6 +1,6 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - --const { Gio, St } = imports.gi; -+const { GLib, Gio, St } = imports.gi; - const Signals = imports.signals; - - const ExtensionUtils = imports.misc.extensionUtils; -@@ -26,6 +26,7 @@ var ExtensionManager = class { - } - - init() { -+ this._installExtensionUpdates(); - this._sessionUpdated(); - } - -@@ -424,6 +425,21 @@ var ExtensionManager = class { - } - } - -+ _installExtensionUpdates() { -+ FileUtils.collectFromDatadirs('extension-updates', true, (dir, info) => { -+ let fileType = info.get_file_type(); -+ if (fileType !== Gio.FileType.DIRECTORY) -+ return; -+ let uuid = info.get_name(); -+ let extensionDir = Gio.File.new_for_path( -+ GLib.build_filenamev([global.userdatadir, 'extensions', uuid])); -+ -+ FileUtils.recursivelyDeleteDir(extensionDir, false); -+ FileUtils.recursivelyMoveDir(dir, extensionDir); -+ FileUtils.recursivelyDeleteDir(dir, true); -+ }); -+ } -+ - _loadExtensions() { - global.settings.connect(`changed::${ENABLED_EXTENSIONS_KEY}`, - this._onEnabledExtensionsChanged.bind(this)); --- -2.29.2 - - -From e377b16ffb667be40a850ff03e092f2f9dfe8fe8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 24 Jan 2020 18:09:34 +0100 -Subject: [PATCH 20/26] extensionPrefs: Add application icon - -We are about to make the tool a user-visible application, so we -need an icon. Add one (plus its symbolic variant). - -https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968 ---- - data/gnome-shell-extension-prefs.desktop.in.in | 1 + - data/icons/hicolor/scalable/apps/org.gnome.Extensions.svg | 7 +++++++ - .../symbolic/apps/org.gnome.Extensions-symbolic.svg | 1 + - data/icons/meson.build | 1 + - data/meson.build | 1 + - meson.build | 1 + - 6 files changed, 12 insertions(+) - create mode 100644 data/icons/hicolor/scalable/apps/org.gnome.Extensions.svg - create mode 100644 data/icons/hicolor/symbolic/apps/org.gnome.Extensions-symbolic.svg - create mode 100644 data/icons/meson.build - -diff --git a/data/gnome-shell-extension-prefs.desktop.in.in b/data/gnome-shell-extension-prefs.desktop.in.in -index 1b144c5bd..1b58c424e 100644 ---- a/data/gnome-shell-extension-prefs.desktop.in.in -+++ b/data/gnome-shell-extension-prefs.desktop.in.in -@@ -1,6 +1,7 @@ - [Desktop Entry] - Type=Application - Name=Shell Extensions -+Icon=org.gnome.Extensions - Comment=Configure GNOME Shell Extensions - Exec=@bindir@/gnome-shell-extension-prefs %u - X-GNOME-Bugzilla-Bugzilla=GNOME -diff --git a/data/icons/hicolor/scalable/apps/org.gnome.Extensions.svg b/data/icons/hicolor/scalable/apps/org.gnome.Extensions.svg -new file mode 100644 -index 000000000..49d63888b ---- /dev/null -+++ b/data/icons/hicolor/scalable/apps/org.gnome.Extensions.svg -@@ -0,0 +1,7 @@ -+ -+ -+ -+ -+ -+ -+ -diff --git a/data/icons/hicolor/symbolic/apps/org.gnome.Extensions-symbolic.svg b/data/icons/hicolor/symbolic/apps/org.gnome.Extensions-symbolic.svg -new file mode 100644 -index 000000000..43786ff4a ---- /dev/null -+++ b/data/icons/hicolor/symbolic/apps/org.gnome.Extensions-symbolic.svg -@@ -0,0 +1 @@ -+ -\ No newline at end of file -diff --git a/data/icons/meson.build b/data/icons/meson.build -new file mode 100644 -index 000000000..eff6e4b53 ---- /dev/null -+++ b/data/icons/meson.build -@@ -0,0 +1 @@ -+install_subdir('hicolor', install_dir: icondir) -diff --git a/data/meson.build b/data/meson.build -index 31ac4514e..33edb58c4 100644 ---- a/data/meson.build -+++ b/data/meson.build -@@ -42,6 +42,7 @@ endforeach - - - subdir('dbus-interfaces') -+subdir('icons') - subdir('theme') - - data_resources = [ -diff --git a/meson.build b/meson.build -index 0acaba705..2dd1bbc7a 100644 ---- a/meson.build -+++ b/meson.build -@@ -52,6 +52,7 @@ pkglibdir = join_paths(libdir, meson.project_name()) - autostartdir = join_paths(sysconfdir, 'xdg', 'autostart') - convertdir = join_paths(datadir, 'GConf', 'gsettings') - desktopdir = join_paths(datadir, 'applications') -+icondir = join_paths(datadir, 'icons') - ifacedir = join_paths(datadir, 'dbus-1', 'interfaces') - localedir = join_paths(datadir, 'locale') - portaldir = join_paths(datadir, 'xdg-desktop-portal', 'portals') --- -2.29.2 - - -From 6b3fa1549f9682f54f55cdd963a242cd279ff17c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Sun, 26 Jan 2020 23:47:24 +0100 -Subject: [PATCH 21/26] extensionSystem: Show notification when updates are - available - -Now that the extensions app has the ability to handle updates, we -can use it as source of updates notifications. - -https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968 ---- - js/ui/extensionSystem.js | 39 ++++++++++++++++++++++++++++++++++++++- - 1 file changed, 38 insertions(+), 1 deletion(-) - -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 36a248dc1..805e08cae 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -1,11 +1,12 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - --const { GLib, Gio, St } = imports.gi; -+const { GLib, Gio, GObject, St } = imports.gi; - const Signals = imports.signals; - - const ExtensionUtils = imports.misc.extensionUtils; - const FileUtils = imports.misc.fileUtils; - const Main = imports.ui.main; -+const MessageTray = imports.ui.messageTray; - - const { ExtensionState, ExtensionType } = ExtensionUtils; - -@@ -17,6 +18,7 @@ var ExtensionManager = class { - constructor() { - this._initted = false; - this._enabled = false; -+ this._updateNotified = false; - - this._extensions = new Map(); - this._enabledExtensions = []; -@@ -173,6 +175,18 @@ var ExtensionManager = class { - - extension.hasUpdate = true; - this.emit('extension-state-changed', extension); -+ -+ if (!this._updateNotified) { -+ this._updateNotified = true; -+ -+ let source = new ExtensionUpdateSource(); -+ Main.messageTray.add(source); -+ -+ let notification = new MessageTray.Notification(source, -+ _('Extension Updates Available'), -+ _('Extension updates are ready to be installed.')); -+ source.notify(notification); -+ } - } - - logExtensionError(uuid, error) { -@@ -521,3 +535,26 @@ var ExtensionManager = class { - } - }; - 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.29.2 - - -From f6a5e2731f487d7a0ac088aff53ca1e76006c118 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 27 Jan 2020 00:59:19 +0100 -Subject: [PATCH 22/26] extensionSystem: Periodically check for extension - updates - -Now that we can download, apply and display extension updates, it is time -to actually check for updates. Schedule an update check right on startup, -then every 24 hours. - -https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968 ---- - js/ui/extensionSystem.js | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 805e08cae..914abb309 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -3,6 +3,7 @@ - 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; -@@ -14,6 +15,8 @@ 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; -@@ -30,6 +33,12 @@ var ExtensionManager = class { - 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) { --- -2.29.2 - - -From cb3ed33a72fea3ae6b8df031abca48b99dba75a5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 9 Mar 2020 16:49:34 +0100 -Subject: [PATCH 23/26] extensionDownloader: Remove pending updates with - extension - -When an extension is uninstalled, there is no point in keeping -a pending update: If the update didn't fail (which it currently -does), we would end up sneakily reinstalling the extension. - -https://gitlab.gnome.org/GNOME/gnome-shell/issues/2343 ---- - js/ui/extensionDownloader.js | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js -index f957c6c62..0bd77e125 100644 ---- a/js/ui/extensionDownloader.js -+++ b/js/ui/extensionDownloader.js -@@ -55,6 +55,15 @@ function uninstallExtension(uuid) { - return false; - - FileUtils.recursivelyDeleteDir(extension.dir, true); -+ -+ try { -+ const updatesDir = Gio.File.new_for_path(GLib.build_filenamev( -+ [global.userdatadir, 'extension-updates', extension.uuid])); -+ FileUtils.recursivelyDeleteDir(updatesDir, true); -+ } catch (e) { -+ // not an error -+ } -+ - return true; - } - --- -2.29.2 - - -From 6abb5a189a7c97de8c0ed28c40f34fb625363223 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 9 Mar 2020 16:45:22 +0100 -Subject: [PATCH 24/26] extensionSystem: Catch errors when updating extensions - -Extension updates are installed at startup, so any errors that bubble -up uncaught will prevent the startup to complete. - -While the most likely error reason was addressed in the previous commit -(pending update for a no-longer exitent extension), it makes sense to -catch any kind of corrupt updates to not interfere with shell startup. - -https://gitlab.gnome.org/GNOME/gnome-shell/issues/2343 ---- - js/ui/extensionSystem.js | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 914abb309..320af54e4 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -457,9 +457,14 @@ var ExtensionManager = class { - let extensionDir = Gio.File.new_for_path( - GLib.build_filenamev([global.userdatadir, 'extensions', uuid])); - -- FileUtils.recursivelyDeleteDir(extensionDir, false); -- FileUtils.recursivelyMoveDir(dir, extensionDir); -- FileUtils.recursivelyDeleteDir(dir, true); -+ try { -+ FileUtils.recursivelyDeleteDir(extensionDir, false); -+ FileUtils.recursivelyMoveDir(dir, extensionDir); -+ } catch (e) { -+ log('Failed to install extension updates for %s'.format(uuid)); -+ } finally { -+ FileUtils.recursivelyDeleteDir(dir, true); -+ } - }); - } - --- -2.29.2 - - -From 405897a9930362dad590eb8bd425c130dc636083 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Tue, 26 Jan 2021 17:12:04 +0100 -Subject: [PATCH 25/26] extensionSystem: Fix opening Extensions app from - notification - -Launching the app is implemented by the source's open() method, but -only external notifications are hooked up to call into the source -when no default action was provided. ---- - js/ui/extensionSystem.js | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 320af54e4..81804ea5e 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -194,6 +194,8 @@ var ExtensionManager = class { - let notification = new MessageTray.Notification(source, - _('Extension Updates Available'), - _('Extension updates are ready to be installed.')); -+ notification.connect('activated', -+ () => source.open()); - source.notify(notification); - } - } --- -2.29.2 - - -From 8d50b96701eefa7f9bff4af8c855087eee35739a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 1 Feb 2021 18:26:00 +0100 -Subject: [PATCH 26/26] 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 0bd77e125..1e6f5340a 100644 ---- a/js/ui/extensionDownloader.js -+++ b/js/ui/extensionDownloader.js -@@ -16,6 +16,14 @@ var REPOSITORY_URL_UPDATE = REPOSITORY_URL_BASE + '/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: uuid, - shell_version: Config.PACKAGE_VERSION }; - --- -2.29.2 diff --git a/fix-app-view-leaks.patch b/fix-app-view-leaks.patch deleted file mode 100644 index b74b9b251d78654e867fd60444feeec0554a99f9..0000000000000000000000000000000000000000 --- a/fix-app-view-leaks.patch +++ /dev/null @@ -1,421 +0,0 @@ -From a518c9f57e5fe9c6b5ece5c6cb0534a83f0b2f2d Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 -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 -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 -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 -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 -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 -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 -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 - diff --git a/fix-invalid-access-warnings.patch b/fix-invalid-access-warnings.patch deleted file mode 100644 index 8fbdb93205a595bb80bd7e4fdcc0f97a7e795a1e..0000000000000000000000000000000000000000 --- a/fix-invalid-access-warnings.patch +++ /dev/null @@ -1,224 +0,0 @@ -From 76eebb42ed4c76970a9debfc0cd41537923eccde Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= -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 -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 - diff --git a/fix-login-lock-screen.patch b/fix-login-lock-screen.patch deleted file mode 100644 index f714a385a17752c3e8a4aa0296edf9c373d572a4..0000000000000000000000000000000000000000 --- a/fix-login-lock-screen.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 214c4f390faa40199c03a80594313760ffe9c5a6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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?= -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 - diff --git a/fix-markup-in-highlighter.patch b/fix-markup-in-highlighter.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7509f6cc90bcf96fa1d4c8a411b733ee7b30754 --- /dev/null +++ b/fix-markup-in-highlighter.patch @@ -0,0 +1,334 @@ +From 49a950b9e0dc262fd20c28e21ee4815ea8efe758 Mon Sep 17 00:00:00 2001 +From: Sebastian Keller +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: +--- + 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, '$1'); ++ } ++}; +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, '$1'); ++ return this._highlighter.highlight(description); + } + }); + +-- +2.35.1 + + +From 7c1abe1bd91ecf274d81e122035cbeeef6fd58d4 Mon Sep 17 00:00:00 2001 +From: Sebastian Keller +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 "". 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: +--- + 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('%s'.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, '$1'); ++ return escaped.join(''); + } + }; +-- +2.35.1 + + +From 82e2a6dcfabc2f82efbf468175d16c303f0c73da Mon Sep 17 00:00:00 2001 +From: Sebastian Keller +Date: Wed, 17 Nov 2021 03:05:05 +0100 +Subject: [PATCH 3/3] tests: Add unit test for highlighter + +Part-of: +--- + 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: 'abc cba' }, ++ { input: 'abc cba', ++ terms: ['a', 'a'], ++ output: 'abc cba' }, ++ { input: 'CaSe InSenSiTiVe', ++ terms: ['cas', 'sens'], ++ output: 'CaSe InSenSiTiVe' }, ++ { input: 'This contains the < character', ++ terms: null, ++ output: 'This contains the < character' }, ++ { input: 'Don\'t', ++ terms: ['t'], ++ output: 'Don't' }, ++ { input: 'Don\'t', ++ terms: ['n\'t'], ++ output: 'Don't' }, ++ { input: 'Don\'t', ++ terms: ['o', 't'], ++ output: 'Don't' }, ++ { input: 'salt&pepper', ++ terms: ['salt'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['salt', 'alt'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['pepper'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['salt', 'pepper'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['t', 'p'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['t', '&', 'p'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['e'], ++ output: 'salt&pepper' }, ++ { input: 'salt&pepper', ++ terms: ['&a', '&am', '&', '&'], ++ output: 'salt&pepper' }, ++ { input: '&&&&&', ++ terms: ['a'], ++ output: '&&&&&' }, ++ { input: '&;&;&;&;&;', ++ terms: ['a'], ++ output: '&;&;&;&;&;' }, ++ { input: '&;&;&;&;&;', ++ terms: [';'], ++ output: '&;&;&;&;&;' }, ++ { input: '&', ++ terms: ['a'], ++ output: '&amp;' } ++]; ++ ++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 + diff --git a/fix-some-js-warnings.patch b/fix-some-js-warnings.patch index 3faa3290e6c02876c7d400c75bc385656595caef..67adf0df79564cde763bb5d396544493512a0b2e 100644 --- a/fix-some-js-warnings.patch +++ b/fix-some-js-warnings.patch @@ -1,47 +1,7 @@ -From 530964cc6e5db02633434853debd96069dc2b8d8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= -Date: Thu, 23 May 2019 06:12:56 +0200 -Subject: [PATCH 1/6] realmd: Set login format to null on start and update if - invalid - -We were checking an undefined property but that would lead to a a warning. -Instead we can consider the login format unset until is null, and in case -update it. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/700 ---- - js/gdm/realmd.js | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/js/gdm/realmd.js b/js/gdm/realmd.js -index 50f3c5899..04cd99787 100644 ---- a/js/gdm/realmd.js -+++ b/js/gdm/realmd.js -@@ -21,6 +21,7 @@ var Manager = class { - '/org/freedesktop/realmd', - this._reloadRealms.bind(this)) - this._realms = {}; -+ this._loginFormat = null; - - this._signalId = this._aggregateProvider.connect('g-properties-changed', - (proxy, properties) => { -@@ -86,7 +87,7 @@ var Manager = class { - } - - get loginFormat() { -- if (this._loginFormat !== undefined) -+ if (this._loginFormat) - return this._loginFormat; - - this._updateLoginFormat(); --- -2.33.1 - - -From 988e4b58d64fbf87f0c497315ff2506b269ff7c9 Mon Sep 17 00:00:00 2001 +From 05a5f4641c8ad6337ccb46e63abcaf27dd7eb852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 9 Jun 2020 19:42:21 +0200 -Subject: [PATCH 2/6] popupMenu: Guard against non-menu-item children +Subject: [PATCH 1/4] popupMenu: Guard against non-menu-item children This avoid a harmless but annoying warning. --- @@ -49,10 +9,10 @@ This avoid a harmless but annoying warning. 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js -index 44818533a..b5115d7f7 100644 +index 11528560d..144c600d7 100644 --- a/js/ui/popupMenu.js +++ b/js/ui/popupMenu.js -@@ -696,7 +696,8 @@ var PopupMenuBase = class { +@@ -773,7 +773,8 @@ var PopupMenuBase = class { } _getMenuItems() { @@ -63,13 +23,13 @@ index 44818533a..b5115d7f7 100644 }); } -- -2.33.1 +2.31.1 -From 609a8e22e67b63da1e35167d8511400f22641368 Mon Sep 17 00:00:00 2001 +From e5b2c2b3cfd0443fa83fd1f6f56f65fefa5186c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 9 Jun 2020 19:48:06 +0200 -Subject: [PATCH 3/6] st/shadow: Check pipeline when painting +Subject: [PATCH 2/4] st/shadow: Check pipeline when painting We shouldn't simply assume that st_shadow_helper_update() has been called before paint() or that the pipeline was created successfully. @@ -78,10 +38,10 @@ called before paint() or that the pipeline was created successfully. 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/st/st-shadow.c b/src/st/st-shadow.c -index f3a22f034..7665de755 100644 +index ab3eaa856..d53808698 100644 --- a/src/st/st-shadow.c +++ b/src/st/st-shadow.c -@@ -289,9 +289,10 @@ st_shadow_helper_paint (StShadowHelper *helper, +@@ -296,9 +296,10 @@ st_shadow_helper_paint (StShadowHelper *helper, ClutterActorBox *actor_box, guint8 paint_opacity) { @@ -98,126 +58,127 @@ index f3a22f034..7665de755 100644 + paint_opacity); } -- -2.33.1 +2.31.1 -From b57d6efccbeb139d6c7c1894f83caa7a26fd6bad Mon Sep 17 00:00:00 2001 +From 0f7656d85af51339d14217b9a673442a18df3de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Tue, 5 Jan 2021 21:42:24 +0100 -Subject: [PATCH 4/6] viewSelector: Don't set page parent during construction - -gjs now aggressively garbage-collects objects that fall out of scope, -sometimes too aggressively: - - - we pass a child as construct property to StBin - - as a result, the child's ::parent-set handler runs - - when calling clutter_actor_get_parent() from that - handler, the returned object is garbage-collected - *before* the constructor returns (and thus the - assignment that would keep it alive) - -This is a bug on the gjs side that should be fixed, but we can easily -work around the issue by setting the child after constructing the -parent. ---- - js/ui/viewSelector.js | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/js/ui/viewSelector.js b/js/ui/viewSelector.js -index 77146552d..6529ac9a5 100644 ---- a/js/ui/viewSelector.js -+++ b/js/ui/viewSelector.js -@@ -301,11 +301,13 @@ var ViewSelector = class { - _addPage(actor, name, a11yIcon, params) { - params = Params.parse(params, { a11yFocus: null }); - -- let page = new St.Bin({ child: actor, -- x_align: St.Align.START, -- y_align: St.Align.START, -- x_fill: true, -- y_fill: true }); -+ let page = new St.Bin({ -+ x_align: St.Align.START, -+ y_align: St.Align.START, -+ x_fill: true, -+ y_fill: true, -+ }); -+ page.set_child(actor); - if (params.a11yFocus) - Main.ctrlAltTabManager.addGroup(params.a11yFocus, name, a11yIcon); - else --- -2.33.1 +Date: Thu, 8 Jul 2021 19:10:05 +0200 +Subject: [PATCH 3/4] messageTray: Always remove destroyed banners +Currently we only mark the banner as removed if it is destroyed +while in SHOWN or SHOWING state, but not if we're already HIDING +(for example in response to `NotificationBanner::done-displaying`). -From 0c76c91c3d16c8386a242daf367d66057364a5d1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 23 Oct 2020 23:44:48 +0200 -Subject: [PATCH 5/6] workspacesView: Don't set up MetaLater when unparented +If this happens, we'll try to destroy the notification again at +the end of the transition, which leads to (harmless but annoying) +log spam since Notifications were turned into GObjects (that are +disposed when destroyed). + +Address this by always marking destroyed banners as removed, while +still only triggering a state update while shown (or in the process +of being shown). -We already do the check in the later handler, but if we got -unparented because the actor is destroyed, then the call to -get_parent() itself will trigger a (harmless but annoying) -warning. +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4457 --- - js/ui/workspacesView.js | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js -index e302296a6..3270900b2 100644 ---- a/js/ui/workspacesView.js -+++ b/js/ui/workspacesView.js -@@ -715,6 +715,9 @@ var WorkspacesDisplay = class { - oldParent.disconnect(this._notifyOpacityId); - this._notifyOpacityId = 0; + js/ui/messageTray.js | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js +index 1dab00a70..ccf56fc5b 100644 +--- a/js/ui/messageTray.js ++++ b/js/ui/messageTray.js +@@ -1022,17 +1022,20 @@ var MessageTray = GObject.registerClass({ + } + + _onNotificationDestroy(notification) { +- if (this._notification == notification && (this._notificationState == State.SHOWN || this._notificationState == State.SHOWING)) { +- this._updateNotificationTimeout(0); +- this._notificationRemoved = true; +- this._updateState(); +- return; +- } ++ this._notificationRemoved = this._notification === notification; + +- let index = this._notificationQueue.indexOf(notification); +- if (index != -1) { +- this._notificationQueue.splice(index, 1); +- this.emit('queue-changed'); ++ if (this._notificationRemoved) { ++ if (this._notificationState === State.SHOWN || ++ this._notificationState === State.SHOWING) { ++ this._updateNotificationTimeout(0); ++ this._updateState(); ++ } ++ } else { ++ const index = this._notificationQueue.indexOf(notification); ++ if (index !== -1) { ++ this._notificationQueue.splice(index, 1); ++ this.emit('queue-changed'); ++ } + } + } -+ if (!this.actor.get_parent()) -+ return; -+ - Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { - let newParent = this.actor.get_parent(); - if (!newParent) -- -2.33.1 +2.31.1 -From 4ba01f2fdada7e4b059a0f57a99dc3ff2ddfa8f8 Mon Sep 17 00:00:00 2001 +From 8652836521d0729ce230268c7b448cdb393d5b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 26 Nov 2021 17:28:54 +0100 -Subject: [PATCH 6/6] workspacesView: Remove later on destroy +Date: Thu, 8 Jul 2021 19:23:38 +0200 +Subject: [PATCH 4/4] shellInfo: Don't destroy source on undo + +Destroying the source from an action callback will result in the +notification being destroyed twice: -We are careful not to schedule the later when the actor is destroyed, -however it is possible that one is still pending at that point (namely -if the actor was never shown). + - source.destroy() destroys all its notifications + + - a notification destroys itself after an action + was activated + +This results in unwanted log spam when attempting to dispose the +notification for a second time. + +There is actually no good reason for destroying the source explicitly, +as sources already self-destruct with their last notification. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4457 --- - js/ui/workspacesView.js | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js -index 3270900b2..9dc05fca7 100644 ---- a/js/ui/workspacesView.js -+++ b/js/ui/workspacesView.js -@@ -449,6 +449,11 @@ var WorkspacesDisplay = class { - this.actor._delegate = this; - this.actor.connect('notify::allocation', this._updateWorkspacesActualGeometry.bind(this)); - this.actor.connect('parent-set', this._parentSet.bind(this)); -+ this.actor.connect('destroy', () => { -+ if (this._laterId) -+ Meta.later_remove(this._laterId); -+ this._laterId = 0; -+ }); + js/ui/overview.js | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +diff --git a/js/ui/overview.js b/js/ui/overview.js +index 529779ea8..c71b11389 100644 +--- a/js/ui/overview.js ++++ b/js/ui/overview.js +@@ -25,16 +25,6 @@ var OVERVIEW_ACTIVATION_TIMEOUT = 0.5; + var ShellInfo = class { + constructor() { + this._source = null; +- this._undoCallback = null; +- } +- +- _onUndoClicked() { +- if (this._undoCallback) +- this._undoCallback(); +- this._undoCallback = null; +- +- if (this._source) +- this._source.destroy(); + } + + setMessage(text, options) { +@@ -64,9 +54,8 @@ var ShellInfo = class { + notification.update(text, null, { clear: true }); + } - let clickAction = new Clutter.ClickAction(); - clickAction.connect('clicked', action => { -@@ -718,7 +723,7 @@ var WorkspacesDisplay = class { - if (!this.actor.get_parent()) - return; +- this._undoCallback = undoCallback; + if (undoCallback) +- notification.addAction(_("Undo"), this._onUndoClicked.bind(this)); ++ notification.addAction(_('Undo'), () => undoCallback()); -- Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { -+ this._laterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { - let newParent = this.actor.get_parent(); - if (!newParent) - return; + this._source.showNotification(notification); + } -- -2.33.1 +2.31.1 diff --git a/gdm-networking.patch b/gdm-networking.patch index 4f5e2fcbe036c428fb9ce700791b890c56fe593b..6bb33d7f12783273f9c13adc353dd3f0873937d9 100644 --- a/gdm-networking.patch +++ b/gdm-networking.patch @@ -1,4 +1,4 @@ -From ed0699886f49e5dd8d6ca9ffb60ba17cd76a810f Mon Sep 17 00:00:00 2001 +From 1eb9fef5e18d56bbe7a6422303ff8e31fe677759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Mon, 7 Jun 2021 17:49:57 +0200 Subject: [PATCH 1/5] status/network: Disable modem connection when windows @@ -12,10 +12,10 @@ failing silently, turn the item insensitive. 1 file changed, 12 insertions(+) diff --git a/js/ui/status/network.js b/js/ui/status/network.js -index b3bb7589c..3ad7b04dd 100644 +index 5487fde40..6e7878d20 100644 --- a/js/ui/status/network.js +++ b/js/ui/status/network.js -@@ -514,6 +514,10 @@ var NMDeviceModem = class extends NMConnectionDevice { +@@ -563,6 +563,10 @@ var NMDeviceModem = class extends NMConnectionDevice { this._iconChanged(); }); } @@ -26,8 +26,8 @@ index b3bb7589c..3ad7b04dd 100644 } get category() { -@@ -525,6 +529,10 @@ var NMDeviceModem = class extends NMConnectionDevice { - 'connect-3g', this._device.get_path()]); +@@ -573,6 +577,10 @@ var NMDeviceModem = class extends NMConnectionDevice { + launchSettingsPanel('network', 'connect-3g', this._device.get_path()); } + _sessionUpdated() { @@ -37,7 +37,7 @@ index b3bb7589c..3ad7b04dd 100644 destroy() { if (this._operatorNameId) { this._mobileDevice.disconnect(this._operatorNameId); -@@ -534,6 +542,10 @@ var NMDeviceModem = class extends NMConnectionDevice { +@@ -582,6 +590,10 @@ var NMDeviceModem = class extends NMConnectionDevice { this._mobileDevice.disconnect(this._signalQualityId); this._signalQualityId = 0; } @@ -52,7 +52,7 @@ index b3bb7589c..3ad7b04dd 100644 2.31.1 -From 59d52e1591e1522fff22320c657496ca978a7926 Mon Sep 17 00:00:00 2001 +From 0288558940c0090dca0873daeaa33e8d20cdbb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Mon, 7 Jun 2021 18:28:32 +0200 Subject: [PATCH 2/5] status/network: Only list wifi networks that can be @@ -62,34 +62,35 @@ Setting up a connection for an Enterprise WPA(2) encrypted wireless network requires Settings. That's not available when windows are disabled via the session mode, so filter out affected entries. --- - js/ui/status/network.js | 29 ++++++++++++++++++++++++++++- - 1 file changed, 28 insertions(+), 1 deletion(-) + js/ui/status/network.js | 30 +++++++++++++++++++++++++++++- + 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/js/ui/status/network.js b/js/ui/status/network.js -index 3ad7b04dd..c023022a7 100644 +index 6e7878d20..36915dbc1 100644 --- a/js/ui/status/network.js +++ b/js/ui/status/network.js -@@ -1,5 +1,5 @@ +@@ -1,6 +1,6 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + /* exported NMApplet */ -const { Clutter, Gio, GLib, GObject, NM, St } = imports.gi; +const { Clutter, Gio, GLib, GObject, Meta, NM, St } = imports.gi; - const Mainloop = imports.mainloop; const Signals = imports.signals; -@@ -751,6 +751,11 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog { + const Animation = imports.ui.animation; +@@ -816,6 +816,11 @@ class NMWirelessDialog extends ModalDialog.ModalDialog { + GLib.source_remove(this._scanTimeoutId); this._scanTimeoutId = 0; } - ++ + if (this._syncVisibilityId) { + Meta.later_remove(this._syncVisibilityId); + this._syncVisibilityId = 0; + } -+ - super.destroy(); } -@@ -1081,9 +1086,31 @@ var NMWirelessDialog = class extends ModalDialog.ModalDialog { - this._itemBox.insert_child_at_index(network.item.actor, newPos); + _onScanTimeout() { +@@ -1149,9 +1154,32 @@ class NMWirelessDialog extends ModalDialog.ModalDialog { + this._itemBox.insert_child_at_index(network.item, newPos); } + this._queueSyncItemVisibility(); @@ -113,6 +114,7 @@ index 3ad7b04dd..c023022a7 100644 + network.connections.length > 0 || + (firstAp._secType !== WPA2_ENT && firstAp._secType !== WPA_ENT); + } ++ this._syncVisibilityId = 0; + return GLib.SOURCE_REMOVE; + }); + } @@ -124,7 +126,7 @@ index 3ad7b04dd..c023022a7 100644 2.31.1 -From 9d204cdb38bcfee214dbe0b0bf9c2073dc50fe93 Mon Sep 17 00:00:00 2001 +From eb9620bc134ef8e7732f5e64b93ac9ea5bba2092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 8 Jun 2021 00:17:48 +0200 Subject: [PATCH 3/5] status/network: Consider network-control action @@ -134,37 +136,33 @@ be used to disallow network configuration, except that we happily ignore it. Add it to the conditions that turn a network section insensitive. --- - js/ui/status/network.js | 20 +++++++++++++++++--- - 1 file changed, 17 insertions(+), 3 deletions(-) + js/ui/status/network.js | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/js/ui/status/network.js b/js/ui/status/network.js -index c023022a7..79729e01b 100644 +index 36915dbc1..e238fdfe7 100644 --- a/js/ui/status/network.js +++ b/js/ui/status/network.js -@@ -1,5 +1,5 @@ +@@ -1,6 +1,6 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + /* exported NMApplet */ -const { Clutter, Gio, GLib, GObject, Meta, NM, St } = imports.gi; +const { Clutter, Gio, GLib, GObject, Meta, NM, Polkit, St } = imports.gi; - const Mainloop = imports.mainloop; const Signals = imports.signals; -@@ -1683,11 +1683,25 @@ var NMApplet = class extends PanelMenu.SystemIndicator { + const Animation = imports.ui.animation; +@@ -1750,11 +1750,21 @@ class Indicator extends PanelMenu.SystemIndicator { this._client.connect('connection-removed', this._connectionRemoved.bind(this)); Main.sessionMode.connect('updated', this._sessionUpdated.bind(this)); -- this._sessionUpdated(); -+ -+ this._configPermission = null; -+ Polkit.Permission.new( -+ 'org.freedesktop.NetworkManager.network-control', null, null, -+ (o, res) => { -+ try { -+ this._configPermission = Polkit.Permission.new_finish(res); -+ } catch (e) { -+ log('No permission to control network connections: %s'.format(e.toString())); -+ } -+ this._sessionUpdated(); -+ }); ++ try { ++ this._configPermission = await Polkit.Permission.new( ++ 'org.freedesktop.NetworkManager.network-control', null, null); ++ } catch (e) { ++ log('No permission to control network connections: %s'.format(e.toString())); ++ this._configPermission = null; ++ } + this._sessionUpdated(); } _sessionUpdated() { @@ -180,7 +178,7 @@ index c023022a7..79729e01b 100644 2.31.1 -From 7d2c8aabb86b9942c99ae9b7157dbffb875acde9 Mon Sep 17 00:00:00 2001 +From 2392810bb7e3d48fb33c4d6de39f5be2eca58988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 10 Jun 2021 23:12:27 +0200 Subject: [PATCH 4/5] sessionMode: Enable networkAgent on login screen @@ -193,10 +191,10 @@ requests (like wifi/VPN passwords). 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js -index 25aa75a3d..fa7f83416 100644 +index aa69fd115..4d4fb2444 100644 --- a/js/ui/sessionMode.js +++ b/js/ui/sessionMode.js -@@ -43,7 +43,9 @@ const _modes = { +@@ -47,7 +47,9 @@ const _modes = { isGreeter: true, isPrimary: true, unlockDialog: imports.gdm.loginDialog.LoginDialog, @@ -211,7 +209,7 @@ index 25aa75a3d..fa7f83416 100644 2.31.1 -From 07ce899bcb9d30991262d6c484508e6c5fa14c85 Mon Sep 17 00:00:00 2001 +From b5fedfd846f271bf28be02ce5cd8517af7a3bc0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 8 Jun 2021 00:19:26 +0200 Subject: [PATCH 5/5] status/network: Do not disable on login screen @@ -230,10 +228,10 @@ old behavior if desired. 1 file changed, 1 deletion(-) diff --git a/js/ui/status/network.js b/js/ui/status/network.js -index 79729e01b..914dbbd99 100644 +index e238fdfe7..f510f90ae 100644 --- a/js/ui/status/network.js +++ b/js/ui/status/network.js -@@ -1700,7 +1700,6 @@ var NMApplet = class extends PanelMenu.SystemIndicator { +@@ -1763,7 +1763,6 @@ class Indicator extends PanelMenu.SystemIndicator { _sessionUpdated() { const sensitive = !Main.sessionMode.isLocked && diff --git a/gnome-shell-enabled-extensions-background-logos.patch b/gnome-shell-enabled-extensions-background-logos.patch new file mode 100644 index 0000000000000000000000000000000000000000..c511c66793ebec4a5286ae7fe241423043089a8d --- /dev/null +++ b/gnome-shell-enabled-extensions-background-logos.patch @@ -0,0 +1,67 @@ +From 1f8252470ce43dc8a0680871013e2f4492764302 Mon Sep 17 00:00:00 2001 +From: 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 @@ + + + + true + + Enable internal tools useful for developers and testers from Alt-F2 + + + Allows access to internal debugging and monitoring tools + using the Alt-F2 dialog. + + + +- [] ++ ['background-logo@fedorahosted.org'] + UUIDs of extensions to enable + + 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. + + + + [] + UUIDs of extensions to force disabling + + 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. + + + + false + Disable user extensions + + Disable all extensions the user has enabled without affecting + the “enabled-extension” setting. + + + + false + Disables the validation of extension version compatibility +-- +2.35.1 + diff --git a/gnome-shell-favourite-apps-firefox.patch b/gnome-shell-favourite-apps-firefox.patch index 888491ea0d7c7826ce4d050059bb7848f2a8a506..fba63ae9c47a1e10d97fe066e94ef0b1148ef35b 100644 --- a/gnome-shell-favourite-apps-firefox.patch +++ b/gnome-shell-favourite-apps-firefox.patch @@ -1,7 +1,7 @@ -From 87104647f061892525236a71f304b63609960626 Mon Sep 17 00:00:00 2001 +From a2e62e671260576d23f18c22c10a48ac4a8504af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Thu, 9 Mar 2017 14:43:30 +0100 -Subject: [PATCH] appFavorites: Make firefox the default browser +Date: Wed, 17 Sep 2014 07:11:12 +0200 +Subject: [PATCH] Replace Web with Firefox in default favorites --- data/org.gnome.shell.gschema.xml.in | 2 +- @@ -9,23 +9,23 @@ Subject: [PATCH] appFavorites: Make firefox the default browser 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in -index 24e2a75b0..2f50036d0 100644 +index cd6a2356d..b8a13a9cc 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 @@ -- [ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ] -+ [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ] +- [ 'org.gnome.Epiphany.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ] ++ [ 'firefox.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ] List of desktop file IDs for favorite applications The applications corresponding to these identifiers diff --git a/js/ui/appFavorites.js b/js/ui/appFavorites.js -index 657e15965..1e44a1655 100644 +index a876727ed..24ce16f81 100644 --- a/js/ui/appFavorites.js +++ b/js/ui/appFavorites.js -@@ -49,6 +49,7 @@ const RENAMED_DESKTOP_IDS = { +@@ -52,6 +52,7 @@ const RENAMED_DESKTOP_IDS = { 'gnotski.desktop': 'org.gnome.Klotski.desktop', 'gtali.desktop': 'org.gnome.Tali.desktop', 'iagno.desktop': 'org.gnome.Reversi.desktop', @@ -34,5 +34,5 @@ index 657e15965..1e44a1655 100644 'org.gnome.gnome-2048.desktop': 'org.gnome.TwentyFortyEight.desktop', 'org.gnome.taquin.desktop': 'org.gnome.Taquin.desktop', -- -2.21.0 +2.30.1 diff --git a/gnome-shell-favourite-apps-terminal.patch b/gnome-shell-favourite-apps-terminal.patch index d3f0377944c1080fabdddff4e1940a2f9a0461a4..5f7207a6f59a3c00b6e4fe272e3c999a5ea6ac56 100644 --- a/gnome-shell-favourite-apps-terminal.patch +++ b/gnome-shell-favourite-apps-terminal.patch @@ -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?= 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 @@ -- [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop' ] -+ [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop', 'gnome-terminal.desktop' ] +- [ 'firefox.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop' ] ++ [ 'firefox.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop', 'org.gnome.Terminal.desktop' ] List of desktop file IDs for favorite applications The applications corresponding to these identifiers -- -2.21.0 +2.31.1 diff --git a/gnome-shell-favourite-apps-yelp.patch b/gnome-shell-favourite-apps-yelp.patch index d96597a7ef0d960cd350f5e92481ee3247066e66..f47dab87284a36507a8454e7d2a12f6f2a357e11 100644 --- a/gnome-shell-favourite-apps-yelp.patch +++ b/gnome-shell-favourite-apps-yelp.patch @@ -1,7 +1,7 @@ -From 53eba56c29c2c3f25bdfc4b73d1b9ce74ce2504b Mon Sep 17 00:00:00 2001 +From 4e21aed64d48ddd22e40a3605084379b2fa7f1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 9 Mar 2017 14:44:03 +0100 -Subject: [PATCH] Add 'yelp' to default favorites +Subject: [PATCH 2/3] Add 'yelp' to default favorites Help should be easily available, so add it to the default favorites. --- @@ -9,18 +9,18 @@ Help should be easily available, so add it to the default favorites. 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in -index 2f50036d0..40526187e 100644 +index b8a13a9cc..35ddaf4a9 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 @@ -- [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ] -+ [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop' ] +- [ 'firefox.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ] ++ [ 'firefox.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop' ] List of desktop file IDs for favorite applications The applications corresponding to these identifiers -- -2.21.0 +2.31.1 diff --git a/gnome-shell.spec b/gnome-shell.spec index a98ccbd95c3f42aef1bdab9d77c83a3a8bb994e9..d77e201ad6d8c0d02796dcca99d2839a321ad614 100644 --- a/gnome-shell.spec +++ b/gnome-shell.spec @@ -1,119 +1,70 @@ %define anolis_release .0.1 +%global tarball_version %%(echo %{version} | tr '~' '.') + Name: gnome-shell -Version: 3.32.2 -Release: 44%{anolis_release}%{?dist} +Version: 40.10 +Release: 3%{anolis_release}%{?dist} Summary: Window management and application launching for GNOME -Group: User Interface/Desktops License: GPLv2+ -Provides: desktop-notification-daemon URL: https://wiki.gnome.org/Projects/GnomeShell -#VCS: git:git://git.gnome.org/gnome-shell -Source0: http://download.gnome.org/sources/gnome-shell/3.32/%{name}-%{version}.tar.xz +Source0: http://download.gnome.org/sources/gnome-shell/40/%{name}-%{tarball_version}.tar.xz + +Recommends: gnome-shell-extension-background-logo -# Replace Epiphany with Firefox in the default favourite apps list +# Replace Epiphany with Firefox in the default favourite apps list, etc +# and enable background extension by default Patch1: gnome-shell-favourite-apps-firefox.patch Patch2: gnome-shell-favourite-apps-yelp.patch Patch3: gnome-shell-favourite-apps-terminal.patch +Patch4: gnome-shell-enabled-extensions-background-logos.patch # GDM/Lock stuff -Patch12: 0001-screenShield-unblank-when-inserting-smartcard.patch -Patch13: enforce-smartcard-at-unlock.patch -Patch14: disable-unlock-entry-until-question.patch -Patch15: allow-timed-login-with-no-user-list.patch -Patch16: 0001-data-install-process-working.svg-to-filesystem.patch -Patch17: 0001-loginDialog-make-info-messages-themed.patch -Patch18: 0001-gdm-add-AuthList-control.patch -Patch19: 0002-gdmUtil-enable-support-for-GDM-s-ChoiceList-PAM-exte.patch -Patch20: wake-up-on-deactivate.patch -Patch21: caps-lock-warning.patch -Patch22: gdm-networking.patch -Patch23: 0001-shellEntry-Disconnect-handler-on-destroy.patch -Patch24: fix-login-lock-screen.patch -Patch25: 0001-shellEntry-Determine-if-password-entry-from-content-.patch -Patch26: 0002-shellEntry-Give-password-menu-item-text-when-it-s-cr.patch -Patch27: 0003-shellEntry-Handle-password-item-from-dedication-func.patch -Patch28: 0004-shellEntry-Support-lockdown-of-Show-Text-menu-in-pas.patch -Patch29: 0005-shellEntry-Only-mask-text-in-password-entries.patch +Patch10: 0001-screenShield-unblank-when-inserting-smartcard.patch +Patch11: enforce-smartcard-at-unlock.patch +Patch12: disable-unlock-entry-until-question.patch +Patch13: 0001-loginDialog-make-info-messages-themed.patch +Patch14: support-choicelist-extension.patch +Patch15: gdm-networking.patch +Patch16: login-screen-extensions.patch # Misc. -Patch30: 0001-shellDBus-Add-a-DBus-method-to-load-a-single-extensi.patch -Patch31: 0001-extensions-Add-a-SESSION_MODE-extension-type.patch -Patch32: extension-updates.patch -Patch33: 0001-panel-add-an-icon-to-the-ActivitiesButton.patch -Patch34: 0001-app-Fall-back-to-window-title-instead-of-WM_CLASS.patch -Patch35: 0001-windowMenu-Bring-back-workspaces-submenu-for-static-.patch -Patch36: 0001-shell-app-Handle-workspace-from-startup-notification.patch -Patch37: 0001-main-Dump-stack-on-segfaults-by-default.patch -Patch38: 0001-appDisplay-Show-full-app-name-on-hover.patch -Patch39: horizontal-workspace-support.patch -Patch40: 0001-animation-fix-unintentional-loop-while-polkit-dialog.patch -Patch41: 0001-workspacesView-Work-around-spurious-allocation-chang.patch -Patch42: 0001-layout-Make-the-hot-corner-optional.patch -Patch43: fix-app-view-leaks.patch -Patch44: root-warning.patch -Patch45: 0001-workspace-Pass-device-to-startDrag.patch -Patch46: 0001-a11y-Change-HC-icon-theme-first.patch -Patch47: perf-tool-wayland.patch -Patch48: 0001-padOsd-Re-query-action-labels-after-mode-switches.patch -Patch49: 0001-Do-not-change-Wacom-LEDs-through-g-s-d.patch -Patch50: 0001-st-texture-cache-Cancel-pending-requests-on-icon-the.patch -Patch51: introspect-backports.patch -Patch52: 0001-popupMenu-Handle-keypress-if-numlock-is-enabled.patch -Patch53: 0001-theme-Update-window-preview-style.patch -Patch54: warn-less.patch -Patch55: 0001-networkAgent-add-support-for-SAE-secrets.patch - -# Backport JS invalid access warnings (#1651894, #1663171, #1642482, #1637622) -Patch57: fix-invalid-access-warnings.patch -Patch58: more-spurious-allocation-warnings.patch -Patch59: fix-some-js-warnings.patch - -# Backport performance fixes under load (#1820760) -Patch60: 0001-environment-reduce-calls-to-g_time_zone_new_local.patch -Patch61: 0002-environment-Fix-date-conversion.patch -Patch62: 0003-shell-app-system-Monitor-for-icon-theme-changes.patch -Patch63: 0004-global-force-fsync-to-worker-thread-when-saving-stat.patch -Patch64: 0005-app-cache-add-ShellAppCache-for-GAppInfo-caching.patch -Patch65: 0006-js-Always-use-AppSystem-to-lookup-apps.patch -Patch66: 0007-gnome-shell-anolis-international-modification.patch - -# Stop screen recording on monitor changes (#1705392) -Patch70: 0001-screencast-Stop-recording-when-screen-size-or-resour.patch - -# Backport OSK fixes (#1871041) -Patch75: osk-fixes.patch -Patch76: 0001-keyboard-Only-enable-keyboard-if-ClutterDeviceManage.patch - -# suspend/resume fix on nvidia (#1663440) -Patch10001: 0001-background-refresh-after-suspend-on-wayland.patch -Patch10002: 0002-background-rebuild-background-not-just-animation-on-.patch -Patch10003: 0003-st-texture-cache-purge-on-resume.patch -Patch10004: 0004-background-refresh-background-on-gl-video-memory-pur.patch - -# Allow login screen extensions (#1651378) -Patch20001: 0001-extensionSystem-Handle-added-or-removed-sessionMode-.patch -Patch20002: 0002-extensionSystem-Get-rid-of-_enabled-boolean-optimiza.patch -Patch20003: 0003-extensionSystem-Allow-extensions-to-run-on-the-login.patch -Patch20004: 0004-sessionMode-Allow-extensions-at-the-login-and-unlock.patch - -# CVE-2020-17489 -Patch30001: 0001-loginDialog-Reset-auth-prompt-on-vt-switch-before-fa.patch - -%define libcroco_version 0.6.8 -%define eds_version 3.17.2 -%define gnome_desktop_version 3.7.90 +Patch30: 0001-panel-add-an-icon-to-the-ActivitiesButton.patch +Patch31: 0001-app-Fall-back-to-window-title-instead-of-WM_CLASS.patch +Patch32: 0001-windowMenu-Bring-back-workspaces-submenu-for-static-.patch +Patch33: 0001-main-Dump-stack-on-segfaults-by-default.patch +Patch34: 0001-extensionDownloader-Refuse-to-override-system-extens.patch +Patch35: fix-some-js-warnings.patch +Patch36: 0001-st-texture-cache-purge-on-resume.patch +Patch37: 0001-Update-generated-stylesheets.patch +Patch38: add-power-profiles-menu.patch +Patch39: 0001-status-network-Use-wwan-settings-panel-for-GSM-LTE-M.patch +Patch40: 0001-welcomeDialog-Adapt-dialog-title.patch +Patch41: 0001-main-Leak-the-GJS-context-and-ShellGlobal.patch +Patch42: fix-markup-in-highlighter.patch +Patch43: restrict-dbus-callers.patch +Patch44: 0001-Revert-dash-Subtract-vertical-margins-from-availHeig.patch +Patch45: 0001-status-volume-Hide-sliders-initially.patch +Patch46: 0001-kbdA11yDialog-Use-MetaKeyboardA11yFlags.patch + +%define eds_version 3.33.1 +%define gnome_desktop_version 3.35.91 %define glib2_version 2.56.0 %define gobject_introspection_version 1.49.1 -%define gjs_version 1.54.0 +%define gjs_version 1.57.3 %define gtk3_version 3.15.0 -%define mutter_version 3.32.2-57 +%define gtk4_version 4.0.0 +%define mutter_version 40.0~alpha.1.1 %define polkit_version 0.100 -%define gsettings_desktop_schemas_version 3.32.0-6 +%define gsettings_desktop_schemas_version 40~alpha %define ibus_version 1.5.2 %define gnome_bluetooth_version 1:3.9.0 %define gstreamer_version 1.4.5 +%define pipewire_version 0.3.0 +%define gnome_settings_daemon_version 3.37.1 +%define libgweather_version 40~alpha +BuildRequires: bash-completion BuildRequires: gcc BuildRequires: meson BuildRequires: git @@ -124,21 +75,22 @@ BuildRequires: evolution-data-server-devel >= %{eds_version} BuildRequires: gcr-devel BuildRequires: gjs-devel >= %{gjs_version} BuildRequires: glib2-devel >= %{glib2_version} +BuildRequires: gnome-autoar-devel +BuildRequires: pkgconfig(gnome-desktop-3.0) BuildRequires: gobject-introspection >= %{gobject_introspection_version} BuildRequires: mesa-libGL-devel BuildRequires: mesa-libEGL-devel BuildRequires: NetworkManager-libnm-devel BuildRequires: polkit-devel >= %{polkit_version} BuildRequires: startup-notification-devel -# for theme generation -BuildRequires: sassc +BuildRequires: systemd-devel # for screencast recorder functionality BuildRequires: gstreamer1-devel >= %{gstreamer_version} +BuildRequires: pkgconfig(libpipewire-0.3) >= %{pipewire_version} BuildRequires: gtk3-devel >= %{gtk3_version} +BuildRequires: gtk4-devel >= %{gtk4_version} BuildRequires: gettext >= 0.19.6 BuildRequires: libcanberra-devel -BuildRequires: libcroco-devel >= %{libcroco_version} -BuildRequires: pkgconfig(libsystemd) BuildRequires: python3 # for barriers @@ -150,7 +102,6 @@ BuildRequires: pulseaudio-libs-devel %ifnarch s390 s390x ppc ppc64 ppc64p7 BuildRequires: gnome-bluetooth-libs-devel >= %{gnome_bluetooth_version} %endif -#BuildRequires: control-center # Bootstrap requirements BuildRequires: gtk-doc %ifnarch s390 s390x @@ -159,13 +110,15 @@ Requires: gnome-bluetooth%{?_isa} >= %{gnome_bluetooth_version} Requires: gnome-desktop3%{?_isa} >= %{gnome_desktop_version} %if 0%{?rhel} != 7 # Disabled on RHEL 7 to allow logging into KDE session by default -Requires: gnome-session-xsession +Recommends: gnome-session-xsession %endif # wrapper script uses to restart old GNOME session if run --replace # from the command line Requires: gobject-introspection%{?_isa} >= %{gobject_introspection_version} Requires: gjs%{?_isa} >= %{gjs_version} Requires: gtk3%{?_isa} >= %{gtk3_version} +Requires: gtk4%{?_isa} >= %{gtk4_version} +Requires: highcontrast-icon-theme Requires: libnma%{?_isa} # needed for loading SVG's via gdk-pixbuf Requires: librsvg2%{?_isa} @@ -175,12 +128,18 @@ Requires: polkit%{?_isa} >= %{polkit_version} Requires: gnome-desktop3%{?_isa} >= %{gnome_desktop_version} Requires: glib2%{?_isa} >= %{glib2_version} Requires: gsettings-desktop-schemas%{?_isa} >= %{gsettings_desktop_schemas_version} -Requires: libcroco%{?_isa} >= %{libcroco_version} +Requires: gnome-settings-daemon%{?_isa} >= %{gnome_settings_daemon_version} Requires: gstreamer1%{?_isa} >= %{gstreamer_version} +# needed for screen recorder +Requires: gstreamer1-plugins-good%{?_isa} +Requires: pipewire-gstreamer%{?_isa} +Requires: xdg-user-dirs-gtk # needed for schemas Requires: at-spi2-atk%{?_isa} # needed for on-screen keyboard Requires: ibus%{?_isa} >= %{ibus_version} +# needed for "show keyboard layout" +Requires: libgnomekbd # needed for the user menu Requires: accountsservice-libs%{?_isa} Requires: gdm-libs%{?_isa} @@ -192,13 +151,34 @@ Requires: python3%{_isa} Requires: switcheroo-control # needed for clocks/weather integration Requires: geoclue2-libs%{?_isa} -Requires: libgweather%{?_isa} +Requires: libgweather%{?_isa} >= %{libgweather_version} # needed for thunderbolt support Requires: bolt%{?_isa} # Needed for launching flatpak apps etc -Requires: xdg-desktop-portal-gtk +# 1.8.0 is needed for source type support in the screencast portal. +Requires: xdg-desktop-portal-gtk >= 1.8.0 +# needed by the welcome dialog +Recommends: gnome-tour +Provides: desktop-notification-daemon = %{version}-%{release} Provides: PolicyKit-authentication-agent = %{version}-%{release} +Provides: bundled(gvc) +Provides: bundled(libcroco) = 0.6.13 + +%if 0%{?rhel} +# In Fedora, fedora-obsolete-packages obsoletes caribou +Obsoletes: caribou < 0.4.21-10 +Obsoletes: caribou-antler < 0.4.21-10 +Obsoletes: caribou-devel < 0.4.21-10 +Obsoletes: caribou-gtk2-module < 0.4.21-10 +Obsoletes: caribou-gtk3-module < 0.4.21-10 +Obsoletes: python-caribou < 0.4.21-10 +Obsoletes: python2-caribou < 0.4.21-10 +Obsoletes: python3-caribou < 0.4.21-10 +%endif + +# https://bugzilla.redhat.com/show_bug.cgi?id=1740897 +Conflicts: gnome-shell-extension-background-logo < 3.34.0 %description GNOME Shell provides core user interface functions for the GNOME 3 desktop, @@ -208,10 +188,10 @@ innovative user interface concepts to provide a visually attractive and easy to use experience. %prep -%autosetup -S git +%autosetup -S git -n %{name}-%{tarball_version} %build -%meson +%meson -Dextensions_app=false %meson_build %install @@ -225,27 +205,32 @@ mkdir -p %{buildroot}%{_datadir}/gnome-shell/search-providers %check desktop-file-validate %{buildroot}%{_datadir}/applications/org.gnome.Shell.desktop -desktop-file-validate %{buildroot}%{_datadir}/applications/gnome-shell-extension-prefs.desktop desktop-file-validate %{buildroot}%{_datadir}/applications/evolution-calendar.desktop %files -f %{name}.lang %license COPYING %doc README.md %{_bindir}/gnome-shell +%{_bindir}/gnome-extensions +%{_bindir}/gnome-shell-extension-prefs %{_bindir}/gnome-shell-extension-tool %{_bindir}/gnome-shell-perf-tool -%{_bindir}/gnome-shell-extension-prefs %{_datadir}/glib-2.0/schemas/*.xml %{_datadir}/glib-2.0/schemas/00_org.gnome.shell.gschema.override +%{_datadir}/applications/org.gnome.Shell.Extensions.desktop %{_datadir}/applications/org.gnome.Shell.desktop -%{_datadir}/applications/gnome-shell-extension-prefs.desktop %{_datadir}/applications/evolution-calendar.desktop %{_datadir}/applications/org.gnome.Shell.PortalHelper.desktop +%{_datadir}/bash-completion/completions/gnome-extensions %{_datadir}/gnome-control-center/keybindings/50-gnome-shell-system.xml %{_datadir}/gnome-shell/ +%{_datadir}/dbus-1/services/org.gnome.ScreenSaver.service %{_datadir}/dbus-1/services/org.gnome.Shell.CalendarServer.service +%{_datadir}/dbus-1/services/org.gnome.Shell.Extensions.service %{_datadir}/dbus-1/services/org.gnome.Shell.HotplugSniffer.service +%{_datadir}/dbus-1/services/org.gnome.Shell.Notifications.service %{_datadir}/dbus-1/services/org.gnome.Shell.PortalHelper.service +%{_datadir}/dbus-1/services/org.gnome.Shell.Screencast.service %{_datadir}/dbus-1/interfaces/org.gnome.Shell.Extensions.xml %{_datadir}/dbus-1/interfaces/org.gnome.Shell.Introspect.xml %{_datadir}/dbus-1/interfaces/org.gnome.Shell.PadOsd.xml @@ -253,11 +238,12 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/evolution-calendar.de %{_datadir}/dbus-1/interfaces/org.gnome.Shell.Screenshot.xml %{_datadir}/dbus-1/interfaces/org.gnome.ShellSearchProvider.xml %{_datadir}/dbus-1/interfaces/org.gnome.ShellSearchProvider2.xml -%{_datadir}/icons/hicolor/scalable/apps/org.gnome.Extensions.svg -%{_datadir}/icons/hicolor/symbolic/apps/org.gnome.Extensions-symbolic.svg -%{_userunitdir}/gnome-shell.service -%{_userunitdir}/gnome-shell-wayland.target -%{_userunitdir}/gnome-shell-x11.target +%{_datadir}/icons/hicolor/scalable/apps/org.gnome.Shell.Extensions.svg +%{_datadir}/icons/hicolor/symbolic/apps/org.gnome.Shell.Extensions-symbolic.svg +%{_userunitdir}/org.gnome.Shell-disable-extensions.service +%{_userunitdir}/org.gnome.Shell.target +%{_userunitdir}/org.gnome.Shell@wayland.service +%{_userunitdir}/org.gnome.Shell@x11.service %{_sysconfdir}/xdg/autostart/gnome-shell-overrides-migration.desktop # Co own directory instead of pulling in xdg-desktop-portal - we # are providing a backend to the portal, not depending on it @@ -274,248 +260,469 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/evolution-calendar.de %dir %{_datadir}/GConf %dir %{_datadir}/GConf/gsettings %{_datadir}/GConf/gsettings/gnome-shell-overrides.convert -%{_mandir}/man1/%{name}.1.gz +%{_mandir}/man1/gnome-extensions.1* +%{_mandir}/man1/gnome-shell.1* %changelog -* Tue Apr 26 2022 pangqing - 3.32.2-44.0.1 +* Wed May 17 2023 pangqing - 40.10-3.0.1 - International modification -* Fri Nov 26 2021 Florian Müllner - 3.32.2-44 -- Fix more JS warnings - Resolves: #2025940 +* Mon Jun 20 2022 Florian Müllner - 40.10-3 +- Fix keyboard a11y confirmation dialog + Resolves: #2047644 + +* Wed May 11 2022 Florian Müllner - 40.10-2 +- Hide volume sliders initially + Related: #2052808 + +* Tue Apr 19 2022 Florian Müllner - 40.10-1 +- Update to 40.10 + Related: #2066169 + +* Tue Apr 05 2022 Florian Müllner - 40.9-5 +- Keep new ShimMetaContext type private + Related: #2055366 + +* Fri Apr 01 2022 Florian Müllner - 40.9-4 +- Restrict D-Bus callers + Resolves: #2055366 + +* Wed Mar 30 2022 Florian Müllner - 40.9-3 +- Fix markup handling in highlighter + Resolves: #2049194 +- Fix warning on restacking + Resolves: #2053638 + +* Mon Feb 28 2022 Ray Strode - 40.9-2 +- Depend on and use background extension + Related: #2057150 + +* Tue Feb 22 2022 Florian Müllner - 40.9-1 +- Update to 40.9 + Resolves: #2056411 + +* Tue Feb 08 2022 Ray Strode - 40.8-3 +- Backport latest, working, version of ChoiceList extension +- Regenerate stylesheet patch + Related: #1993954 + +* Thu Jan 27 2022 Florian Müllner - 40.8-2 +- Do not hardcode OS name in welcome dialog + Resolves: #2044040 + +* Mon Jan 17 2022 Florian Müllner - 40.8-1 +- Update to 40.8 + Resolves: #2040061 + +* Mon Dec 13 2021 Florian Müllner - 40.7-1 +- Update to 40.7 + Resolves: #2031655 + +* Thu Nov 04 2021 Florian Müllner - 40.6-1 +- Update to 40.6 +- Work around crashy tear down + Resolves: #2008065 + +* Wed Oct 27 2021 Florian Müllner - 40.4-5 +- Adapt welcome dialog title + Resolves: #2013989 + +* Wed Oct 13 2021 Ray Strode - 40.4-4 +- Ensure extensions are reenabled after unlock + Resolves: #2013801 + +* Mon Sep 27 2021 Ray Strode - 40.4-3 +- Allow extensions at the login screen + Related: #2006985 + +* Thu Aug 19 2021 Florian Müllner - 40.4-2 +- Use wwan setting panel for GSM/LTE modems + Resolves: #1995560 + +* Wed Aug 18 2021 Florian Müllner - 40.4-1 +- Update to 40.4 + Resolves: #1995094 + +* Wed Aug 18 2021 Florian Müllner - 40.3-4 +- Add power profiles menu + Resolves: #1994471 + +* Mon Aug 09 2021 Mohan Boddu - 40.3-3 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags + Related: rhbz#1991688 + +* Mon Aug 09 2021 Florian Müllner - 40.3-2 +- Avoid a gjs warning + Resolves: #1990821 + +* Mon Jul 12 2021 Florian Müllner - 40.3-1 +- Update to 40.3 + Resolves: #1979143 +- Fix some more JS warnings + Resolves: #1980414 + +* Tue Jun 15 2021 Florian Müllner - 40.2-1 +- Update to 40.2-1 + Resolves: #1971432 + +* Fri Jun 04 2021 Florian Müllner - 40.1-5 +- Don't set CAP_SYS_NICE + Resolves: #1967973 + +* Wed Jun 02 2021 Florian Müllner - 40.1-4 +- Fix regression in AuthList rebase + Resolves: #1966841 + +* Thu May 27 2021 Florian Müllner - 40.1-3 +- Update generated stylesheets + Resolves: #1965327 + +* Wed May 19 2021 Florian Müllner - 40.1-2 +- Re-apply RHEL8 downstream patches that are still valid + Resolves: #1949133 + +* Fri May 14 2021 Florian Müllner - 40.1-1 +- Update to 40.1 + Resolves: #1951132 + +* Fri Apr 30 2021 Kalev Lember - 40.0-4 +- Move gnome-tour dep here from gnome-initial-setup (#1955179) + +* Thu Apr 15 2021 Mohan Boddu - 40.0-3 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 -* Thu Oct 21 2021 Florian Müllner - 3.32.2-43 -- Backport fix for CVE-2020-17489 - Resolves: #1874259 +* Tue Apr 13 2021 Ray Strode - 40.0-2 +- Fix timed login when user list is disabled + Resolves: #1940618 -* Wed Oct 20 2021 Florian Müllner - 3.32.2-42 -- Backport WPA3 support - Resolves: #1924593 +* Sat Mar 20 2021 Florian Müllner - 40.0-1 +- Update to 40.0 -* Tue Aug 31 2021 Ray Strode - 3.32.2-41 -- Add bugs introduced in backport for #1651378 - Related: #2000918 -- Tidy up patch list a bit +* Mon Mar 15 2021 Florian Müllner - 40.0~rc-1 +- Update to 40.rc -* Wed Aug 25 2021 Ray Strode - 3.32.2-39 -- Allow extensions on the login screen - Related: #1651378 +* Thu Mar 11 2021 Kalev Lember - 40.0~beta-4.20210304git7a57528bd +- Recommend gnome-session-xsession rather than hard-require it -* Thu Jul 29 2021 Florian Müllner - 3.32.2-38 -- Only mask text in password entries - Resolves: #1987233 +* Mon Mar 08 2021 Florian Müllner - 40.0~beta-3.20210304git40.7a57528bd +- Fix crash after launching apps via drag-and-drop -* Wed Jul 28 2021 Florian Müllner - 3.32.2-37 -- Only warn once when not running under GDM - Resolves: #1980661 +* Thu Mar 04 2021 Florian Müllner - 40.0~beta-2.20210304git40.7a57528bd +- Build snapshot of current upstream -* Tue Jul 20 2021 Ray Strode - 3.32.2-36 -- Add ability to lock down password showing - Resolves: #1770302 -- Add requires on newer mutter version - Related: #1937866 +* Tue Feb 23 2021 Florian Müllner - 40.0~beta-1 +- Update to 40.beta -* Tue Jul 13 2021 Florian Müllner - 3.32.2-35 -- Improve style of window preview close buttons - Resolves: #1981420 +* Mon Feb 22 2021 Kalev Lember - 40.0~alpha.1.1-9.20210212git829a096ba +- Add missing requires on gstreamer1-plugins-good and xdg-user-dirs-gtk (#1931342) -* Mon Jul 12 2021 Florian Müllner - 3.32.2-34 +* Sun Feb 14 2021 Florian Müllner - 40.0~alpha.1.1-8.20210212git829a096ba +- Only open app picker on left-click/touch + +* Sun Feb 14 2021 Florian Müllner - 40.0~alpha.1.1-7.20210212git829a096ba +- Don't open app picker when clicking minimap + +* Fri Feb 12 2021 Florian Müllner - 40.0~alpha.1.1-6.20210212git829a096ba +- Update snapshot to current upstream +- Allow opening app picker by clicking overview background + +* Fri Feb 12 2021 Milan Crha - 40.0~alpha.1.1-5.20210202git9ce666ac1 +- Rebuilt for evolution-data-server soname version bump + +* Tue Feb 02 2021 Florian Müllner - 40.0~alpha.1.1-4.20210202git9ce666ac1 +- Build snapshot of current upstream + +* Tue Jan 26 2021 Fedora Release Engineering - 40.0~alpha.1.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Tue Jan 19 2021 Kalev Lember - 40.0~alpha.1.1-2 +- Require libgweather >= 40~alpha for new application_id property + +* Mon Jan 18 2021 Florian Müllner - 40.alpha.1.1-1 +- Update to 40.alpha.1.1 + +* Fri Jan 15 2021 Florian Müllner - 40.alpha.1-1 +- Update to 40.alpha.1 + +* Wed Dec 02 2020 Florian Müllner - 40.alpha-1 +- Update to 40.alpha + +* Tue Oct 13 2020 Florian Müllner - 3.38.1-2 +- Fix crash on size change (non-)transitions + +* Mon Oct 05 2020 Florian Müllner - 3.38.1-1 +- Update to 3.38.1 + +* Tue Sep 29 2020 David King - 3.38.0-2 +- Better specify xdg-desktop-portal-gtk dependency (#1882894) + +* Mon Sep 14 2020 Florian Müllner - 3.38.0-1 +- Update to 3.38.0 + +* Thu Sep 10 2020 Kalev Lember - 3.37.92-5 +- Set minimum gnome-settings-daemon version for Screencast proxy changes + +* Wed Sep 09 2020 Kalev Lember - 3.37.92-4 +- Add missing pipewire-gstreamer dependency for screen recorder + +* Sun Sep 06 2020 Florian Müllner - 3.37.92-1 +- Update to 3.37.92 + +* Wed Sep 02 2020 Florian Müllner - 3.37.91-3 +- Add missing pipewire dependency for screen recorder + +* Wed Aug 26 2020 Kalev Lember - 3.37.91-2 - Add PolicyKit-authentication-agent virtual provides - Resolves: #1978287 - -* Mon Jun 14 2021 Florian Müllner - 3.32.2-33 -- Fix warnings on unlock - Resolves: #1971534 -- Fix gdm lock screen - Resolves: #1971507 - -* Thu Jun 10 2021 Florian Müllner - 3.32.2-32 -- Fix network secret requests on login screen - Related: #1935261 - -* Wed Jun 09 2021 Florian Müllner - 3.32.2-31 -- Backport of touch mode - Resolves: #1937866 - -* Tue Jun 08 2021 Florian Müllner - 3.32.2-30 -- Do not disable network actions on login screen - Resolves: #1935261 - -* Mon Feb 01 2021 Florian Müllner - 3.32.2-29 -- Refuse to override system extensions - Related: #1802105 - -* Mon Jan 25 2021 Florian Müllner - 3.32.2-28 -- Backport extension updates support - Related: #1802105 - -* Thu Jan 14 2021 Florian Müllner - 3.32.2-27 -- Default to printing JS backtrace on segfaults - Resolves: #1883868 - -* Wed Jan 13 2021 Carlos Garnacho - 3.32.2-26 -- Backport OSK fixes - Resolves: #1871041 - -* Tue Jan 12 2021 Jonas Ådahl - 3.32.2-25 -- Stop screen recording on monitor changes - Resolves: #1705392 - -* Thu Jan 07 2021 Florian Müllner - 3.32.2-24 -- Handle workspace from startup notification - Resolves: #1671761 - -* Tue Jan 05 2021 Florian Müllner - 3.32.2-23 -- Work around aggressive garbage collection - Related: #1881312 - -* Fri Oct 23 2020 Florian Müllner - 3.32.2-22 -- Wake up lock screen when deactivated programmatically - Resolves: #1854290 -- Backport better caps-lock warning - Resolves: #1861357 -- Fix more (harmless) JS warnings - Resolves: #1881312 - -* Thu Oct 01 2020 Michael Catanzaro - 3.32.2-21 -- Fix JS warning in AuthList downstream patch - Resolves: #1860946 - -* Thu Jul 30 2020 Florian Müllner - 3.32.2-20 -- Fix popupMenu keynav when NumLock is active - Resolves: #1840080 - -* Mon Jun 15 2020 Florian Müllner - 3.32.2-19 -- Fix last backport - Resolves: #1847051 - -* Sun Jun 14 2020 Florian Müllner - 3.32.2-18 -- Fix more spurious allocation warnings - Resolves: #1715845 - -* Fri May 22 2020 Florian Müllner - 3.32.2-17 -- Really allow using perf-tool on wayland - Resolves: #1652178 -- Fix timed login without user list - Resolves: #1668895 -- Fix HighContrast/symbolic icon mixup - Resolves: #1794045 -- Backport introspect API changes - Resolves: #1837413 - -* Fri Apr 17 2020 Florian Müllner - 3.32.2-16 -- Drop bad upstream patch - Resolves: #1820760 - -* Wed Apr 08 2020 Florian Müllner - 3.32.2-15 -- Improve performance under load - Resolves: #1820760 - -* Wed Mar 04 2020 Carlos Garnacho - 3.32.2-14 -- Do not set Wacom LEDs through gnome-settings-daemon, rely on kernel driver - Resolves: #1687979 - -* Mon Dec 16 2019 Carlos Garnacho - 3.32.2-13 -- Update pad OSD on mode switching - Resolves: #1716774 - -* Fri Dec 13 2019 Carlos Garnacho - 3.32.2-12 -- Fix window dragging with tablets in the overview - Resolves: #1716767 -- Fix high-contrast/symbolic race - Resolves: #1730612 -- Make perf-tool usable on wayland - Resolves: #1652178 - -* Mon Dec 02 2019 Florian Müllner - 3.32.2-11 -- Warn when logging in as root - Resolves: #1746327 - -* Wed Nov 27 2019 Florian Müllner - 3.32.2-10 -- Fix leaks in app picker - Related: #1719819 - -* Thu Aug 15 2019 Jonas Ådahl - 3.32.2-9 -- Depend on correct gsettings-desktop-schemas version - Related: #1704355 - -* Wed Aug 14 2019 Jonas Ådahl - 3.32.2-8 -- Depend on required gsettings-desktop-schemas version - Related: #1704355 - -* Tue Jul 23 2019 Florian Müllner - 3.32.2-7 -- Make the hot corner optional - Resolves: #1704355 - -* Fri Jul 12 2019 Florian Müllner - 3.32.2-6 -- Fix warnings triggered by spurious allocations - Resolves: #1719279 - -* Wed Jul 10 2019 Florian Müllner - 3.32.2-5 -- Fix infinite loop in spinner animation - Resolves: #1725555 - -* Tue Jun 18 2019 Florian Müllner - 3.32.2-4 -- Adjust more shortcut handlers for horizontal workspaces - Related: #1704360 - -* Wed Jun 12 2019 Florian Müllner - 3.32.2-3 -- Support horizontal workspaces in gestures/keybindings/animations - Related: #1704360 - -* Fri May 31 2019 Florian Müllner - 3.32.2-2 -- Adjust downstream patch to mutter changes - Resolves: #1715738 - -* Thu May 23 2019 Florian Müllner - 3.32.2-1 -- Update to 3.32.2 - Resolves: #1698520 - -* Mon Feb 11 2019 Florian Müllner - 3.28.3-10 -- Backport another IM fix (#1668979) - -* Mon Feb 11 2019 Florian Müllner - 3.28.3-9 -- Fix JS "invalid access" warnings (#1642482, #1637622) -- Fix new input sources only working after re-login (#1628154) -- Backport IM support fixes (#1668979) -* Fri Feb 08 2019 Florian Müllner - 3.28.3-8 -- Re-add dropped downstream patches (rhbz#1668884) - -* Tue Feb 05 2019 Jonas Ådahl - 3.28.3-7 -- Backport dnd crash fix (#1663171) +* Mon Aug 24 2020 Florian Müllner - 3.37.91-1 +- Update to 3.37.91 + +* Sun Aug 23 2020 Kalev Lember - 3.37.90-2 +- Backport a fix for launching apps under X11 (#1870234) + +* Fri Aug 14 2020 Florian Müllner - 3.37.90-1 +- Update to 3.37.90 + +* Sat Aug 01 2020 Fedora Release Engineering - 3.37.3-4 +- Second attempt - Rebuilt for + https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Mon Jul 27 2020 Fedora Release Engineering - 3.37.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Mon Jul 13 2020 Milan Crha - 3.37.3-2 +- Rebuilt for evolution-data-server soname version bump + +* Tue Jul 07 2020 Florian Müllner - 3.37.3-1 +- Update to 3.37.3 + +* Fri Jul 03 2020 Milan Crha - 3.37.2-2 +- Rebuilt for evolution-data-server soname version bump + +* Wed Jun 03 2020 Florian Müllner - 3.37.2-1 +- Update to 3.37.2 + +* Wed May 20 2020 Stephen Gallagher - 3.37.1-3 +- Fix crashes when locking the screen while certain extensions are active +- Resolves: rhbz#1817082 + +* Mon May 04 2020 Adam Williamson - 3.37.1-2 +- Fix panel to show input methods (MR #1235) + +* Thu Apr 30 2020 Florian Müllner - 3.28.3-6 -- Fix suspend and resume corruption on NVidia - Resolves: #1663440 +* Tue Mar 31 2020 Florian Müllner - 3.28.3-5 -- Backport dnd fix (#1651894) +* Tue Mar 31 2020 Jonas Ådahl - 3.36.1-2 +- Backport fixup for spring animation fix -* Fri Jan 11 2019 Olivier Fourdan - 3.28.3-4 -- Backport Introspection D-BUS API (rhbz#1658967) +* Tue Mar 31 2020 Florian Müllner - 3.36.1-1 +- Update to 3.36.1 +- Remove gnome-extensions-app subpackage (will move to a separate .spec) -* Tue Sep 18 2018 David King - 3.28.3-3 -- Improve Python 3 dependency (#1630148) +* Wed Mar 25 2020 Ray Strode - 3.36.0-4 +- Clear environment on logout + Fixes log in to Xorg right after log out from wayland + Resolves: #1815487 -* Fri Aug 10 2018 Jonas Ådahl - 3.28.3-2 -- Backport remote access control UI (rhbz#1613749) +* Wed Mar 11 2020 Adam Williamson - 3.36.0-3 +- Backport fix for input method preedit issue (MR #1084) -* Fri Aug 10 2018 Kalev Lember - 3.28.3-1 -- Update to 3.28.3 +* Tue Mar 10 2020 Adam Williamson - 3.36.0-2 +- Backport fix for ibus failing to start automatically (MR #1080) -* Mon Aug 06 2018 Charalampos Stratakis - 3.28.1-6 +* Sat Mar 07 2020 Florian Müllner - 3.36.0-1 +- Update to 3.36.0 + +* Sun Mar 01 2020 Florian Müllner - 3.35.92-1 +- Update to 3.35.92 + +* Tue Feb 18 2020 Florian Müllner - 3.35.91-1 +- Update to 3.35.91 + +* Fri Feb 07 2020 Kalev Lember - 3.35.90-2 +- Adjust the favorites patch to include the apps we install by default + +* Thu Feb 06 2020 Florian Müllner - 3.35.90-1 +- Update to 3.35.90 + +* Tue Jan 28 2020 Fedora Release Engineering - 3.35.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Thu Jan 16 2020 Kalev Lember - 3.35.3-2 +- Rebuilt for libgnome-desktop soname bump + +* Sun Jan 05 2020 Florian Müllner - 3.35.3-2 +- Update to 3.35.3 + +* Wed Dec 11 2019 Florian Müllner - 3.35.2-1 +- Udpate to 3.35.2 + +* Sat Oct 12 2019 Florian Müllner - 3.35.1-1 +- Update to 3.35.1 + +* Sat Oct 12 2019 Adam Williamson - 3.34.1-2 +- Backport MR #754 to fix #1749433 + +* Wed Oct 09 2019 Florian Müllner - 3.34.1-1 +- Update to 3.34.1 + +* Tue Sep 24 2019 Debarshi Ray - 3.34.0-3 +- Stop NOTIFY_SOCKET from leaking into the GNOME environment + +* Fri Sep 20 2019 Florian Müllner - 3.34.0-2 +- Fix disappearing icons in frequent view + +* Mon Sep 09 2019 Florian Müllner - 3.34.0-1 +- Update to 3.34.0 + +* Thu Sep 05 2019 Kalev Lember - 3.33.92-1 +- Update to 3.33.92 + +* Mon Aug 26 2019 Kalev Lember - 3.33.91-1 +- Update to 3.33.91 + +* Fri Aug 23 2019 Adam Williamson - 3.33.90-2 +- Revert commit that causes #1740897 (overview type-to-search bug) + Resolves: #1740897 + +* Sat Aug 10 2019 Florian Müllner - 3.33.90-1 +- Update to 3.33.90 + +* Thu Jul 25 2019 Fedora Release Engineering - 3.33.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Sat Jul 20 2019 Florian Müllner - 3.33.4-1 +- Update to 3.33.4 + +* Mon Jun 24 2019 Florian Mülllner - 3.33.3-1 +- Update to 3.33.3 + +* Wed May 22 2019 Florian Müllner - 3.33.2-1 +- Update to 3.33.2 + +* Wed May 22 2019 Kalev Lember - 3.33.1-2 +- Rebuild for libecal-2.0 + +* Tue May 14 2019 Florian Müllner - 3.33.1-1 +- Update to 3.33.1 + +* Wed Apr 17 2019 Florian Müllner - 3.32.1-1 +- Update to 3.32.1 + +* Wed Apr 17 2019 Adam Williamson - 3.32.0-3 +- Backport MR #463 and MR #494 to fix a couple of bugs + Resolves: #1696270 + Resolves: #1690429 + +* Sat Mar 23 2019 Phil Wyett - 3.32.0-2 +- Update source URL +- Add gcc BuildRequires +- Update versions required for gjs and mutter + +* Tue Mar 12 2019 Florian Müllner - 3.32.0-1 +- Update to 3.32.0 + +* Tue Mar 05 2019 Florian Müllner - 3.31.92-1 +- Update to 3.31.92 + +* Thu Feb 21 2019 Florian Müllner - 3.31.91-1 +- Update to 3.31.91 + +* Mon Feb 11 2019 Adam Williamson - 3.31.90-2 +- Backport MR #402 to fix missing logo on login screen + +* Thu Feb 07 2019 Florian Müllner - 3.31.90-1 +- Update to 3.31.90 + +* Thu Jan 31 2019 Fedora Release Engineering - 3.31.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Thu Jan 10 2019 Florian Müllner - 3.31.4-1 +- Update to 3.31.4 + +* Fri Dec 14 2018 Adam Williamson - 3.31.2-3 +- Backport several bugfix commits from current git master + +* Fri Nov 30 2018 Adam Williamson - 3.31.2-2 +- Backport PR #293 to fix 'empty input method indicator' bug + +* Wed Nov 14 2018 Florian Müllner - 3.31.2-1 +- Update to 3.31.2 + +* Mon Nov 12 2018 Mohan Boddu - 3.30.1-3 +- Rebuilt for evolution-data-server soname bump + +* Tue Oct 23 2018 Jonas Ådahl - 3.30.1-2 +- Backport keyboard layout change fixes (rhbz#1637418) + +* Mon Oct 08 2018 Florian Müllner - 3.30.1-1 +- Update to 3.30.1 + +* Thu Sep 27 2018 Hans de Goede - 3.30.0-9 +- Add downstream patches implementing the "Boot Options" menu from: + https://wiki.gnome.org/Design/OS/BootOptions + +* Sat Sep 22 2018 Adam Williamson - 3.30.0-8 +- Backport fix for IBus type issue (GGO MR #228) + +* Wed Sep 19 2018 Adam Williamson - 3.30.0-7 +- Replace dnd fix from -5 with upstream version (GGO MR #209) +- Fix a window destroy crash which can occur with new gjs (GGO #539) +- Fix a window menu issue on multi-monitor systems (GGO MR #227) +- Fix hover and active states for some buttons (GGO #523) + +* Wed Sep 19 2018 Adam Williamson - 3.30.0-6 +- Fix missing key description in ssh key unlock prompt (GGO #574) + +* Wed Sep 19 2018 Ray Strode - 3.30.0-5 +- Fix lock up when dropping icon on dash + Resolves: #1630134 + +* Tue Sep 18 2018 Adam Williamson - 3.30.0-4 +- Fix connecting to wifi from user menu (RHBZ #1628263) + +* Sat Sep 15 2018 Adam Williamson - 3.30.0-3 +- Backport fix for GGO #140 from upstream master + +* Thu Sep 13 2018 Kalev Lember - 3.30.0-2 +- Require xdg-desktop-portal-gtk + +* Tue Sep 04 2018 Florian Müllner - 3.30.0-1 +- Update to 3.30.0 + +* Wed Aug 29 2018 Florian Müllner - 3.29.92-1 +- Update to 3.29.92 + +* Mon Aug 20 2018 Florian Müllner - 3.29.91-1 +- Update to 3.29.91 + +* Thu Aug 09 2018 Debarshi Ray - 3.29.90-2 - Remove telepathy-logger and telepathy-glib runtime dependencies -* Wed Aug 01 2018 Stef Walter - 3.28.1-5 -- Remove unneeded libgnome-keyring dependency (#1589078) +* Wed Aug 01 2018 Florian Müllner - 3.29.90-1 +- Update to 3.29.90 + +* Wed Jul 18 2018 Florian Müllner - 3.29.4-1 +- Update to 3.29.4 -* Wed Aug 01 2018 Charalampos Stratakis - 3.28.1-4 -- BuildRequire python3-devel +* Fri Jul 13 2018 Fedora Release Engineering - 3.29.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild -* Sun Apr 29 2018 Adam Williamson - 3.28.1-3 +* Thu May 24 2018 Florian Müllner - 3.29.2-1 +- Update to 3.29.2 + +* Wed May 09 2018 Florian Müllner - 3.29.1-3 +- Fix automatic connection to wireless networks without stored secrets + +* Sun Apr 29 2018 Adam Williamson - 3.29.1-2 - Backport fix for password entry modifier key issues (#1569211) +* Wed Apr 25 2018 Florian Müllner - 3.29.1-1 +- Update to 3.29.1 + * Tue Apr 24 2018 Ray Strode - 3.28.1-2 - pull polkit cancel lock up from upstream Resolves: #1568213 diff --git a/horizontal-workspace-support.patch b/horizontal-workspace-support.patch deleted file mode 100644 index 8605e1d25a2971939bdd4753ebcde60b35a7aba9..0000000000000000000000000000000000000000 --- a/horizontal-workspace-support.patch +++ /dev/null @@ -1,399 +0,0 @@ -From b42dd3f87ad5fb6c7ee139cb0de22e0fbb393ba2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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?= -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 - diff --git a/introspect-backports.patch b/introspect-backports.patch deleted file mode 100644 index b93532cc3ebaa388bf54d799fcb5ac082c37c4cc..0000000000000000000000000000000000000000 --- a/introspect-backports.patch +++ /dev/null @@ -1,643 +0,0 @@ -From 781dfcf6ce7168c6b116d58df5f1c67291a7b513 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -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?= -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?= -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?= -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?= -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 - #include - #include -+#include -+#include - - #include - #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?= -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?= -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?= -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?= -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?= -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?= -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 @@ - - - -+ -+ -+ -+ -+ - - -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 - diff --git a/login-screen-extensions.patch b/login-screen-extensions.patch new file mode 100644 index 0000000000000000000000000000000000000000..bdfb9a12d4aaa3a7b531a911b91427074d2abba5 --- /dev/null +++ b/login-screen-extensions.patch @@ -0,0 +1,227 @@ +From 4024d59871d0c8990ef5e4243c9fc485971755e7 Mon Sep 17 00:00:00 2001 +From: Ray Strode +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 +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 +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 + diff --git a/more-spurious-allocation-warnings.patch b/more-spurious-allocation-warnings.patch deleted file mode 100644 index 16acc8f93eeccf5bcd9017a1a6ec20b551852205..0000000000000000000000000000000000000000 --- a/more-spurious-allocation-warnings.patch +++ /dev/null @@ -1,176 +0,0 @@ -From 4926a9b8f958617d67d603622b1382c17fe4037c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -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?= -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 - diff --git a/osk-fixes.patch b/osk-fixes.patch deleted file mode 100644 index 6c5648d6ed0389f332deff94213cddee40057971..0000000000000000000000000000000000000000 --- a/osk-fixes.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 96ccb155bbe6ce570832a9f3d27a0a08698127ea Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Sat, 28 Mar 2020 14:15:09 +0100 -Subject: [PATCH 1/3] keyboard: Don't include keyboard devices when updating - lastDevice - -We're dealing with attached keyboards now using the touch_mode property -of ClutterSeat: If a device has a keyboard attached, the touch-mode is -FALSE and we won't automatically show the OSK on touches, also the -touch-mode gets set to FALSE when an external keyboard is being plugged -in, so that also hides the OSK automatically. - -With that, we can now ignore keyboard devices when updating the last -used device and no longer have to special-case our own virtual devices. - -Because there was no special-case for the virtual device we use on -Wayland now, this fixes a bug where the keyboard disappeared after -touching keys like Enter or Backspace. - -Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2287 - -https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1142 ---- - js/ui/keyboard.js | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/js/ui/keyboard.js b/js/ui/keyboard.js -index c4ac72d..94b5325 100644 ---- a/js/ui/keyboard.js -+++ b/js/ui/keyboard.js -@@ -1075,6 +1075,9 @@ var Keyboard = class Keyboard { - let device = manager.get_device(deviceId); - - if (device.get_device_name().indexOf('XTEST') < 0) { -+ if (device.device_type == Clutter.InputDeviceType.KEYBOARD_DEVICE) -+ return; -+ - this._lastDeviceId = deviceId; - this._syncEnabled(); - } --- -2.26.2 - - -From 3106746ae424287d8644643a2ef46d565e4cd7ed Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Sat, 28 Mar 2020 14:34:24 +0100 -Subject: [PATCH 2/3] layout: Use translation_y of 0 to hide keyboard - -Since we show the keyboard using a translation_y of -keyboardHeight, the -keyboard will be moved down far enough to be out of sight by setting -translation_y to 0. - -https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1142 ---- - js/ui/layout.js | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/js/ui/layout.js b/js/ui/layout.js -index beb4c0a..4382f6e 100644 ---- a/js/ui/layout.js -+++ b/js/ui/layout.js -@@ -719,7 +719,7 @@ var LayoutManager = GObject.registerClass({ - showKeyboard() { - this.keyboardBox.show(); - Tweener.addTween(this.keyboardBox, -- { anchor_y: this.keyboardBox.height, -+ { translation_y: -this.keyboardBox.height, - opacity: 255, - time: KEYBOARD_ANIMATION_TIME, - transition: 'easeOutQuad', -@@ -735,7 +735,7 @@ var LayoutManager = GObject.registerClass({ - this._updateRegions(); - - this._keyboardHeightNotifyId = this.keyboardBox.connect('notify::height', () => { -- this.keyboardBox.anchor_y = this.keyboardBox.height; -+ this.keyboardBox.translation_y = -this.keyboardBox.height; - }); - } - -@@ -745,7 +745,7 @@ var LayoutManager = GObject.registerClass({ - this._keyboardHeightNotifyId = 0; - } - Tweener.addTween(this.keyboardBox, -- { anchor_y: 0, -+ { translation_y: 0, - opacity: 0, - time: immediate ? 0 : KEYBOARD_ANIMATION_TIME, - transition: 'easeInQuad', --- -2.26.2 - - -From 642822308a72be6a47f4eb285f32539499f0d3e4 Mon Sep 17 00:00:00 2001 -From: rpm-build -Date: Wed, 21 Oct 2020 20:29:34 +0200 -Subject: [PATCH 3/3] layout: queue redraw after hiding keyboard - ---- - js/ui/layout.js | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/js/ui/layout.js b/js/ui/layout.js -index 4382f6e..1824313 100644 ---- a/js/ui/layout.js -+++ b/js/ui/layout.js -@@ -759,6 +759,7 @@ var LayoutManager = GObject.registerClass({ - _hideKeyboardComplete() { - this.keyboardBox.hide(); - this._updateRegions(); -+ global.stage.queue_redraw(); - } - - // setDummyCursorGeometry: --- -2.26.2 - diff --git a/perf-tool-wayland.patch b/perf-tool-wayland.patch deleted file mode 100644 index be4b625e73a936925e24dbc5b55b40d0a757f191..0000000000000000000000000000000000000000 --- a/perf-tool-wayland.patch +++ /dev/null @@ -1,399 +0,0 @@ -From 119ec213b8f9a9e55ca340dbde10b0d19becab41 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Thu, 5 Dec 2019 14:12:47 +0100 -Subject: [PATCH 1/4] perf-helper: Add content for custom drawing - -Drawing windows got a lot more involved with the advent of client-side -decorations. Instead of accounting for visible and invisible borders, -titlebar and shadows when necessary, just add an empty child for the -custom drawing. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/887 ---- - src/shell-perf-helper.c | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/src/shell-perf-helper.c b/src/shell-perf-helper.c -index e5eab208b..55bdbef02 100644 ---- a/src/shell-perf-helper.c -+++ b/src/shell-perf-helper.c -@@ -120,9 +120,9 @@ on_window_map_event (GtkWidget *window, - } - - static gboolean --on_window_draw (GtkWidget *window, -- cairo_t *cr, -- WindowInfo *info) -+on_child_draw (GtkWidget *window, -+ cairo_t *cr, -+ WindowInfo *info) - { - cairo_rectangle_int_t allocation; - double x_offset, y_offset; -@@ -204,6 +204,7 @@ create_window (int width, - gboolean redraws) - { - WindowInfo *info; -+ GtkWidget *child; - - info = g_new0 (WindowInfo, 1); - info->width = width; -@@ -219,10 +220,13 @@ create_window (int width, - info->pending = TRUE; - info->start_time = -1; - -+ child = g_object_new (GTK_TYPE_BOX, "visible", TRUE, "app-paintable", TRUE, NULL); -+ gtk_container_add (GTK_CONTAINER (info->window), child); -+ - gtk_widget_set_size_request (info->window, width, height); - gtk_widget_set_app_paintable (info->window, TRUE); - g_signal_connect (info->window, "map-event", G_CALLBACK (on_window_map_event), info); -- g_signal_connect (info->window, "draw", G_CALLBACK (on_window_draw), info); -+ g_signal_connect (child, "draw", G_CALLBACK (on_child_draw), info); - gtk_widget_show (info->window); - - if (info->redraws) --- -2.26.2 - - -From bb4c2acaef4d8fdea50915030c221e1190f704a4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Thu, 5 Dec 2019 13:29:38 +0100 -Subject: [PATCH 2/4] perf-helper: Remove unused atoms - -Those aren't used for anything, but make the helper dependent on X11. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/887 ---- - src/shell-perf-helper.c | 18 ------------------ - 1 file changed, 18 deletions(-) - -diff --git a/src/shell-perf-helper.c b/src/shell-perf-helper.c -index 55bdbef02..d3280de96 100644 ---- a/src/shell-perf-helper.c -+++ b/src/shell-perf-helper.c -@@ -12,7 +12,6 @@ - #include - - #include --#include - - #define BUS_NAME "org.gnome.Shell.PerfHelper" - -@@ -60,12 +59,6 @@ static GOptionEntry opt_entries[] = - { NULL } - }; - --static Display *xdisplay; --static Window xroot; --static Atom atom_wm_state; --static Atom atom__net_wm_name; --static Atom atom_utf8_string; -- - static guint timeout_id; - static GList *our_windows; - static GList *wait_windows_invocations; -@@ -351,8 +344,6 @@ on_name_lost (GDBusConnection *connection, - int - main (int argc, char **argv) - { -- GdkDisplay *display; -- GdkScreen *screen; - GOptionContext *context; - GError *error = NULL; - -@@ -368,15 +359,6 @@ main (int argc, char **argv) - return 1; - } - -- display = gdk_display_get_default (); -- screen = gdk_screen_get_default (); -- -- xdisplay = gdk_x11_display_get_xdisplay (display); -- xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen)); -- atom_wm_state = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE"); -- atom__net_wm_name = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME"); -- atom_utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"); -- - g_bus_own_name (G_BUS_TYPE_SESSION, - BUS_NAME, - G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | --- -2.26.2 - - -From d8b4d72b89340dab46bdcb92ee54bde18dbb9ba9 Mon Sep 17 00:00:00 2001 -From: Olivier Fourdan -Date: Fri, 24 Jan 2020 10:59:31 +0100 -Subject: [PATCH 3/4] perf-tool: Spawn perf-tool-helper from gnome-shell - -On Wayland, the display server is the Wayland compositor, i.e. -`gnome-shell` itself. - -As a result, we cannot spawn `gnome-shell-perf-helper` before -`gnome-shell` is started, as `gnome-shell-perf-helper` needs to connect -to the display server. - -So, instead of spawning `gnome-shell-perf-helper` from the perf tool, -start it from `gnome-shell` itself. - -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/941 ---- - js/ui/scripting.js | 51 ++++++++++++++++++++++------------ - src/gnome-shell-perf-tool.in | 53 ------------------------------------ - 2 files changed, 34 insertions(+), 70 deletions(-) - -diff --git a/js/ui/scripting.js b/js/ui/scripting.js -index d227b9ef4..eef8f3887 100644 ---- a/js/ui/scripting.js -+++ b/js/ui/scripting.js -@@ -3,8 +3,10 @@ - const { Gio, GLib, Meta, Shell } = imports.gi; - const Mainloop = imports.mainloop; - -+const Config = imports.misc.config; - const Main = imports.ui.main; - const Params = imports.misc.params; -+const Util = imports.misc.util; - - const { loadInterfaceXML } = imports.misc.fileUtils; - -@@ -73,6 +75,12 @@ function _getPerfHelper() { - return _perfHelper; - } - -+function _spawnPerfHelper() { -+ let path = Config.LIBEXECDIR; -+ let command = `${path}/gnome-shell-perf-helper`; -+ Util.trySpawnCommandLine(command); -+} -+ - function _callRemote(obj, method, ...args) { - return new Promise((resolve, reject) => { - args.push((result, excp) => { -@@ -270,6 +278,25 @@ function _collect(scriptModule, outputFile) { - } - } - -+async function _runPerfScript(scriptModule, outputFile) { -+ for (let step of scriptModule.run()) { -+ try { -+ await step; // eslint-disable-line no-await-in-loop -+ } catch (err) { -+ log(`Script failed: ${err}\n${err.stack}`); -+ Meta.exit(Meta.ExitCode.ERROR); -+ } -+ } -+ -+ try { -+ _collect(scriptModule, outputFile); -+ } catch (err) { -+ log(`Script failed: ${err}\n${err.stack}`); -+ Meta.exit(Meta.ExitCode.ERROR); -+ } -+ Meta.exit(Meta.ExitCode.SUCCESS); -+} -+ - /** - * runPerfScript - * @scriptModule: module object with run and finish functions -@@ -310,23 +337,13 @@ function _collect(scriptModule, outputFile) { - * After running the script and collecting statistics from the - * event log, GNOME Shell will exit. - **/ --async function runPerfScript(scriptModule, outputFile) { -+function runPerfScript(scriptModule, outputFile) { - Shell.PerfLog.get_default().set_enabled(true); -+ _spawnPerfHelper(); - -- for (let step of scriptModule.run()) { -- try { -- await step; -- } catch (err) { -- log(`Script failed: ${err}\n${err.stack}`); -- Meta.exit(Meta.ExitCode.ERROR); -- } -- } -- -- try { -- _collect(scriptModule, outputFile); -- } catch (err) { -- log(`Script failed: ${err}\n${err.stack}`); -- Meta.exit(Meta.ExitCode.ERROR); -- } -- Meta.exit(Meta.ExitCode.SUCCESS); -+ Gio.bus_watch_name(Gio.BusType.SESSION, -+ 'org.gnome.Shell.PerfHelper', -+ Gio.BusNameWatcherFlags.NONE, -+ () => _runPerfScript(scriptModule, outputFile), -+ null); - } -diff --git a/src/gnome-shell-perf-tool.in b/src/gnome-shell-perf-tool.in -index f4b48f730..050c66b30 100755 ---- a/src/gnome-shell-perf-tool.in -+++ b/src/gnome-shell-perf-tool.in -@@ -24,52 +24,6 @@ def show_version(option, opt_str, value, parser): - print("GNOME Shell Performance Test @VERSION@") - sys.exit() - --def wait_for_dbus_name(wait_name): -- loop = GLib.MainLoop() -- -- def on_name_appeared(connection, name, new_owner, *args): -- if not (name == wait_name and new_owner != ''): -- return -- loop.quit() -- return -- -- watch_id = Gio.bus_watch_name(Gio.BusType.SESSION, -- wait_name, -- Gio.BusNameWatcherFlags.NONE, -- on_name_appeared, -- None) -- -- def on_timeout(): -- print("\nFailed to start %s: timed out" % (wait_name,)) -- sys.exit(1) -- GLib.timeout_add_seconds(7, on_timeout) -- -- loop.run() -- Gio.bus_unwatch_name(watch_id) -- --PERF_HELPER_NAME = "org.gnome.Shell.PerfHelper" --PERF_HELPER_IFACE = "org.gnome.Shell.PerfHelper" --PERF_HELPER_PATH = "/org/gnome/Shell/PerfHelper" -- --def start_perf_helper(): -- self_dir = os.path.dirname(os.path.abspath(sys.argv[0])) -- perf_helper_path = "@libexecdir@/gnome-shell-perf-helper" -- -- subprocess.Popen([perf_helper_path]) -- wait_for_dbus_name (PERF_HELPER_NAME) -- --def stop_perf_helper(): -- bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) -- -- proxy = Gio.DBusProxy.new_sync(bus, -- Gio.DBusProxyFlags.NONE, -- None, -- PERF_HELPER_NAME, -- PERF_HELPER_PATH, -- PERF_HELPER_IFACE, -- None) -- proxy.Exit() -- - def start_shell(perf_output=None): - # Set up environment - env = dict(os.environ) -@@ -204,8 +158,6 @@ def run_performance_test(): - logs = [] - metric_summaries = {} - -- start_perf_helper() -- - for i in range(0, iters): - # We create an empty temporary file that the shell will overwrite - # with the contents. -@@ -217,14 +169,12 @@ def run_performance_test(): - try: - normal_exit = run_shell(perf_output=output_file) - except: -- stop_perf_helper() - raise - finally: - if not normal_exit: - os.remove(output_file) - - if not normal_exit: -- stop_perf_helper() - return False - - try: -@@ -232,7 +182,6 @@ def run_performance_test(): - output = json.load(f) - f.close() - except: -- stop_perf_helper() - raise - finally: - os.remove(output_file) -@@ -260,8 +209,6 @@ def run_performance_test(): - - logs.append(output['log']) - -- stop_perf_helper() -- - if options.perf_output or options.perf_upload: - # Write a complete report, formatted as JSON. The Javascript/C code that - # generates the individual reports we are summarizing here is very careful --- -2.26.2 - - -From 8090db0f29dc72e602be341d43b3113373404b21 Mon Sep 17 00:00:00 2001 -From: Olivier Fourdan -Date: Tue, 21 Jan 2020 11:05:58 +0100 -Subject: [PATCH 4/4] perf-tool: Allow to run as a Wayland compositor - -`gnome-shell-perf-tool` is initially designed to run on X11, using the -`--replace` option which does not work when gnome-shell is a Wayland -compositor. - -A solution would be to run `gnome-shell-perf-tool` in place of just -`gnome-shell` to run the entire perf session under Wayland, but the -script `gnome-shell-perf-tool` does not spawn `gnome-shell` as a Wayladn -compositor, so that fails as well. - -Add a `--wayland` option to `gnome-shell-perf-tool` so that it can -optionally spawn gnome-shell as a Wayland compositor so the whole perf -tool can be starred from a console with: - -``` - $ dbus-run-session -- gnome-shell-perf-tool --wayland -``` - -Alternatively, for testing purposes, it can also be started nested with: - -``` - $ dbus-run-session -- gnome-shell-perf-tool --nested -``` - -Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/2139 -https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/941 ---- - src/gnome-shell-perf-tool.in | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/src/gnome-shell-perf-tool.in b/src/gnome-shell-perf-tool.in -index 050c66b30..04072c4cd 100755 ---- a/src/gnome-shell-perf-tool.in -+++ b/src/gnome-shell-perf-tool.in -@@ -45,6 +45,13 @@ def start_shell(perf_output=None): - if options.replace: - args.append('--replace') - -+ if options.wayland or options.nested: -+ args.append('--wayland') -+ if options.nested: -+ args.append('--nested') -+ else: -+ args.append('--display-server') -+ - return subprocess.Popen(args, env=env) - - def run_shell(perf_output=None): -@@ -284,6 +291,10 @@ parser.add_option("", "--version", action="callback", callback=show_version, - - parser.add_option("-r", "--replace", action="store_true", - help="Replace the running window manager") -+parser.add_option("-w", "--wayland", action="store_true", -+ help="Run as a Wayland compositor") -+parser.add_option("-n", "--nested", action="store_true", -+ help="Run as a Wayland nested compositor") - - options, args = parser.parse_args() - --- -2.26.2 - diff --git a/restrict-dbus-callers.patch b/restrict-dbus-callers.patch new file mode 100644 index 0000000000000000000000000000000000000000..914adcd008fce11e3131bf1cd3e6fe7dab85d4ce --- /dev/null +++ b/restrict-dbus-callers.patch @@ -0,0 +1,1353 @@ +From eb26ea5e1bb0c6fc978aae5db99ed3427b34175b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 1 Apr 2022 19:40:31 +0200 +Subject: [PATCH 01/12] shell/global: Expose shim context property + +Parts of the following commits rely on the ShellGlobal:context +property that was added in GNOME 41 to expose the MetaContext +(likewise a GNOME 41 addition). + +To prepare for that, expose a small shim object as context +property that mimicks the expected upstream API. +--- + src/shell-global.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 92 insertions(+) + +diff --git a/src/shell-global.c b/src/shell-global.c +index 24e771f52..805c73145 100644 +--- a/src/shell-global.c ++++ b/src/shell-global.c +@@ -47,6 +47,9 @@ + + static ShellGlobal *the_object = NULL; + ++#define SHIM_TYPE_META_CONTEXT shim_meta_context_get_type () ++G_DECLARE_FINAL_TYPE (ShimMetaContext, shim_meta_context, SHIM, META_CONTEXT, GObject) ++ + struct _ShellGlobal { + GObject parent; + +@@ -54,6 +57,7 @@ struct _ShellGlobal { + + MetaBackend *backend; + MetaDisplay *meta_display; ++ ShimMetaContext *meta_context; + MetaWorkspaceManager *workspace_manager; + Display *xdisplay; + +@@ -92,6 +96,7 @@ enum { + + PROP_SESSION_MODE, + PROP_BACKEND, ++ PROP_CONTEXT, + PROP_DISPLAY, + PROP_WORKSPACE_MANAGER, + PROP_SCREEN_WIDTH, +@@ -235,6 +240,9 @@ shell_global_get_property(GObject *object, + case PROP_BACKEND: + g_value_set_object (value, global->backend); + break; ++ case PROP_CONTEXT: ++ g_value_set_object (value, global->meta_context); ++ break; + case PROP_DISPLAY: + g_value_set_object (value, global->meta_display); + break; +@@ -514,6 +522,13 @@ shell_global_class_init (ShellGlobalClass *klass) + "MetaBackend object", + META_TYPE_BACKEND, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); ++ g_object_class_install_property (gobject_class, ++ PROP_CONTEXT, ++ g_param_spec_object ("context", ++ "Context", ++ "MetaContext object", ++ G_TYPE_OBJECT, ++ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_DISPLAY, + g_param_spec_object ("display", +@@ -996,6 +1011,7 @@ _shell_global_set_plugin (ShellGlobal *global, + + display = meta_plugin_get_display (plugin); + global->meta_display = display; ++ global->meta_context = g_object_new (SHIM_TYPE_META_CONTEXT, NULL); + global->workspace_manager = meta_display_get_workspace_manager (display); + + global->stage = CLUTTER_STAGE (meta_get_stage_for_display (display)); +@@ -1888,3 +1904,79 @@ _shell_global_locate_pointer (ShellGlobal *global) + { + g_signal_emit (global, shell_global_signals[LOCATE_POINTER], 0); + } ++ ++enum { ++ SHIM_PROP_0, ++ ++ SHIM_PROP_UNSAFE_MODE, ++ ++ N_SHIM_PROPS ++}; ++ ++static GParamSpec *shim_obj_props [N_SHIM_PROPS]; ++ ++struct _ShimMetaContext ++{ ++ GObject parent_instance; ++}; ++ ++G_DEFINE_TYPE (ShimMetaContext, shim_meta_context, G_TYPE_OBJECT); ++ ++static void ++shim_meta_context_get_property (GObject *object, ++ guint prop_id, ++ GValue *value, ++ GParamSpec *pspec) ++{ ++ switch (prop_id) ++ { ++ case SHIM_PROP_UNSAFE_MODE: ++ { ++ gboolean unsafe_mode; ++ ++ g_object_get (meta_get_backend (), "unsafe-mode", &unsafe_mode, NULL); ++ g_value_set_boolean (value, unsafe_mode); ++ } ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ } ++} ++ ++static void ++shim_meta_context_set_property (GObject *object, ++ guint prop_id, ++ const GValue *value, ++ GParamSpec *pspec) ++{ ++ switch (prop_id) ++ { ++ case SHIM_PROP_UNSAFE_MODE: ++ g_object_set_property (G_OBJECT (meta_get_backend ()), "unsafe-mode", value); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ } ++} ++ ++static void ++shim_meta_context_class_init (ShimMetaContextClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ ++ object_class->get_property = shim_meta_context_get_property; ++ object_class->set_property = shim_meta_context_set_property; ++ ++ shim_obj_props[SHIM_PROP_UNSAFE_MODE] = ++ g_param_spec_boolean ("unsafe-mode", ++ "unsafe mode", ++ "Unsafe mode", ++ FALSE, ++ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); ++ g_object_class_install_properties (object_class, N_SHIM_PROPS, shim_obj_props); ++} ++ ++static void ++shim_meta_context_init (ShimMetaContext *self) ++{ ++} +-- +2.35.1 + + +From 20fcc7bc78a3c227304e89deddc57266e560175c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 2 Sep 2021 17:15:36 +0200 +Subject: [PATCH 02/12] panel: Show warning indicator when unsafe-mode is on + +MetaContext added an unsafe-mode property, which we will use to restrict +a number of privileged operations unless it is enabled. It is meant to +only be enabled temporarily for development/debugging purposes, so add +a scary icon to the top bar as a reminder to turn it off again. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/ui/panel.js | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/js/ui/panel.js b/js/ui/panel.js +index 380480744..c57c3ba8e 100644 +--- a/js/ui/panel.js ++++ b/js/ui/panel.js +@@ -641,6 +641,20 @@ class PanelCorner extends St.DrawingArea { + } + }); + ++const UnsafeModeIndicator = GObject.registerClass( ++class UnsafeModeIndicator extends PanelMenu.SystemIndicator { ++ _init() { ++ super._init(); ++ ++ this._indicator = this._addIndicator(); ++ this._indicator.icon_name = 'channel-insecure-symbolic'; ++ ++ global.context.bind_property('unsafe-mode', ++ this._indicator, 'visible', ++ GObject.BindingFlags.SYNC_CREATE); ++ } ++}); ++ + var AggregateLayout = GObject.registerClass( + class AggregateLayout extends Clutter.BoxLayout { + _init(params = {}) { +@@ -702,6 +716,7 @@ class AggregateMenu extends PanelMenu.Button { + this._location = new imports.ui.status.location.Indicator(); + this._nightLight = new imports.ui.status.nightLight.Indicator(); + this._thunderbolt = new imports.ui.status.thunderbolt.Indicator(); ++ this._unsafeMode = new UnsafeModeIndicator(); + + this._indicators.add_child(this._remoteAccess); + this._indicators.add_child(this._thunderbolt); +@@ -713,6 +728,7 @@ class AggregateMenu extends PanelMenu.Button { + this._indicators.add_child(this._bluetooth); + this._indicators.add_child(this._rfkill); + this._indicators.add_child(this._volume); ++ this._indicators.add_child(this._unsafeMode); + this._indicators.add_child(this._power); + this._indicators.add_child(this._powerProfiles); + +-- +2.35.1 + + +From 158eeebc1d3a243e75de550cf5711e38a9f77f7f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 17 Jun 2021 01:50:50 +0200 +Subject: [PATCH 03/12] shellDBus: Use MetaContext:unsafe-mode to restrict + Eval() + +The Eval() method is unarguably the most sensitive D-Bus method +we expose, since it allows running arbitrary code in the compositor. + +It is currently tied to the `development-tools` settings that is +enabled by default. As users have become accustomed to the built-in +commands that are enabled by the same setting (restart, lg, ...), +that default cannot easily be changed. + +In order to restrict the method without affecting the rather harmless +commands, guard it by the new MetaContext:unsafe-mode property instead +of the setting. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/ui/shellDBus.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js +index 734ca4fc7..5a6edec74 100644 +--- a/js/ui/shellDBus.js ++++ b/js/ui/shellDBus.js +@@ -54,7 +54,7 @@ var GnomeShell = class { + * + */ + Eval(code) { +- if (!global.settings.get_boolean('development-tools')) ++ if (!global.context.unsafe_mode) + return [false, '']; + + let returnValue; +-- +2.35.1 + + +From 0882e04a11fe8db7abf05a5d7c786664dc54ad4f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 2 Sep 2021 16:23:38 +0200 +Subject: [PATCH 04/12] introspect: Make invocation check error-based + +If we throw an error when the invocation isn't allowed instead of +returning false, we can simply return that error instead of duplicating +the error handling. + +Part-of: +--- + js/misc/introspect.js | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +diff --git a/js/misc/introspect.js b/js/misc/introspect.js +index e46a7e8c5..318955be2 100644 +--- a/js/misc/introspect.js ++++ b/js/misc/introspect.js +@@ -134,21 +134,23 @@ var IntrospectService = class { + type == Meta.WindowType.UTILITY; + } + +- _isInvocationAllowed(invocation) { ++ _checkInvocation(invocation) { + if (this._isIntrospectEnabled()) +- return true; ++ return; + + if (this._isSenderAllowed(invocation.get_sender())) +- return true; ++ return; + +- return false; ++ throw new GLib.Error(Gio.DBusError, ++ Gio.DBusError.ACCESS_DENIED, ++ 'App introspection not allowed'); + } + + GetRunningApplicationsAsync(params, invocation) { +- if (!this._isInvocationAllowed(invocation)) { +- invocation.return_error_literal(Gio.DBusError, +- Gio.DBusError.ACCESS_DENIED, +- 'App introspection not allowed'); ++ try { ++ this._checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); + return; + } + +@@ -160,10 +162,10 @@ var IntrospectService = class { + let apps = this._appSystem.get_running(); + let windowsList = {}; + +- if (!this._isInvocationAllowed(invocation)) { +- invocation.return_error_literal(Gio.DBusError, +- Gio.DBusError.ACCESS_DENIED, +- 'App introspection not allowed'); ++ try { ++ this._checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); + return; + } + +-- +2.35.1 + + +From 33c3c3846f62cc4737f0029455f9dcd838876bca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 1 Sep 2021 21:18:42 +0200 +Subject: [PATCH 05/12] introspect: Use MetaContext:unsafe-mode instead of + setting + +The property was added precisely for this purpose, except that its +name isn't tied to the introspect API. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/misc/introspect.js | 12 +----------- + 1 file changed, 1 insertion(+), 11 deletions(-) + +diff --git a/js/misc/introspect.js b/js/misc/introspect.js +index 318955be2..967e7b830 100644 +--- a/js/misc/introspect.js ++++ b/js/misc/introspect.js +@@ -1,8 +1,6 @@ + /* exported IntrospectService */ + const { Gio, GLib, Meta, Shell, St } = imports.gi; + +-const INTROSPECT_SCHEMA = 'org.gnome.shell'; +-const INTROSPECT_KEY = 'introspect'; + const APP_ALLOWLIST = ['org.freedesktop.impl.portal.desktop.gtk']; + + const INTROSPECT_DBUS_API_VERSION = 3; +@@ -33,10 +31,6 @@ var IntrospectService = class { + this._syncRunningApplications(); + }); + +- this._introspectSettings = new Gio.Settings({ +- schema_id: INTROSPECT_SCHEMA, +- }); +- + let tracker = Shell.WindowTracker.get_default(); + tracker.connect('notify::focus-app', + () => { +@@ -70,10 +64,6 @@ var IntrospectService = class { + return app.get_windows().some(w => w.transient_for == null); + } + +- _isIntrospectEnabled() { +- return this._introspectSettings.get_boolean(INTROSPECT_KEY); +- } +- + _isSenderAllowed(sender) { + return [...this._allowlistMap.values()].includes(sender); + } +@@ -135,7 +125,7 @@ var IntrospectService = class { + } + + _checkInvocation(invocation) { +- if (this._isIntrospectEnabled()) ++ if (global.context.unsafe_mode) + return; + + if (this._isSenderAllowed(invocation.get_sender())) +-- +2.35.1 + + +From 4238128ba403da2cc788b0b249ee34acbea5d743 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 1 Sep 2021 21:25:26 +0200 +Subject: [PATCH 06/12] data: Remove now unused "introspect" setting + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + data/org.gnome.shell.gschema.xml.in | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in +index d5ea1e35f..6f1c424ba 100644 +--- a/data/org.gnome.shell.gschema.xml.in ++++ b/data/org.gnome.shell.gschema.xml.in +@@ -104,14 +104,6 @@ + number can be used to effectively disable the dialog. + + +- +- false +- Enable introspection API +- +- Enables a D-Bus API that allows to introspect the application state of +- the shell. +- +- + + +Date: Wed, 16 Jun 2021 19:09:42 +0200 +Subject: [PATCH 07/12] introspect: Split out DBusSenderChecker + +Restricting callers to a list of allowed senders is useful for +other D-Bus services as well, so split out the existing code +into a reusable class. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/misc/introspect.js | 30 ++++------------------- + js/misc/util.js | 56 ++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 59 insertions(+), 27 deletions(-) + +diff --git a/js/misc/introspect.js b/js/misc/introspect.js +index 967e7b830..e9d9260c0 100644 +--- a/js/misc/introspect.js ++++ b/js/misc/introspect.js +@@ -6,6 +6,7 @@ const APP_ALLOWLIST = ['org.freedesktop.impl.portal.desktop.gtk']; + const INTROSPECT_DBUS_API_VERSION = 3; + + const { loadInterfaceXML } = imports.misc.fileUtils; ++const { DBusSenderChecker } = imports.misc.util; + + const IntrospectDBusIface = loadInterfaceXML('org.gnome.Shell.Introspect'); + +@@ -40,14 +41,7 @@ var IntrospectService = class { + + this._syncRunningApplications(); + +- this._allowlistMap = new Map(); +- APP_ALLOWLIST.forEach(appName => { +- Gio.DBus.watch_name(Gio.BusType.SESSION, +- appName, +- Gio.BusNameWatcherFlags.NONE, +- (conn, name, owner) => this._allowlistMap.set(name, owner), +- (conn, name) => this._allowlistMap.delete(name)); +- }); ++ this._senderChecker = new DBusSenderChecker(APP_ALLOWLIST); + + this._settings = St.Settings.get(); + this._settings.connect('notify::enable-animations', +@@ -64,10 +58,6 @@ var IntrospectService = class { + return app.get_windows().some(w => w.transient_for == null); + } + +- _isSenderAllowed(sender) { +- return [...this._allowlistMap.values()].includes(sender); +- } +- + _getSandboxedAppId(app) { + let ids = app.get_windows().map(w => w.get_sandboxed_app_id()); + return ids.find(id => id != null); +@@ -124,21 +114,9 @@ var IntrospectService = class { + type == Meta.WindowType.UTILITY; + } + +- _checkInvocation(invocation) { +- if (global.context.unsafe_mode) +- return; +- +- if (this._isSenderAllowed(invocation.get_sender())) +- return; +- +- throw new GLib.Error(Gio.DBusError, +- Gio.DBusError.ACCESS_DENIED, +- 'App introspection not allowed'); +- } +- + GetRunningApplicationsAsync(params, invocation) { + try { +- this._checkInvocation(invocation); ++ this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -153,7 +131,7 @@ var IntrospectService = class { + let windowsList = {}; + + try { +- this._checkInvocation(invocation); ++ this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +diff --git a/js/misc/util.js b/js/misc/util.js +index 802398d18..e6c183fbf 100644 +--- a/js/misc/util.js ++++ b/js/misc/util.js +@@ -2,7 +2,7 @@ + /* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine, + formatTime, formatTimeSpan, createTimeLabel, insertSorted, + ensureActorVisibleInScrollView, wiggle, lerp, GNOMEversionCompare, +- Highlighter */ ++ DBusSenderChecker, Highlighter */ + + const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi; + const Gettext = imports.gettext; +@@ -479,6 +479,60 @@ function GNOMEversionCompare(version1, version2) { + return 0; + } + ++var DBusSenderChecker = class { ++ /** ++ * @param {string[]} allowList - list of allowed well-known names ++ */ ++ constructor(allowList) { ++ this._allowlistMap = new Map(); ++ ++ this._watchList = allowList.map(name => { ++ return Gio.DBus.watch_name(Gio.BusType.SESSION, ++ name, ++ Gio.BusNameWatcherFlags.NONE, ++ (conn_, name_, owner) => this._allowlistMap.set(name, owner), ++ () => this._allowlistMap.delete(name)); ++ }); ++ } ++ ++ /** ++ * @param {string} sender - the bus name that invoked the checked method ++ * @returns {bool} ++ */ ++ _isSenderAllowed(sender) { ++ return [...this._allowlistMap.values()].includes(sender); ++ } ++ ++ /** ++ * Check whether the bus name that invoked @invocation maps ++ * to an entry in the allow list. ++ * ++ * @throws ++ * @param {Gio.DBusMethodInvocation} invocation - the invocation ++ * @returns {void} ++ */ ++ checkInvocation(invocation) { ++ if (global.context.unsafe_mode) ++ return; ++ ++ if (this._isSenderAllowed(invocation.get_sender())) ++ return; ++ ++ throw new GLib.Error(Gio.DBusError, ++ Gio.DBusError.ACCESS_DENIED, ++ '%s is not allowed'.format(invocation.get_method_name())); ++ } ++ ++ /** ++ * @returns {void} ++ */ ++ destroy() { ++ for (const id in this._watchList) ++ Gio.DBus.unwatch_name(id); ++ this._watchList = []; ++ } ++}; ++ + /* @class Highlighter Highlight given terms in text using markup. */ + var Highlighter = class { + /** +-- +2.35.1 + + +From c6679a876a3c73c2c691333a5b987e27965231f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 17 Jun 2021 15:29:42 +0200 +Subject: [PATCH 08/12] shellDBus: Implement all methods asynchronously + +In order to restrict callers, we will need access to the invocation, +not just the unpacked method parameters. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/ui/shellDBus.js | 31 ++++++++++++++++++++++++++++--- + 1 file changed, 28 insertions(+), 3 deletions(-) + +diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js +index 5a6edec74..aa5b4dc3c 100644 +--- a/js/ui/shellDBus.js ++++ b/js/ui/shellDBus.js +@@ -72,11 +72,26 @@ var GnomeShell = class { + return [success, returnValue]; + } + +- FocusSearch() { ++ /** ++ * Focus the overview's search entry ++ * ++ * @param {...any} params - method parameters ++ * @param {Gio.DBusMethodInvocation} invocation - the invocation ++ * @returns {void} ++ */ ++ FocusSearchAsync(params, invocation) { + Main.overview.focusSearch(); ++ invocation.return_value(null); + } + +- ShowOSD(params) { ++ /** ++ * Show OSD with the specified parameters ++ * ++ * @param {...any} params - method parameters ++ * @param {Gio.DBusMethodInvocation} invocation - the invocation ++ * @returns {void} ++ */ ++ ShowOSDAsync([params], invocation) { + for (let param in params) + params[param] = params[param].deep_unpack(); + +@@ -97,6 +112,7 @@ var GnomeShell = class { + icon = Gio.Icon.new_for_string(serializedIcon); + + Main.osdWindowManager.show(monitorIndex, icon, label, level, maxLevel); ++ invocation.return_value(null); + } + + /** +@@ -118,10 +134,19 @@ var GnomeShell = class { + } + + Main.overview.selectApp(id); ++ invocation.return_value(null); + } + +- ShowApplications() { ++ /** ++ * Show the overview's app grid ++ * ++ * @param {...any} params - method parameters ++ * @param {Gio.DBusMethodInvocation} invocation - the invocation ++ * @returns {void} ++ */ ++ ShowApplicationsAsync(params, invocation) { + Main.overview.show(ControlsState.APP_GRID); ++ invocation.return_value(null); + } + + GrabAcceleratorAsync(params, invocation) { +-- +2.35.1 + + +From 3ad733997eecb069be543f1a4452d7a7916a0962 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 17 Jun 2021 15:29:42 +0200 +Subject: [PATCH 09/12] shellDBus: Restrict callers + +The org.gnome.Shell interface provides a private API to other core +components to implement desktop functionalities like Settings or +global keybindings. It is not meant as a public API, so limit it +to a set of expected callers. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/ui/shellDBus.js | 76 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 76 insertions(+) + +diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js +index aa5b4dc3c..c511314f9 100644 +--- a/js/ui/shellDBus.js ++++ b/js/ui/shellDBus.js +@@ -10,6 +10,7 @@ const Main = imports.ui.main; + const Screenshot = imports.ui.screenshot; + + const { loadInterfaceXML } = imports.misc.fileUtils; ++const { DBusSenderChecker } = imports.misc.util; + const { ControlsState } = imports.ui.overviewControls; + + const GnomeShellIface = loadInterfaceXML('org.gnome.Shell'); +@@ -20,6 +21,11 @@ var GnomeShell = class { + this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellIface, this); + this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell'); + ++ this._senderChecker = new DBusSenderChecker([ ++ 'org.gnome.ControlCenter', ++ 'org.gnome.SettingsDaemon.MediaKeys', ++ ]); ++ + this._extensionsService = new GnomeShellExtensions(); + this._screenshotService = new Screenshot.ScreenshotService(); + +@@ -80,6 +86,13 @@ var GnomeShell = class { + * @returns {void} + */ + FocusSearchAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + Main.overview.focusSearch(); + invocation.return_value(null); + } +@@ -92,6 +105,13 @@ var GnomeShell = class { + * @returns {void} + */ + ShowOSDAsync([params], invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + for (let param in params) + params[param] = params[param].deep_unpack(); + +@@ -124,6 +144,13 @@ var GnomeShell = class { + * @returns {void} + */ + FocusAppAsync([id], invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + const appSys = Shell.AppSystem.get_default(); + if (appSys.lookup_app(id) === null) { + invocation.return_error_literal( +@@ -145,11 +172,25 @@ var GnomeShell = class { + * @returns {void} + */ + ShowApplicationsAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + Main.overview.show(ControlsState.APP_GRID); + invocation.return_value(null); + } + + GrabAcceleratorAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let [accel, modeFlags, grabFlags] = params; + let sender = invocation.get_sender(); + let bindingAction = this._grabAcceleratorForSender(accel, modeFlags, grabFlags, sender); +@@ -157,6 +198,13 @@ var GnomeShell = class { + } + + GrabAcceleratorsAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let [accels] = params; + let sender = invocation.get_sender(); + let bindingActions = []; +@@ -168,6 +216,13 @@ var GnomeShell = class { + } + + UngrabAcceleratorAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let [action] = params; + let sender = invocation.get_sender(); + let ungrabSucceeded = this._ungrabAcceleratorForSender(action, sender); +@@ -176,6 +231,13 @@ var GnomeShell = class { + } + + UngrabAcceleratorsAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let [actions] = params; + let sender = invocation.get_sender(); + let ungrabSucceeded = true; +@@ -256,6 +318,13 @@ var GnomeShell = class { + } + + ShowMonitorLabelsAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let sender = invocation.get_sender(); + let [dict] = params; + Main.osdMonitorLabeler.show(sender, dict); +@@ -263,6 +332,13 @@ var GnomeShell = class { + } + + HideMonitorLabelsAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let sender = invocation.get_sender(); + Main.osdMonitorLabeler.hide(sender); + invocation.return_value(null); +-- +2.35.1 + + +From 5b87782b4950742b6ae1b29777e7812c93892ad7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 16 Jun 2021 22:11:50 +0200 +Subject: [PATCH 10/12] screenshot: Restrict callers + +The shell D-Bus API was always meant as a private API for core +components, so enforce that by limiting caller to a list of +allowed well-known names. + +Applications that want to request a screenshot can use the corresponding +desktop portal. + +https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943 + +Part-of: +--- + js/ui/screenshot.js | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js +index 81ab516b1..bf537b7d6 100644 +--- a/js/ui/screenshot.js ++++ b/js/ui/screenshot.js +@@ -15,6 +15,7 @@ Gio._promisify(Shell.Screenshot.prototype, + 'screenshot_area', 'screenshot_area_finish'); + + const { loadInterfaceXML } = imports.misc.fileUtils; ++const { DBusSenderChecker } = imports.misc.util; + + const ScreenshotIface = loadInterfaceXML('org.gnome.Shell.Screenshot'); + +@@ -24,6 +25,12 @@ var ScreenshotService = class { + this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screenshot'); + + this._screenShooter = new Map(); ++ this._senderChecker = new DBusSenderChecker([ ++ 'org.gnome.SettingsDaemon.MediaKeys', ++ 'org.freedesktop.impl.portal.desktop.gtk', ++ 'org.freedesktop.impl.portal.desktop.gnome', ++ 'org.gnome.Screenshot', ++ ]); + + this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' }); + +@@ -46,6 +53,13 @@ var ScreenshotService = class { + Gio.IOErrorEnum, Gio.IOErrorEnum.PERMISSION_DENIED, + 'Saving to disk is disabled'); + return null; ++ } else { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return null; ++ } + } + + let shooter = new Shell.Screenshot(); +@@ -254,6 +268,13 @@ var ScreenshotService = class { + } + + async SelectAreaAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let selectArea = new SelectArea(); + try { + let areaRectangle = await selectArea.selectAsync(); +@@ -269,6 +290,13 @@ var ScreenshotService = class { + } + + FlashAreaAsync(params, invocation) { ++ try { ++ this._senderChecker.checkInvocation(invocation); ++ } catch (e) { ++ invocation.return_gerror(e); ++ return; ++ } ++ + let [x, y, width, height] = params; + [x, y, width, height] = this._scaleArea(x, y, width, height); + if (!this._checkArea(x, y, width, height)) { +-- +2.35.1 + + +From b02e721663ed1481ff7b4cf40cae3a34d059d90c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sat, 25 Sep 2021 14:15:32 +0200 +Subject: [PATCH 11/12] screenshot: Unrestrict PickColor + +Commit dd2cd6286cd3 restricted callers of the screenshot methods to +portal implementations, gnome-settings-daemon and gnome-screenshot. + +That restriction does make sense for the actual screenshot methods, +but `PickColor` is actually used by GTK in its color picker (and +therefore may be called from arbitrary applications). + +Fix this by unrestricting access to `PickColor` again. Considering that +the method is always interactive, it's not very privacy/security-sensitive +anyway. + +https://gitlab.gnome.org/GNOME/gtk/-/issues/4283 + +Part-of: +--- + js/ui/screenshot.js | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js +index bf537b7d6..ae1156f47 100644 +--- a/js/ui/screenshot.js ++++ b/js/ui/screenshot.js +@@ -37,7 +37,7 @@ var ScreenshotService = class { + Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null); + } + +- _createScreenshot(invocation, needsDisk = true) { ++ _createScreenshot(invocation, needsDisk = true, restrictCallers = true) { + let lockedDown = false; + if (needsDisk) + lockedDown = this._lockdownSettings.get_boolean('disable-save-to-disk'); +@@ -53,7 +53,7 @@ var ScreenshotService = class { + Gio.IOErrorEnum, Gio.IOErrorEnum.PERMISSION_DENIED, + 'Saving to disk is disabled'); + return null; +- } else { ++ } else if (restrictCallers) { + try { + this._senderChecker.checkInvocation(invocation); + } catch (e) { +@@ -311,7 +311,7 @@ var ScreenshotService = class { + } + + async PickColorAsync(params, invocation) { +- const screenshot = this._createScreenshot(invocation, false); ++ const screenshot = this._createScreenshot(invocation, false, false); + if (!screenshot) + return; + +-- +2.35.1 + + +From 9e8073afbf30aaea87aefd8201fc5e04f94edaf8 Mon Sep 17 00:00:00 2001 +From: Sebastian Keller +Date: Tue, 23 Nov 2021 02:48:04 +0100 +Subject: [PATCH 12/12] util: Wait for initial name owners in DBusSenderCheck + before checking + +Otherwise an allowed caller might get rejected if the call is right +after a gnome-shell restart and the watchers have not finished running +their callbacks yet. + +Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4813 +Part-of: +(cherry picked from commit 85609a232d4088b058f23f4922b9a993dea95199) +--- + js/misc/introspect.js | 8 ++++---- + js/misc/util.js | 33 ++++++++++++++++++++++++++++----- + js/ui/screenshot.js | 18 +++++++++--------- + js/ui/shellDBus.js | 43 +++++++++++++++++++++++-------------------- + 4 files changed, 64 insertions(+), 38 deletions(-) + +diff --git a/js/misc/introspect.js b/js/misc/introspect.js +index e9d9260c0..f3c938af9 100644 +--- a/js/misc/introspect.js ++++ b/js/misc/introspect.js +@@ -114,9 +114,9 @@ var IntrospectService = class { + type == Meta.WindowType.UTILITY; + } + +- GetRunningApplicationsAsync(params, invocation) { ++ async GetRunningApplicationsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -125,13 +125,13 @@ var IntrospectService = class { + invocation.return_value(new GLib.Variant('(a{sa{sv}})', [this._runningApplications])); + } + +- GetWindowsAsync(params, invocation) { ++ async GetWindowsAsync(params, invocation) { + let focusWindow = global.display.get_focus_window(); + let apps = this._appSystem.get_running(); + let windowsList = {}; + + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +diff --git a/js/misc/util.js b/js/misc/util.js +index e6c183fbf..6a0f6f641 100644 +--- a/js/misc/util.js ++++ b/js/misc/util.js +@@ -486,20 +486,42 @@ var DBusSenderChecker = class { + constructor(allowList) { + this._allowlistMap = new Map(); + ++ this._uninitializedNames = new Set(allowList); ++ this._initializedPromise = new Promise(resolve => { ++ this._resolveInitialized = resolve; ++ }); ++ + this._watchList = allowList.map(name => { + return Gio.DBus.watch_name(Gio.BusType.SESSION, + name, + Gio.BusNameWatcherFlags.NONE, +- (conn_, name_, owner) => this._allowlistMap.set(name, owner), +- () => this._allowlistMap.delete(name)); ++ (conn_, name_, owner) => { ++ this._allowlistMap.set(name, owner); ++ this._checkAndResolveInitialized(name); ++ }, ++ () => { ++ this._allowlistMap.delete(name); ++ this._checkAndResolveInitialized(name); ++ }); + }); + } + + /** ++ * @param {string} name - bus name for which the watcher got initialized ++ */ ++ _checkAndResolveInitialized(name) { ++ if (this._uninitializedNames.delete(name) && ++ this._uninitializedNames.size === 0) ++ this._resolveInitialized(); ++ } ++ ++ /** ++ * @async + * @param {string} sender - the bus name that invoked the checked method + * @returns {bool} + */ +- _isSenderAllowed(sender) { ++ async _isSenderAllowed(sender) { ++ await this._initializedPromise; + return [...this._allowlistMap.values()].includes(sender); + } + +@@ -507,15 +529,16 @@ var DBusSenderChecker = class { + * Check whether the bus name that invoked @invocation maps + * to an entry in the allow list. + * ++ * @async + * @throws + * @param {Gio.DBusMethodInvocation} invocation - the invocation + * @returns {void} + */ +- checkInvocation(invocation) { ++ async checkInvocation(invocation) { + if (global.context.unsafe_mode) + return; + +- if (this._isSenderAllowed(invocation.get_sender())) ++ if (await this._isSenderAllowed(invocation.get_sender())) + return; + + throw new GLib.Error(Gio.DBusError, +diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js +index ae1156f47..97fcfacd0 100644 +--- a/js/ui/screenshot.js ++++ b/js/ui/screenshot.js +@@ -37,7 +37,7 @@ var ScreenshotService = class { + Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null); + } + +- _createScreenshot(invocation, needsDisk = true, restrictCallers = true) { ++ async _createScreenshot(invocation, needsDisk = true, restrictCallers = true) { + let lockedDown = false; + if (needsDisk) + lockedDown = this._lockdownSettings.get_boolean('disable-save-to-disk'); +@@ -55,7 +55,7 @@ var ScreenshotService = class { + return null; + } else if (restrictCallers) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return null; +@@ -200,7 +200,7 @@ var ScreenshotService = class { + "Invalid params"); + return; + } +- let screenshot = this._createScreenshot(invocation); ++ let screenshot = await this._createScreenshot(invocation); + if (!screenshot) + return; + +@@ -223,7 +223,7 @@ var ScreenshotService = class { + + async ScreenshotWindowAsync(params, invocation) { + let [includeFrame, includeCursor, flash, filename] = params; +- let screenshot = this._createScreenshot(invocation); ++ let screenshot = await this._createScreenshot(invocation); + if (!screenshot) + return; + +@@ -246,7 +246,7 @@ var ScreenshotService = class { + + async ScreenshotAsync(params, invocation) { + let [includeCursor, flash, filename] = params; +- let screenshot = this._createScreenshot(invocation); ++ let screenshot = await this._createScreenshot(invocation); + if (!screenshot) + return; + +@@ -269,7 +269,7 @@ var ScreenshotService = class { + + async SelectAreaAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -289,9 +289,9 @@ var ScreenshotService = class { + } + } + +- FlashAreaAsync(params, invocation) { ++ async FlashAreaAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -311,7 +311,7 @@ var ScreenshotService = class { + } + + async PickColorAsync(params, invocation) { +- const screenshot = this._createScreenshot(invocation, false, false); ++ const screenshot = await this._createScreenshot(invocation, false, false); + if (!screenshot) + return; + +diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js +index c511314f9..39bba7aa3 100644 +--- a/js/ui/shellDBus.js ++++ b/js/ui/shellDBus.js +@@ -81,13 +81,14 @@ var GnomeShell = class { + /** + * Focus the overview's search entry + * ++ * @async + * @param {...any} params - method parameters + * @param {Gio.DBusMethodInvocation} invocation - the invocation + * @returns {void} + */ +- FocusSearchAsync(params, invocation) { ++ async FocusSearchAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -100,13 +101,14 @@ var GnomeShell = class { + /** + * Show OSD with the specified parameters + * ++ * @async + * @param {...any} params - method parameters + * @param {Gio.DBusMethodInvocation} invocation - the invocation + * @returns {void} + */ +- ShowOSDAsync([params], invocation) { ++ async ShowOSDAsync([params], invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -143,9 +145,9 @@ var GnomeShell = class { + * @param {Gio.DBusMethodInvocation} invocation - the invocation + * @returns {void} + */ +- FocusAppAsync([id], invocation) { ++ async FocusAppAsync([id], invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -167,13 +169,14 @@ var GnomeShell = class { + /** + * Show the overview's app grid + * ++ * @async + * @param {...any} params - method parameters + * @param {Gio.DBusMethodInvocation} invocation - the invocation + * @returns {void} + */ +- ShowApplicationsAsync(params, invocation) { ++ async ShowApplicationsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -183,9 +186,9 @@ var GnomeShell = class { + invocation.return_value(null); + } + +- GrabAcceleratorAsync(params, invocation) { ++ async GrabAcceleratorAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -197,9 +200,9 @@ var GnomeShell = class { + invocation.return_value(GLib.Variant.new('(u)', [bindingAction])); + } + +- GrabAcceleratorsAsync(params, invocation) { ++ async GrabAcceleratorsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -215,9 +218,9 @@ var GnomeShell = class { + invocation.return_value(GLib.Variant.new('(au)', [bindingActions])); + } + +- UngrabAcceleratorAsync(params, invocation) { ++ async UngrabAcceleratorAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -230,9 +233,9 @@ var GnomeShell = class { + invocation.return_value(GLib.Variant.new('(b)', [ungrabSucceeded])); + } + +- UngrabAcceleratorsAsync(params, invocation) { ++ async UngrabAcceleratorsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -317,9 +320,9 @@ var GnomeShell = class { + this._grabbers.delete(name); + } + +- ShowMonitorLabelsAsync(params, invocation) { ++ async ShowMonitorLabelsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +@@ -331,9 +334,9 @@ var GnomeShell = class { + invocation.return_value(null); + } + +- HideMonitorLabelsAsync(params, invocation) { ++ async HideMonitorLabelsAsync(params, invocation) { + try { +- this._senderChecker.checkInvocation(invocation); ++ await this._senderChecker.checkInvocation(invocation); + } catch (e) { + invocation.return_gerror(e); + return; +-- +2.35.1 + diff --git a/root-warning.patch b/root-warning.patch deleted file mode 100644 index 35b2c44528395869bc1c085c2078ecd77d29a32a..0000000000000000000000000000000000000000 --- a/root-warning.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 45ddeeaa317fb0ffd045600d9e4b95143c9ca8b8 Mon Sep 17 00:00:00 2001 -From: Matthias Clasen -Date: Sat, 8 Jun 2013 13:32:35 -0400 -Subject: [PATCH 1/2] main: Show a warning when running as root - -gnome-session used to show a dialog in this case, but a -notification is more natural nowadays. Doing it in gnome-shell -avoids complicated synchronization between gnome-session and -gnome-shell. - -https://bugzilla.gnome.org/show_bug.cgi?id=701212 ---- - js/ui/main.js | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/js/ui/main.js b/js/ui/main.js -index 8d1755cf1..abf8a8765 100644 ---- a/js/ui/main.js -+++ b/js/ui/main.js -@@ -237,6 +237,12 @@ function _initializeUI() { - ['MESSAGE_ID=' + GNOMESHELL_STARTED_MESSAGE_ID]); - } - -+ let credentials = new Gio.Credentials(); -+ if (credentials.get_unix_user() === 0) { -+ notify(_('Logged in as a privileged user'), -+ _('Running a session as a privileged user should be avoided for security reasons. If possible, you should log in as a normal user.')); -+ } -+ - let perfModuleName = GLib.getenv("SHELL_PERF_MODULE"); - if (perfModuleName) { - let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT"); --- -2.23.0 - - -From 8e82907909b6a2e5af5da3f93b087df4b7eb48b5 Mon Sep 17 00:00:00 2001 -From: Matthias Clasen -Date: Sat, 8 Jun 2013 13:33:58 -0400 -Subject: [PATCH 2/2] main: Show a warning when gdm is missing - -If we are not running under gdm, some functionaliy (such as -the lock screen) does not work, and we should inform the -user about this. - -https://bugzilla.gnome.org/show_bug.cgi?id=701212 ---- - js/ui/main.js | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/js/ui/main.js b/js/ui/main.js -index abf8a8765..be49c750e 100644 ---- a/js/ui/main.js -+++ b/js/ui/main.js -@@ -243,6 +243,13 @@ function _initializeUI() { - _('Running a session as a privileged user should be avoided for security reasons. If possible, you should log in as a normal user.')); - } - -+ if (sessionMode.currentMode !== 'gdm' && -+ sessionMode.currentMode !== 'initial-setup' && -+ screenShield === null) { -+ notify(_('Screen Lock disabled'), -+ _('Screen Locking requires the GNOME display manager.')); -+ } -+ - let perfModuleName = GLib.getenv("SHELL_PERF_MODULE"); - if (perfModuleName) { - let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT"); --- -2.23.0 - diff --git a/support-choicelist-extension.patch b/support-choicelist-extension.patch new file mode 100644 index 0000000000000000000000000000000000000000..54e226fb47f42b7a94e1e2d03b6e9b97f1648360 --- /dev/null +++ b/support-choicelist-extension.patch @@ -0,0 +1,1210 @@ +From f821b65401284cc31f68f0eb1b2e71ae3a90a122 Mon Sep 17 00:00:00 2001 +From: Ray Strode +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. +--- + .../widgets/_login-dialog.scss | 26 +++ + js/gdm/authList.js | 176 ++++++++++++++++++ + js/js-resources.gresource.xml | 1 + + 3 files changed, 203 insertions(+) + create mode 100644 js/gdm/authList.js + +diff --git a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss +index 84539342d..f68d5de99 100644 +--- a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss ++++ b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss +@@ -86,60 +86,86 @@ + .caps-lock-warning-label, + .login-dialog-message-warning { + color: $osd_fg_color; + } + } + + .login-dialog-logo-bin { padding: 24px 0px; } + .login-dialog-banner { color: darken($osd_fg_color,10%); } + .login-dialog-button-box { width: 23em; spacing: 5px; } + .login-dialog-message { text-align: center; } + .login-dialog-message-hint, .login-dialog-message { + color: darken($osd_fg_color, 20%); + min-height: 2.75em; + } + .login-dialog-user-selection-box { padding: 100px 0px; } + .login-dialog-not-listed-label { + padding-left: 2px; + .login-dialog-not-listed-button:focus &, + .login-dialog-not-listed-button:hover & { + color: $osd_fg_color; + } + } + + .login-dialog-not-listed-label { + @include fontsize($base_font_size - 1); + font-weight: bold; + color: darken($osd_fg_color,30%); + padding-top: 1em; + } + ++.login-dialog-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: $base_border_radius + 4px; ++ padding: 6px; ++ color: darken($osd_fg_color,30%); ++ &:focus, &:selected { background-color: $selected_bg_color; color: $selected_fg_color; } ++} ++ ++.login-dialog-auth-list-label { ++ @include fontsize($base_font_size + 2); ++ font-weight: bold; ++ padding-left: 15px; ++ ++ &:ltr { padding-left: 14px; text-align: left; } ++ &:rtl { padding-right: 14px; text-align: right; } ++} ++ + .login-dialog-user-list-view { -st-vfade-offset: 1em; } + .login-dialog-user-list { + spacing: 12px; + width: 23em; + &:expanded .login-dialog-user-list-item:selected { background-color: $selected_bg_color; color: $selected_fg_color; } + &:expanded .login-dialog-user-list-item:logged-in { border-right: 2px solid $selected_bg_color; } + } + + .login-dialog-user-list-item { + border-radius: $base_border_radius + 4px; + padding: 6px; + color: darken($osd_fg_color,30%); + &:ltr .user-widget { padding-right: 1em; } + &:rtl .user-widget { padding-left: 1em; } + .login-dialog-timed-login-indicator { + height: 2px; + margin-top: 6px; + background-color: $osd_fg_color; + } + &:focus .login-dialog-timed-login-indicator { background-color: $selected_fg_color; } + } + + .user-widget-label { + color: $osd_fg_color; + } + + .user-widget.horizontal .user-widget-label { + @include fontsize($base_font_size + 2); + font-weight: bold; + padding-left: 15px; +diff --git a/js/gdm/authList.js b/js/gdm/authList.js +new file mode 100644 +index 000000000..fb223a972 +--- /dev/null ++++ b/js/gdm/authList.js +@@ -0,0 +1,176 @@ ++// -*- 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 . ++ */ ++/* exported AuthList */ ++ ++const { Clutter, GObject, Meta, St } = imports.gi; ++ ++const SCROLL_ANIMATION_TIME = 500; ++ ++const AuthListItem = GObject.registerClass({ ++ Signals: { 'activate': {} }, ++}, class AuthListItem extends St.Button { ++ _init(key, text) { ++ this.key = key; ++ const label = new St.Label({ ++ text, ++ style_class: 'login-dialog-auth-list-label', ++ y_align: Clutter.ActorAlign.CENTER, ++ x_expand: false, ++ }); ++ ++ super._init({ ++ style_class: 'login-dialog-auth-list-item', ++ button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, ++ can_focus: true, ++ child: label, ++ reactive: true, ++ }); ++ ++ this.connect('key-focus-in', ++ () => this._setSelected(true)); ++ this.connect('key-focus-out', ++ () => this._setSelected(false)); ++ this.connect('notify::hover', ++ () => this._setSelected(this.hover)); ++ ++ this.connect('clicked', this._onClicked.bind(this)); ++ } ++ ++ _onClicked() { ++ this.emit('activate'); ++ } ++ ++ _setSelected(selected) { ++ if (selected) { ++ this.add_style_pseudo_class('selected'); ++ this.grab_key_focus(); ++ } else { ++ this.remove_style_pseudo_class('selected'); ++ } ++ } ++}); ++ ++var AuthList = GObject.registerClass({ ++ Signals: { ++ 'activate': { param_types: [GObject.TYPE_STRING] }, ++ 'item-added': { param_types: [AuthListItem.$gtype] }, ++ }, ++}, class AuthList extends St.BoxLayout { ++ _init() { ++ super._init({ ++ vertical: true, ++ style_class: 'login-dialog-auth-list-layout', ++ x_align: Clutter.ActorAlign.START, ++ y_align: Clutter.ActorAlign.CENTER, ++ }); ++ ++ this.label = new St.Label({ style_class: 'login-dialog-auth-list-title' }); ++ this.add_child(this.label); ++ ++ this._scrollView = new St.ScrollView({ ++ style_class: 'login-dialog-auth-list-view', ++ }); ++ this._scrollView.set_policy( ++ St.PolicyType.NEVER, St.PolicyType.AUTOMATIC); ++ this.add_child(this._scrollView); ++ ++ this._box = new St.BoxLayout({ ++ vertical: true, ++ style_class: 'login-dialog-auth-list', ++ pseudo_class: 'expanded', ++ }); ++ ++ this._scrollView.add_actor(this._box); ++ this._items = new Map(); ++ ++ this.connect('key-focus-in', this._moveFocusToItems.bind(this)); ++ } ++ ++ _moveFocusToItems() { ++ let hasItems = this.numItems > 0; ++ ++ if (!hasItems) ++ return; ++ ++ if (global.stage.get_key_focus() !== this) ++ return; ++ ++ let focusSet = this.navigate_focus(null, St.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.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.ease(value, { ++ duration: SCROLL_ANIMATION_TIME, ++ mode: Clutter.AnimationMode.EASE_OUT_QUAD, ++ }); ++ } ++ ++ addItem(key, text) { ++ this.removeItem(key); ++ ++ let item = new AuthListItem(key, text); ++ this._box.add(item); ++ ++ this._items.set(key, item); ++ ++ item.connect('activate', this._onItemActivated.bind(this)); ++ ++ // Try to keep the focused item front-and-center ++ item.connect('key-focus-in', () => this.scrollToItem(item)); ++ ++ this._moveFocusToItems(); ++ ++ this.emit('item-added', item); ++ } ++ ++ removeItem(key) { ++ if (!this._items.has(key)) ++ return; ++ ++ let item = this._items.get(key); ++ ++ item.destroy(); ++ ++ this._items.delete(key); ++ } ++ ++ get numItems() { ++ return this._items.size; ++ } ++ ++ clear() { ++ this.label.text = ''; ++ this._box.destroy_all_children(); ++ this._items.clear(); ++ } ++}); +diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml +index e65e0e9cf..b2c603a55 100644 +--- a/js/js-resources.gresource.xml ++++ b/js/js-resources.gresource.xml +@@ -1,33 +1,34 @@ + + + ++ gdm/authList.js + gdm/authPrompt.js + gdm/batch.js + gdm/loginDialog.js + gdm/oVirt.js + gdm/credentialManager.js + gdm/vmware.js + gdm/realmd.js + gdm/util.js + + misc/config.js + misc/extensionUtils.js + misc/fileUtils.js + misc/gnomeSession.js + misc/history.js + misc/ibusManager.js + misc/inputMethod.js + misc/introspect.js + misc/jsParse.js + misc/keyboardManager.js + misc/loginManager.js + misc/modemManager.js + misc/objectManager.js + misc/params.js + misc/parentalControlsManager.js + misc/permissionStore.js + misc/smartcardManager.js + misc/systemActions.js + misc/util.js + misc/weather.js + +-- +2.34.1 + +From 5a2fda2fe2526f81c4dbbee6512182f19fc76a74 Mon Sep 17 00:00:00 2001 +From: Ray Strode +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 | 71 +++++++++++++++++++++++++++++++++++++++++-- + js/gdm/loginDialog.js | 5 +++ + js/gdm/util.js | 28 +++++++++++++++++ + js/ui/unlockDialog.js | 7 +++++ + 4 files changed, 109 insertions(+), 2 deletions(-) + +diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js +index 84c608b2f..4da91e096 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -1,36 +1,37 @@ + // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + /* exported AuthPrompt */ + + const { Clutter, GLib, GObject, Meta, Pango, Shell, St } = imports.gi; + + const Animation = imports.ui.animation; ++const AuthList = imports.gdm.authList; + const Batch = imports.gdm.batch; + const GdmUtil = imports.gdm.util; + const OVirt = imports.gdm.oVirt; + const Vmware = imports.gdm.vmware; + const Params = imports.misc.params; + const ShellEntry = imports.ui.shellEntry; + const UserWidget = imports.ui.userWidget; + const Util = imports.misc.util; + + var DEFAULT_BUTTON_WELL_ICON_SIZE = 16; + var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1000; + var DEFAULT_BUTTON_WELL_ANIMATION_TIME = 300; + + var MESSAGE_FADE_OUT_ANIMATION_TIME = 500; + + var AuthPromptMode = { + UNLOCK_ONLY: 0, + UNLOCK_OR_LOG_IN: 1, + }; + + var AuthPromptStatus = { + NOT_VERIFYING: 0, + VERIFYING: 1, + VERIFICATION_FAILED: 2, + VERIFICATION_SUCCEEDED: 3, + VERIFICATION_CANCELLED: 4, + VERIFICATION_IN_PROGRESS: 5, + }; + + var BeginRequestType = { +@@ -48,144 +49,164 @@ var AuthPrompt = GObject.registerClass({ + 'reset': { param_types: [GObject.TYPE_UINT] }, + }, + }, class AuthPrompt extends St.BoxLayout { + _init(gdmClient, mode) { + super._init({ + style_class: 'login-dialog-prompt-layout', + vertical: true, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + }); + + this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; + + this._gdmClient = gdmClient; + this._mode = mode; + this._defaultButtonWellActor = null; + this._cancelledRetries = 0; + + this._idleMonitor = Meta.IdleMonitor.get_core(); + + let reauthenticationOnly; + if (this._mode == AuthPromptMode.UNLOCK_ONLY) + reauthenticationOnly = true; + else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) + reauthenticationOnly = false; + + this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly }); + + 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)); + this._userVerifier.connect('smartcard-status-changed', this._onSmartcardStatusChanged.bind(this)); + this._userVerifier.connect('credential-manager-authenticated', this._onCredentialManagerAuthenticated.bind(this)); + this.smartcardDetected = this._userVerifier.smartcardDetected; + + this.connect('destroy', this._onDestroy.bind(this)); + + this._userWell = new St.Bin({ + x_expand: true, + y_expand: true, + }); + this.add_child(this._userWell); + + this._hasCancelButton = this._mode === AuthPromptMode.UNLOCK_OR_LOG_IN; + +- this._initEntryRow(); ++ this._initInputRow(); + + let capsLockPlaceholder = new St.Label(); + this.add_child(capsLockPlaceholder); + + this._capsLockWarningLabel = new ShellEntry.CapsLockWarning({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(this._capsLockWarningLabel); + + this._capsLockWarningLabel.bind_property('visible', + capsLockPlaceholder, 'visible', + GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN); + + this._message = new St.Label({ + opacity: 0, + styleClass: 'login-dialog-message', + y_expand: true, + x_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.CENTER, + }); + this._message.clutter_text.line_wrap = true; + this._message.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; + this.add_child(this._message); + } + + _onDestroy() { + if (this._preemptiveAnswerWatchId) { + this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); + this._preemptiveAnswerWatchId = 0; + } + + this._userVerifier.destroy(); + this._userVerifier = null; + } + + vfunc_key_press_event(keyPressEvent) { + if (keyPressEvent.keyval == Clutter.KEY_Escape) + this.cancel(); + return super.vfunc_key_press_event(keyPressEvent); + } + +- _initEntryRow() { ++ _initInputRow() { + this._mainBox = new St.BoxLayout({ + style_class: 'login-dialog-button-box', + vertical: false, + }); + this.add_child(this._mainBox); + + this.cancelButton = new St.Button({ + style_class: 'modal-dialog-button button cancel-button', + accessible_name: _('Cancel'), + button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, + reactive: this._hasCancelButton, + can_focus: this._hasCancelButton, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER, + child: new St.Icon({ icon_name: 'go-previous-symbolic' }), + }); + if (this._hasCancelButton) + this.cancelButton.connect('clicked', () => this.cancel()); + else + this.cancelButton.opacity = 0; + this._mainBox.add_child(this.cancelButton); + ++ this._authList = new AuthList.AuthList(); ++ this._authList.set({ ++ visible: false, ++ }); ++ this._authList.connect('activate', (list, key) => { ++ this._authList.reactive = false; ++ this._authList.ease({ ++ opacity: 0, ++ duration: MESSAGE_FADE_OUT_ANIMATION_TIME, ++ mode: Clutter.AnimationMode.EASE_OUT_QUAD, ++ onComplete: () => { ++ this._authList.clear(); ++ this._authList.hide(); ++ this._userVerifier.selectChoice(this._queryingService, key); ++ }, ++ }); ++ }); ++ this._mainBox.add_child(this._authList); ++ + let entryParams = { + style_class: 'login-dialog-prompt-entry', + can_focus: true, + x_expand: true, + }; + + this._entry = null; + + this._textEntry = new St.Entry(entryParams); + ShellEntry.addContextMenu(this._textEntry, { actionMode: Shell.ActionMode.NONE }); + + this._passwordEntry = new St.PasswordEntry(entryParams); + ShellEntry.addContextMenu(this._passwordEntry, { actionMode: Shell.ActionMode.NONE }); + + this._entry = this._passwordEntry; + this._mainBox.add_child(this._entry); + this._entry.grab_key_focus(); + + this._timedLoginIndicator = new St.Bin({ + style_class: 'login-dialog-timed-login-indicator', + scale_x: 0, + }); + + this.add_child(this._timedLoginIndicator); + + [this._textEntry, this._passwordEntry].forEach(entry => { + entry.clutter_text.connect('text-changed', () => { + if (!this._userVerifier.hasPendingMessages && this._queryingService && !this._preemptiveAnswer) + this._fadeOutMessage(); + }); +@@ -276,60 +297,74 @@ var AuthPrompt = GObject.registerClass({ + this._entry = this._textEntry; + } + this._capsLockWarningLabel.visible = secret; + } + + _onAskQuestion(verifier, serviceName, question, secret) { + if (this._queryingService) + this.clear(); + + this._queryingService = serviceName; + if (this._preemptiveAnswer) { + this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer); + this._preemptiveAnswer = null; + return; + } + + this._updateEntry(secret); + + // Hack: The question string comes directly from PAM, if it's "Password:" + // we replace it with our own to allow localization, if it's something + // else we remove the last colon and any trailing or leading spaces. + if (question === 'Password:' || question === 'Password: ') + this.setQuestion(_('Password')); + else + this.setQuestion(question.replace(/: *$/, '').trim()); + + this.updateSensitivity(true); + this.emit('prompted'); + } + ++ _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.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) { +@@ -411,109 +446,141 @@ var AuthPrompt = GObject.registerClass({ + if (actor) { + if (isSpinner) + this._spinner.play(); + + if (!animate) { + actor.opacity = 255; + } else { + actor.ease({ + opacity: 255, + duration: DEFAULT_BUTTON_WELL_ANIMATION_TIME, + delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, + mode: Clutter.AnimationMode.LINEAR, + }); + } + } + + this._defaultButtonWellActor = actor; + } + + startSpinning() { + this.setActorInDefaultButtonWell(this._spinner, true); + } + + stopSpinning() { + this.setActorInDefaultButtonWell(null, false); + } + + clear() { + this._entry.text = ''; + this.stopSpinning(); ++ this._authList.clear(); ++ this._authList.hide(); + } + + setQuestion(question) { + if (this._preemptiveAnswerWatchId) { + this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); + this._preemptiveAnswerWatchId = 0; + } + + this._entry.hint_text = question; + ++ this._authList.hide(); + this._entry.show(); + this._entry.grab_key_focus(); + } + ++ _fadeInChoiceList() { ++ this._authList.set({ ++ opacity: 0, ++ visible: true, ++ reactive: false, ++ }); ++ this._authList.ease({ ++ opacity: 255, ++ duration: MESSAGE_FADE_OUT_ANIMATION_TIME, ++ transition: Clutter.AnimationMode.EASE_OUT_QUAD, ++ onComplete: () => (this._authList.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._entry.hide(); ++ if (this._message.text === '') ++ this._message.hide(); ++ this._fadeInChoiceList(); ++ } ++ + getAnswer() { + let text; + + if (this._preemptiveAnswer) { + text = this._preemptiveAnswer; + this._preemptiveAnswer = null; + } else { + text = this._entry.get_text(); + } + + return text; + } + + _fadeOutMessage() { + if (this._message.opacity == 0) + return; + this._message.remove_all_transitions(); + this._message.ease({ + opacity: 0, + duration: MESSAGE_FADE_OUT_ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } + + setMessage(serviceName, message, type) { + if (type == GdmUtil.MessageType.ERROR) + this._message.add_style_class_name('login-dialog-message-warning'); + else + this._message.remove_style_class_name('login-dialog-message-warning'); + + if (type == GdmUtil.MessageType.HINT) + this._message.add_style_class_name('login-dialog-message-hint'); + else + this._message.remove_style_class_name('login-dialog-message-hint'); + ++ this._message.show(); + if (message) { + this._message.remove_all_transitions(); + this._message.text = message; + this._message.opacity = 255; + } else { + this._message.opacity = 0; + } + + if (type === GdmUtil.MessageType.ERROR && + this._userVerifier.serviceIsFingerprint(serviceName)) { + // TODO: Use Await for wiggle to be over before unfreezing the user verifier queue + const wiggleParameters = { + duration: 65, + wiggleCount: 3, + }; + this._userVerifier.increaseCurrentMessageTimeout( + wiggleParameters.duration * (wiggleParameters.wiggleCount + 2)); + Util.wiggle(this._message, wiggleParameters); + } + } + + updateSensitivity(sensitive) { + if (this._entry.reactive === sensitive) + return; + + this._entry.reactive = sensitive; + + if (sensitive) { + this._entry.grab_key_focus(); + } else { +diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js +index d2a82b43d..41dd99646 100644 +--- a/js/gdm/loginDialog.js ++++ b/js/gdm/loginDialog.js +@@ -391,60 +391,65 @@ var SessionMenuButton = GObject.registerClass({ + let item = new PopupMenu.PopupMenuItem(sessionName); + this._menu.addMenuItem(item); + this._items[id] = item; + + item.connect('activate', () => { + this.setActiveSession(id); + this.emit('session-activated', this._activeSessionId); + }); + } + } + }); + + var LoginDialog = GObject.registerClass({ + Signals: { + 'failed': {}, + 'wake-up-screen': {}, + }, + }, class LoginDialog extends St.Widget { + _init(parentActor) { + super._init({ style_class: 'login-dialog', visible: false }); + + this.get_accessible().set_role(Atk.Role.WINDOW); + + this.add_constraint(new Layout.MonitorConstraint({ primary: true })); + this.connect('destroy', this._onDestroy.bind(this)); + parentActor.add_child(this); + + 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::%s'.format(GdmUtil.BANNER_MESSAGE_KEY), + this._updateBanner.bind(this)); + this._settings.connect('changed::%s'.format(GdmUtil.BANNER_MESSAGE_TEXT_KEY), + this._updateBanner.bind(this)); + this._settings.connect('changed::%s'.format(GdmUtil.DISABLE_USER_LIST_KEY), + this._updateDisableUserList.bind(this)); + this._settings.connect('changed::%s'.format(GdmUtil.LOGO_KEY), + this._updateLogo.bind(this)); + + this._textureCache = St.TextureCache.get_default(); + this._updateLogoTextureId = this._textureCache.connect('texture-file-changed', + this._updateLogoTexture.bind(this)); + + this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box', + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + vertical: true, + visible: false }); + this.add_child(this._userSelectionBox); + + this._userList = new UserList(); + this._userSelectionBox.add_child(this._userList); + + this._authPrompt = new AuthPrompt.AuthPrompt(this._gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOG_IN); + this._authPrompt.connect('prompted', this._onPrompted.bind(this)); + this._authPrompt.connect('reset', this._onReset.bind(this)); + this._authPrompt.hide(); + this.add_child(this._authPrompt); +diff --git a/js/gdm/util.js b/js/gdm/util.js +index e62114cb1..3f327400f 100644 +--- a/js/gdm/util.js ++++ b/js/gdm/util.js +@@ -211,90 +211,98 @@ var ShellUserVerifier = class { + this._cancellable = new Gio.Cancellable(); + this._hold = hold; + this._userName = userName; + this.reauthenticating = false; + + this._checkForFingerprintReader(); + + // If possible, reauthenticate an already running session, + // so any session specific credentials get updated appropriately + if (userName) + this._openReauthenticationChannel(userName); + else + this._getUserVerifier(); + } + + cancel() { + if (this._cancellable) + this._cancellable.cancel(); + + if (this._userVerifier) { + this._userVerifier.call_cancel_sync(null); + this.clear(); + } + } + + _clearUserVerifier() { + if (this._userVerifier) { + this._disconnectSignals(); + this._userVerifier.run_dispose(); + this._userVerifier = null; ++ if (this._userVerifierChoiceList) { ++ this._userVerifierChoiceList.run_dispose(); ++ this._userVerifierChoiceList = null; ++ } + } + } + + clear() { + if (this._cancellable) { + this._cancellable.cancel(); + this._cancellable = null; + } + + this._clearUserVerifier(); + this._clearMessageQueue(); + } + + destroy() { + this.cancel(); + + this._settings.run_dispose(); + this._settings = null; + + this._smartcardManager.disconnect(this._smartcardInsertedId); + this._smartcardManager.disconnect(this._smartcardRemovedId); + this._smartcardManager = null; + + for (let service in this._credentialManagers) { + let credentialManager = this._credentialManagers[service]; + credentialManager.disconnect(credentialManager._authenticatedSignalId); + credentialManager = 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); + } else { + const cancellable = this._cancellable; + let signalId = this.connect('no-more-messages', () => { + this.disconnect(signalId); + if (!cancellable.is_cancelled()) + this._userVerifier.call_answer_query(serviceName, answer, cancellable, null); + }); + } + } + + _getIntervalForMessage(message) { + if (!message) + return 0; + + // We probably could be smarter here + return message.length * USER_READ_TIME; + } + + finishMessageQueue() { + if (!this.hasPendingMessages) + return; + + this._messageQueue = []; + + this.emit('no-more-messages'); + } + +@@ -429,103 +437,116 @@ var ShellUserVerifier = class { + _reportInitError(where, error, serviceName) { + logError(error, where); + this._hold.release(); + + this._queueMessage(serviceName, _('Authentication error'), MessageType.ERROR); + this._failCounter++; + this._verificationFailed(serviceName, false); + } + + async _openReauthenticationChannel(userName) { + try { + this._clearUserVerifier(); + this._userVerifier = await this._client.open_reauthentication_channel( + userName, this._cancellable); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) + return; + if (e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) && + !this._reauthOnly) { + // Gdm emits org.freedesktop.DBus.Error.AccessDenied when there + // is no session to reauthenticate. Fall back to performing + // verification from this login session + this._getUserVerifier(); + return; + } + + this._reportInitError('Failed to open reauthentication channel', e); + return; + } + ++ if (this._client.get_user_verifier_choice_list) ++ this._userVerifierChoiceList = this._client.get_user_verifier_choice_list(); ++ else ++ this._userVerifierChoiceList = null; ++ + this.reauthenticating = true; + this._connectSignals(); + this._beginVerification(); + this._hold.release(); + } + + async _getUserVerifier() { + try { + this._clearUserVerifier(); + this._userVerifier = + await this._client.get_user_verifier(this._cancellable); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) + return; + this._reportInitError('Failed to obtain user verifier', e); + return; + } + ++ if (this._client.get_user_verifier_choice_list) ++ this._userVerifierChoiceList = this._client.get_user_verifier_choice_list(); ++ else ++ this._userVerifierChoiceList = null; ++ + this._connectSignals(); + this._beginVerification(); + this._hold.release(); + } + + _connectSignals() { + this._disconnectSignals(); + this._signalIds = []; + + let id = this._userVerifier.connect('info', this._onInfo.bind(this)); + this._signalIds.push(id); + id = this._userVerifier.connect('problem', this._onProblem.bind(this)); + this._signalIds.push(id); + id = this._userVerifier.connect('info-query', this._onInfoQuery.bind(this)); + this._signalIds.push(id); + id = this._userVerifier.connect('secret-info-query', this._onSecretInfoQuery.bind(this)); + this._signalIds.push(id); + id = this._userVerifier.connect('conversation-stopped', this._onConversationStopped.bind(this)); + this._signalIds.push(id); + id = this._userVerifier.connect('service-unavailable', this._onServiceUnavailable.bind(this)); + this._signalIds.push(id); + id = this._userVerifier.connect('reset', this._onReset.bind(this)); + this._signalIds.push(id); + id = this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this)); + this._signalIds.push(id); ++ ++ if (this._userVerifierChoiceList) ++ this._userVerifierChoiceList.connect('choice-query', this._onChoiceListQuery.bind(this)); + } + + _disconnectSignals() { + if (!this._signalIds || !this._userVerifier) + return; + + this._signalIds.forEach(s => this._userVerifier.disconnect(s)); + this._signalIds = []; + } + + _getForegroundService() { + if (this._preemptingService) + return this._preemptingService; + + return this._defaultService; + } + + serviceIsForeground(serviceName) { + return serviceName == this._getForegroundService(); + } + + serviceIsDefault(serviceName) { + return serviceName == this._defaultService; + } + + serviceIsFingerprint(serviceName) { + return this._fingerprintReaderType !== FingerprintReaderType.NONE && + serviceName === FINGERPRINT_SERVICE_NAME; + } + +@@ -554,60 +575,67 @@ var ShellUserVerifier = class { + } else { + await this._userVerifier.call_begin_verification( + serviceName, this._cancellable); + } + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) + return; + if (!this.serviceIsForeground(serviceName)) { + logError(e, 'Failed to start %s for %s'.format(serviceName, this._userName)); + this._hold.release(); + return; + } + this._reportInitError(this._userName + ? 'Failed to start %s verification for user'.format(serviceName) + : 'Failed to start %s verification'.format(serviceName), e, + serviceName); + return; + } + this._hold.release(); + } + + _beginVerification() { + this._startService(this._getForegroundService()); + + if (this._userName && + this._fingerprintReaderType !== FingerprintReaderType.NONE && + !this.serviceIsForeground(FINGERPRINT_SERVICE_NAME)) + 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(serviceName, info, MessageType.INFO); + } else if (this.serviceIsFingerprint(serviceName)) { + // We don't show fingerprint messages directly since it's + // not the main auth service. Instead we use the messages + // as a cue to display our own message. + if (this._fingerprintReaderType === FingerprintReaderType.SWIPE) { + // Translators: this message is shown below the password entry field + // to indicate the user can swipe their finger on the fingerprint reader + this._queueMessage(serviceName, _('(or swipe finger across reader)'), + MessageType.HINT); + } else { + // Translators: this message is shown below the password entry field + // to indicate the user can place their finger on the fingerprint reader instead + this._queueMessage(serviceName, _('(or place finger on reader)'), + MessageType.HINT); + } + } + } + + _onProblem(client, serviceName, problem) { + const isFingerprint = this.serviceIsFingerprint(serviceName); + + if (!this.serviceIsForeground(serviceName) && !isFingerprint) + return; + + this._queuePriorityMessage(serviceName, problem, MessageType.ERROR); + + if (isFingerprint) { +diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js +index 5b55cb08a..f4655b25b 100644 +--- a/js/ui/unlockDialog.js ++++ b/js/ui/unlockDialog.js +@@ -466,60 +466,67 @@ class UnlockDialogLayout extends Clutter.LayoutManager { + else + actorBox.x1 = box.x2 - (natWidth * 2); + + actorBox.y1 = box.y2 - (natHeight * 2); + actorBox.x2 = actorBox.x1 + natWidth; + actorBox.y2 = actorBox.y1 + natHeight; + + this._switchUserButton.allocate(actorBox); + } + } + }); + + var UnlockDialog = GObject.registerClass({ + Signals: { + 'failed': {}, + 'wake-up-screen': {}, + }, + }, class UnlockDialog extends St.Widget { + _init(parentActor) { + super._init({ + accessible_role: Atk.Role.WINDOW, + style_class: 'unlock-dialog', + visible: false, + reactive: true, + }); + + parentActor.add_child(this); + + this._gdmClient = new Gdm.Client(); + ++ try { ++ this._gdmClient.set_enabled_extensions([ ++ Gdm.UserVerifierChoiceList.interface_info().name, ++ ]); ++ } catch (e) { ++ } ++ + this._adjustment = new St.Adjustment({ + actor: this, + lower: 0, + upper: 2, + page_size: 1, + page_increment: 1, + }); + this._adjustment.connect('notify::value', () => { + this._setTransitionProgress(this._adjustment.value); + }); + + this._swipeTracker = new SwipeTracker.SwipeTracker(this, + Clutter.Orientation.VERTICAL, + Shell.ActionMode.UNLOCK_SCREEN); + this._swipeTracker.connect('begin', this._swipeBegin.bind(this)); + this._swipeTracker.connect('update', this._swipeUpdate.bind(this)); + this._swipeTracker.connect('end', this._swipeEnd.bind(this)); + + this.connect('scroll-event', (o, event) => { + if (this._swipeTracker.canHandleScrollEvent(event)) + return Clutter.EVENT_PROPAGATE; + + let direction = event.get_scroll_direction(); + if (direction === Clutter.ScrollDirection.UP) + this._showClock(); + else if (direction === Clutter.ScrollDirection.DOWN) + this._showPrompt(); + return Clutter.EVENT_STOP; + }); + +-- +2.34.1 + diff --git a/wake-up-on-deactivate.patch b/wake-up-on-deactivate.patch deleted file mode 100644 index b20cbbdfc6f0b3867f142e8377ca69edc9cf689a..0000000000000000000000000000000000000000 --- a/wake-up-on-deactivate.patch +++ /dev/null @@ -1,79 +0,0 @@ -From d6ead50fe230df58ddab822966d69760b00ec920 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 1 Apr 2020 14:48:10 +0200 -Subject: [PATCH 1/2] screenShield: Switch lightboxes off before unlock - transition - -There is no point in animating a transition with fullscreen black -rectangles stacked on top, so switch them off before rather than -after the transition. - -https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1158 ---- - js/ui/screenShield.js | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index cd38f11fc8..282f29fa30 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -1221,6 +1221,9 @@ var ScreenShield = class { - this._isModal = false; - } - -+ this._longLightbox.hide(); -+ this._shortLightbox.hide(); -+ - Tweener.addTween(this._lockDialogGroup, { - scale_x: 0, - scale_y: 0, -@@ -1237,8 +1240,6 @@ var ScreenShield = class { - this._dialog = null; - } - -- this._longLightbox.hide(); -- this._shortLightbox.hide(); - this.actor.hide(); - - if (this._becameActiveId != 0) { --- -2.28.0 - - -From 39ac7cad68d8c00d98c900b35add637b01eddbbf Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Tue, 31 Mar 2020 21:07:59 +0200 -Subject: [PATCH 2/2] screenShield: Wake up on deactivate() - -Usually the screen is woken up before the shield is deactivated, but -it is also possible to unlock the session programmatically via the -org.gnome.ScreenSaver D-Bus API. - -The intention is very likely not to unlock a turned off screen in -that case. Nor does it seem like a good idea to change the lock -state without any indication. - -Waking up the screen is more likely to meet expectations and is -more reasonable too, so do that. - -https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1158 ---- - js/ui/screenShield.js | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index 282f29fa30..2d0a429bee 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -1200,6 +1200,8 @@ var ScreenShield = class { - if (Main.sessionMode.currentMode == 'unlock-dialog') - Main.sessionMode.popMode('unlock-dialog'); - -+ this.emit('wake-up-screen'); -+ - if (this._isGreeter) { - // We don't want to "deactivate" any more than - // this. In particular, we don't want to drop --- -2.28.0 - diff --git a/warn-less.patch b/warn-less.patch deleted file mode 100644 index f5dd83716c81da4ccfc5a479ac2448871e0d1c22..0000000000000000000000000000000000000000 --- a/warn-less.patch +++ /dev/null @@ -1,279 +0,0 @@ -From 37bbb9175bbd061d4ae14e86c35e4211602dbeaa Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 23 Mar 2020 17:57:38 +0100 -Subject: [PATCH 1/4] shell/util: Add touch_file_async() helper - -Add a small helper method to asynchronously "touch" a file and return -whether the file was created or not. - -As g_file_make_directory_with_parents() doesn't have an async variant, -we need a C helper to make the entire operation non-blocking. - -https://gitlab.gnome.org/GNOME/gnome-shell/issues/2432 ---- - src/shell-util.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/shell-util.h | 7 ++++++ - 2 files changed, 69 insertions(+) - -diff --git a/src/shell-util.c b/src/shell-util.c -index fa3fc08c8..eec67f3d7 100644 ---- a/src/shell-util.c -+++ b/src/shell-util.c -@@ -323,6 +323,68 @@ shell_get_file_contents_utf8_sync (const char *path, - return contents; - } - -+static void -+touch_file (GTask *task, -+ gpointer object, -+ gpointer task_data, -+ GCancellable *cancellable) -+{ -+ GFile *file = object; -+ g_autoptr (GFile) parent = NULL; -+ g_autoptr (GFileOutputStream) stream = NULL; -+ GError *error = NULL; -+ -+ parent = g_file_get_parent (file); -+ g_file_make_directory_with_parents (parent, cancellable, &error); -+ -+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) -+ { -+ g_task_return_error (task, error); -+ return; -+ } -+ g_clear_error (&error); -+ -+ stream = g_file_create (file, G_FILE_CREATE_NONE, cancellable, &error); -+ -+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) -+ { -+ g_task_return_error (task, error); -+ return; -+ } -+ g_clear_error (&error); -+ -+ if (stream) -+ g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL); -+ -+ g_task_return_boolean (task, stream != NULL); -+} -+ -+void -+shell_util_touch_file_async (GFile *file, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ g_autoptr (GTask) task = NULL; -+ -+ g_return_if_fail (G_IS_FILE (file)); -+ -+ task = g_task_new (file, NULL, callback, user_data); -+ g_task_set_source_tag (task, shell_util_touch_file_async); -+ -+ g_task_run_in_thread (task, touch_file); -+} -+ -+gboolean -+shell_util_touch_file_finish (GFile *file, -+ GAsyncResult *res, -+ GError **error) -+{ -+ g_return_val_if_fail (G_IS_FILE (file), FALSE); -+ g_return_val_if_fail (G_IS_TASK (res), FALSE); -+ -+ return g_task_propagate_boolean (G_TASK (res), error); -+} -+ - /** - * shell_util_wifexited: - * @status: the status returned by wait() or waitpid() -diff --git a/src/shell-util.h b/src/shell-util.h -index 02b8404e9..bedf516ba 100644 ---- a/src/shell-util.h -+++ b/src/shell-util.h -@@ -32,6 +32,13 @@ gboolean shell_write_string_to_stream (GOutputStream *stream, - char *shell_get_file_contents_utf8_sync (const char *path, - GError **error); - -+void shell_util_touch_file_async (GFile *file, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+gboolean shell_util_touch_file_finish (GFile *file, -+ GAsyncResult *res, -+ GError **error); -+ - gboolean shell_util_wifexited (int status, - int *exit); - --- -2.31.1 - - -From 1f75494bea1ef7017d50d77cf5c7ad6b9668d4f5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 23 Mar 2020 18:00:27 +0100 -Subject: [PATCH 2/4] environment: Hook up touch_file to GFile prototype - -We don't usually extend introspected types with our own API, but in -this case it's too tempting to make the helper functions usable with -Gio._promisify() ... - -https://gitlab.gnome.org/GNOME/gnome-shell/issues/2432 ---- - js/ui/environment.js | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/js/ui/environment.js b/js/ui/environment.js -index e22ec7402..9c125d3eb 100644 ---- a/js/ui/environment.js -+++ b/js/ui/environment.js -@@ -9,7 +9,7 @@ imports.gi.versions.Gtk = '3.0'; - imports.gi.versions.TelepathyGLib = '0.12'; - imports.gi.versions.TelepathyLogger = '0.2'; - --const { Clutter, GLib, Shell, St } = imports.gi; -+const { Clutter, Gio, GLib, Shell, St } = imports.gi; - const Gettext = imports.gettext; - - // We can't import shell JS modules yet, because they may have -@@ -97,6 +97,13 @@ function init() { - return St.describe_actor(this); - }; - -+ Gio._LocalFilePrototype.touch_async = function (callback) { -+ Shell.util_touch_file_async(this, callback); -+ }; -+ Gio._LocalFilePrototype.touch_finish = function (result) { -+ return Shell.util_touch_file_finish(this, result); -+ }; -+ - let origToString = Object.prototype.toString; - Object.prototype.toString = function() { - let base = origToString.call(this); --- -2.31.1 - - -From 4bef23c7176a43f4dcf146e70bbb8aaa701b8cd2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 20 Mar 2020 12:42:04 +0100 -Subject: [PATCH 3/4] main: Do not warn about missing GDM on each login - -We now warn on startup if screen locking isn't available, however for -users who choose not to use GDM or logind, repeating the warning on -each login is more annoying than helpful. - -Instead, limit the warning to the first login on which the screen lock -became unavailable. That way the notification will still serve the -intended purpose of informing the user, but without being perceived -as nagging. - -https://gitlab.gnome.org/GNOME/gnome-shell/issues/2432 ---- - js/ui/main.js | 36 +++++++++++++++++++++++++++++++----- - 1 file changed, 31 insertions(+), 5 deletions(-) - -diff --git a/js/ui/main.js b/js/ui/main.js -index 1203b3c39..a3fad158c 100644 ---- a/js/ui/main.js -+++ b/js/ui/main.js -@@ -81,6 +81,9 @@ let _a11ySettings = null; - let _themeResource = null; - let _oskResource = null; - -+Gio._promisify(Gio._LocalFilePrototype, 'delete_async', 'delete_finish'); -+Gio._promisify(Gio._LocalFilePrototype, 'touch_async', 'touch_finish'); -+ - function _sessionUpdated() { - if (sessionMode.isPrimary) - _loadDefaultStylesheet(); -@@ -242,11 +245,8 @@ function _initializeUI() { - } - - if (sessionMode.currentMode !== 'gdm' && -- sessionMode.currentMode !== 'initial-setup' && -- screenShield === null) { -- notify(_('Screen Lock disabled'), -- _('Screen Locking requires the GNOME display manager.')); -- } -+ sessionMode.currentMode !== 'initial-setup') -+ _handleLockScreenWarning(); - - let perfModuleName = GLib.getenv("SHELL_PERF_MODULE"); - if (perfModuleName) { -@@ -257,6 +257,32 @@ function _initializeUI() { - }); - } - -+async function _handleLockScreenWarning() { -+ const path = '%s/lock-warning-shown'.format(global.userdatadir); -+ const file = Gio.File.new_for_path(path); -+ -+ const hasLockScreen = screenShield !== null; -+ if (hasLockScreen) { -+ try { -+ await file.delete_async(0, null); -+ } catch (e) { -+ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) -+ logError(e); -+ } -+ } else { -+ try { -+ if (!await file.touch_async()) -+ return; -+ } catch (e) { -+ logError(e); -+ } -+ -+ notify( -+ _('Screen Lock disabled'), -+ _('Screen Locking requires the GNOME display manager.')); -+ } -+} -+ - function _getStylesheet(name) { - let stylesheet; - --- -2.31.1 - - -From c3f34e786826d0ed1af4150190159fed50d9fb87 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Thu, 22 Oct 2020 20:11:14 +0200 -Subject: [PATCH 4/4] messageTray: Default to generic policy - -How and if notifications are shown is controlled by NotificationPolicy -objects. But ever since 098bd45, only notification daemon sources or -notifications associated with an app are hooked up to GSettings. - -The hardcoded default policy for built-in notifications (including -those provided by extensions) arguably made sense back then, but -now that the main setting has been rebranded as "Do Not Disturb" -and is exposed prominently in the calendar drop-down, following -GSettings is a better default. - -https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3291 - -Part-of: ---- - js/ui/messageTray.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js -index 8f8130451..f6bdae8e4 100644 ---- a/js/ui/messageTray.js -+++ b/js/ui/messageTray.js -@@ -731,7 +731,7 @@ var Source = class Source { - } - - _createPolicy() { -- return new NotificationPolicy(); -+ return new NotificationGenericPolicy(); - } - - get narrowestPrivacyScope() { --- -2.31.1 -