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