a528c3
From df0adb82dba725fa2734a8697ae33727201b2ee1 Mon Sep 17 00:00:00 2001
a528c3
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
a528c3
Date: Mon, 21 May 2018 21:21:05 +0200
a528c3
Subject: [PATCH 1/3] closeDialog: Disable unredirection while showing
a528c3
a528c3
The dialog won't be visible when unredirection is in place (for example
a528c3
while a fullscreen window is focused), so disable unredirection while
a528c3
the dialog is up.
a528c3
a528c3
https://gitlab.gnome.org/GNOME/gnome-shell/issues/298
a528c3
---
a528c3
 js/ui/closeDialog.js | 4 ++++
a528c3
 1 file changed, 4 insertions(+)
a528c3
a528c3
diff --git a/js/ui/closeDialog.js b/js/ui/closeDialog.js
a528c3
index aa0b5ceaf..821480a9c 100644
a528c3
--- a/js/ui/closeDialog.js
a528c3
+++ b/js/ui/closeDialog.js
a528c3
@@ -97,6 +97,8 @@ var CloseDialog = new Lang.Class({
a528c3
         if (this._dialog != null)
a528c3
             return;
a528c3
 
a528c3
+        Meta.disable_unredirect_for_screen(global.screen);
a528c3
+
a528c3
         this._addWindowEffect();
a528c3
         this._initDialog();
a528c3
 
a528c3
@@ -117,6 +119,8 @@ var CloseDialog = new Lang.Class({
a528c3
         if (this._dialog == null)
a528c3
             return;
a528c3
 
a528c3
+        Meta.enable_unredirect_for_screen(global.screen);
a528c3
+
a528c3
         let dialog = this._dialog;
a528c3
         this._dialog = null;
a528c3
         this._removeWindowEffect();
a528c3
-- 
a528c3
2.21.0
a528c3
a528c3
a528c3
From eca06cb4dfdd8ca90e4add3e45420ab1d6cfb84a Mon Sep 17 00:00:00 2001
a528c3
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
a528c3
Date: Mon, 21 May 2018 23:12:35 +0200
a528c3
Subject: [PATCH 2/3] closeDialog: Periodically check for window to become
a528c3
 responsive again
a528c3
a528c3
The close dialog for non-responding windows is closed automatically
a528c3
when we detect that the window is responding again. However as we
a528c3
currently only ping the window in response to certain user actions
a528c3
(like focusing the window or opening the window menu), this can
a528c3
easily go undetected.
a528c3
a528c3
Address this by periodically pinging the window while the close
a528c3
dialog is shown.
a528c3
a528c3
https://gitlab.gnome.org/GNOME/gnome-shell/issues/298
a528c3
---
a528c3
 js/ui/closeDialog.js | 12 ++++++++++++
a528c3
 1 file changed, 12 insertions(+)
a528c3
a528c3
diff --git a/js/ui/closeDialog.js b/js/ui/closeDialog.js
a528c3
index 821480a9c..7943880d8 100644
a528c3
--- a/js/ui/closeDialog.js
a528c3
+++ b/js/ui/closeDialog.js
a528c3
@@ -2,6 +2,7 @@
a528c3
 
a528c3
 const Clutter = imports.gi.Clutter;
a528c3
 const Gio = imports.gi.Gio;
a528c3
+const GLib = imports.gi.GLib;
a528c3
 const GObject = imports.gi.GObject;
a528c3
 const Lang = imports.lang;
a528c3
 const Meta = imports.gi.Meta;
a528c3
@@ -13,6 +14,7 @@ const Tweener = imports.ui.tweener;
a528c3
 
a528c3
 var FROZEN_WINDOW_BRIGHTNESS = -0.3
a528c3
 var DIALOG_TRANSITION_TIME = 0.15
a528c3
+var ALIVE_TIMEOUT = 5000;
a528c3
 
a528c3
 var CloseDialog = new Lang.Class({
a528c3
     Name: 'CloseDialog',
a528c3
@@ -26,6 +28,7 @@ var CloseDialog = new Lang.Class({
a528c3
         this.parent();
a528c3
         this._window = window;
a528c3
         this._dialog = null;
a528c3
+        this._timeoutId = 0;
a528c3
     },
a528c3
 
a528c3
     get window() {
a528c3
@@ -99,6 +102,12 @@ var CloseDialog = new Lang.Class({
a528c3
 
a528c3
         Meta.disable_unredirect_for_screen(global.screen);
a528c3
 
a528c3
+        this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, ALIVE_TIMEOUT,
a528c3
+            () => {
a528c3
+                this._window.check_alive(global.display.get_current_time_roundtrip());
a528c3
+                return GLib.SOURCE_CONTINUE;
a528c3
+            });
a528c3
+
a528c3
         this._addWindowEffect();
a528c3
         this._initDialog();
a528c3
 
a528c3
@@ -121,6 +130,9 @@ var CloseDialog = new Lang.Class({
a528c3
 
a528c3
         Meta.enable_unredirect_for_screen(global.screen);
a528c3
 
a528c3
+        GLib.source_remove(this._timeoutId);
a528c3
+        this._timeoutId = 0;
a528c3
+
a528c3
         let dialog = this._dialog;
a528c3
         this._dialog = null;
a528c3
         this._removeWindowEffect();
a528c3
-- 
a528c3
2.21.0
a528c3
a528c3
a528c3
From a33a32cd63f881411fd62aae1d56ceba3b971ff2 Mon Sep 17 00:00:00 2001
a528c3
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
a528c3
Date: Tue, 4 Sep 2018 13:53:24 +0200
a528c3
Subject: [PATCH 3/3] closeDialog: Untrack chrome when window loses focus
a528c3
a528c3
On X11, reactive chrome must be added to the input region in order
a528c3
to work as expected. However that region works independently from
a528c3
any window stacking, with the result that the unresponsive-app dialog
a528c3
currently blocks all input in the "covered" area, even in windows
a528c3
stacked above the unresponsive window.
a528c3
a528c3
The correct fix would be to track the unobscured parts of the dialog
a528c3
and set the input region from that, but that's quite cumbersome. So
a528c3
instead, only track chrome when the corresponding window is focused
a528c3
(or the dialog itself of course).
a528c3
a528c3
https://gitlab.gnome.org/GNOME/gnome-shell/issues/273
a528c3
---
a528c3
 js/ui/closeDialog.js | 52 +++++++++++++++++++++++++++++++++++++++++---
a528c3
 1 file changed, 49 insertions(+), 3 deletions(-)
a528c3
a528c3
diff --git a/js/ui/closeDialog.js b/js/ui/closeDialog.js
a528c3
index 7943880d8..c4b033230 100644
a528c3
--- a/js/ui/closeDialog.js
a528c3
+++ b/js/ui/closeDialog.js
a528c3
@@ -28,7 +28,10 @@ var CloseDialog = new Lang.Class({
a528c3
         this.parent();
a528c3
         this._window = window;
a528c3
         this._dialog = null;
a528c3
+        this._tracked = undefined;
a528c3
         this._timeoutId = 0;
a528c3
+        this._windowFocusChangedId = 0;
a528c3
+        this._keyFocusChangedId = 0;
a528c3
     },
a528c3
 
a528c3
     get window() {
a528c3
@@ -96,6 +99,37 @@ var CloseDialog = new Lang.Class({
a528c3
         this.response(Meta.CloseDialogResponse.FORCE_CLOSE);
a528c3
     },
a528c3
 
a528c3
+    _onFocusChanged() {
a528c3
+        if (Meta.is_wayland_compositor())
a528c3
+            return;
a528c3
+
a528c3
+        let focusWindow = global.display.focus_window;
a528c3
+        let keyFocus = global.stage.key_focus;
a528c3
+
a528c3
+        let shouldTrack;
a528c3
+        if (focusWindow != null)
a528c3
+            shouldTrack = focusWindow == this._window;
a528c3
+        else
a528c3
+            shouldTrack = keyFocus && this._dialog.contains(keyFocus);
a528c3
+
a528c3
+        if (this._tracked === shouldTrack)
a528c3
+            return;
a528c3
+
a528c3
+        if (shouldTrack)
a528c3
+            Main.layoutManager.trackChrome(this._dialog,
a528c3
+                                           { affectsInputRegion: true });
a528c3
+        else
a528c3
+            Main.layoutManager.untrackChrome(this._dialog);
a528c3
+
a528c3
+        // The buttons are broken when they aren't added to the input region,
a528c3
+        // so disable them properly in that case
a528c3
+        this._dialog.buttonLayout.get_children().forEach(b => {
a528c3
+            b.reactive = shouldTrack;
a528c3
+        });
a528c3
+
a528c3
+        this._tracked = shouldTrack;
a528c3
+    },
a528c3
+
a528c3
     vfunc_show() {
a528c3
         if (this._dialog != null)
a528c3
             return;
a528c3
@@ -108,6 +142,14 @@ var CloseDialog = new Lang.Class({
a528c3
                 return GLib.SOURCE_CONTINUE;
a528c3
             });
a528c3
 
a528c3
+        this._windowFocusChangedId =
a528c3
+            global.display.connect('notify::focus-window',
a528c3
+                                   this._onFocusChanged.bind(this));
a528c3
+
a528c3
+        this._keyFocusChangedId =
a528c3
+            global.stage.connect('notify::key-focus',
a528c3
+                                 this._onFocusChanged.bind(this));
a528c3
+
a528c3
         this._addWindowEffect();
a528c3
         this._initDialog();
a528c3
 
a528c3
@@ -118,9 +160,7 @@ var CloseDialog = new Lang.Class({
a528c3
                          { scale_y: 1,
a528c3
                            transition: 'linear',
a528c3
                            time: DIALOG_TRANSITION_TIME,
a528c3
-                           onComplete: () => {
a528c3
-                               Main.layoutManager.trackChrome(this._dialog, { affectsInputRegion: true });
a528c3
-                           }
a528c3
+                           onComplete: this._onFocusChanged.bind(this)
a528c3
                          });
a528c3
     },
a528c3
 
a528c3
@@ -133,6 +173,12 @@ var CloseDialog = new Lang.Class({
a528c3
         GLib.source_remove(this._timeoutId);
a528c3
         this._timeoutId = 0;
a528c3
 
a528c3
+        global.display.disconnect(this._windowFocusChangedId)
a528c3
+        this._windowFocusChangedId = 0;
a528c3
+
a528c3
+        global.stage.disconnect(this._keyFocusChangedId);
a528c3
+        this._keyFocusChangedId = 0;
a528c3
+
a528c3
         let dialog = this._dialog;
a528c3
         this._dialog = null;
a528c3
         this._removeWindowEffect();
a528c3
-- 
a528c3
2.21.0
a528c3