[mutter/gnome-3-28] window-x11: Focus the default window with delay while waiting for take-focus
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/gnome-3-28] window-x11: Focus the default window with delay while waiting for take-focus
- Date: Mon, 24 Jun 2019 15:13:27 +0000 (UTC)
commit b462e519e82be6c7cbba9ac9434ce3ad9d6bb519
Author: Marco Trevisan (Treviño) <mail 3v1n0 net>
Date: Wed Nov 14 00:08:34 2018 +0100
window-x11: Focus the default window with delay while waiting for take-focus
When requesting to a take-focus window to acquire the input, the client may or
may not respond with a SetInputFocus (this doesn't happen for no-input gtk
windows in fact [to be fixed there too]), in such case we were unsetting the
focus while waiting the reply.
In case the client won't respond, we wait for a small delay (set to 250 ms) for
the take-focus window to grab the input focus before setting it to the default
window.
Added a test for this behavior and for the case in which a window takes the
focus meanwhile we're waiting to focus the default window.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/307
(cherry picked from commit f71151a5dd990d935f3fbb39451f9b41f640b625)
src/Makefile-tests.am | 1 +
...parent-delayed-focus-default-cancelled.metatest | 36 ++++++++
.../closed-transient-no-input-parent.metatest | 16 +++-
src/x11/window-x11.c | 101 ++++++++++++++++++++-
4 files changed, 146 insertions(+), 8 deletions(-)
---
diff --git a/src/Makefile-tests.am b/src/Makefile-tests.am
index 376491799..eca6a7b90 100644
--- a/src/Makefile-tests.am
+++ b/src/Makefile-tests.am
@@ -18,6 +18,7 @@ dist_stacking_DATA = \
tests/stacking/closed-transient-no-input-no-take-focus-parent.metatest \
tests/stacking/closed-transient-no-input-no-take-focus-parents.metatest \
tests/stacking/closed-transient-no-input-parent.metatest \
+ tests/stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest \
tests/stacking/minimized.metatest \
tests/stacking/mixed-windows.metatest \
tests/stacking/set-parent.metatest \
diff --git a/src/tests/stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest
b/src/tests/stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest
new file mode 100644
index 000000000..38897e388
--- /dev/null
+++ b/src/tests/stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest
@@ -0,0 +1,36 @@
+new_client 2 x11
+create 2/1
+show 2/1
+
+new_client 1 x11
+create 1/1
+show 1/1
+
+create 1/2 csd
+set_parent 1/2 1
+accept_focus 1/2 false
+show 1/2
+
+create 1/3 csd
+set_parent 1/3 2
+show 1/3
+
+wait
+assert_focused 1/3
+assert_stacking 2/1 1/1 1/2 1/3
+
+destroy 1/3
+sleep 10
+
+assert_focused none
+assert_stacking 2/1 1/1 1/2
+
+activate 2/1
+wait
+
+assert_focused 2/1
+assert_stacking 1/1 1/2 2/1
+
+sleep 250
+assert_focused 2/1
+assert_stacking 1/1 1/2 2/1
diff --git a/src/tests/stacking/closed-transient-no-input-parent.metatest
b/src/tests/stacking/closed-transient-no-input-parent.metatest
index 4cadb2350..e0f1dc1e2 100644
--- a/src/tests/stacking/closed-transient-no-input-parent.metatest
+++ b/src/tests/stacking/closed-transient-no-input-parent.metatest
@@ -1,3 +1,7 @@
+new_client 2 x11
+create 2/1
+show 2/1
+
new_client 1 x11
create 1/1
show 1/1
@@ -12,9 +16,15 @@ set_parent 1/3 2
show 1/3
wait
-assert_stacking 1/1 1/2 1/3
+assert_focused 1/3
+assert_stacking 2/1 1/1 1/2 1/3
destroy 1/3
+dispatch
-wait
-assert_stacking 1/1 1/2
+assert_focused none
+assert_stacking 2/1 1/1 1/2
+
+sleep 250
+assert_focused 1/1
+assert_stacking 2/1 1/1 1/2
diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
index e1c34412d..29ea3a6be 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -53,6 +53,8 @@
#include "backends/meta-logical-monitor.h"
#include "backends/x11/meta-backend-x11.h"
+#define TAKE_FOCUS_FALLBACK_DELAY_MS 250
+
G_DEFINE_TYPE_WITH_PRIVATE (MetaWindowX11, meta_window_x11, META_TYPE_WINDOW)
static void
@@ -722,6 +724,66 @@ request_take_focus (MetaWindow *window,
send_icccm_message (window, display->atom_WM_TAKE_FOCUS, timestamp);
}
+typedef struct
+{
+ MetaWindow *window;
+ guint32 timestamp;
+ guint timeout_id;
+ gulong unmanaged_id;
+ gulong focused_changed_id;
+} MetaWindowX11DelayedFocusData;
+
+static void
+meta_window_x11_delayed_focus_data_free (MetaWindowX11DelayedFocusData *data)
+{
+ g_signal_handler_disconnect (data->window, data->unmanaged_id);
+ g_signal_handler_disconnect (data->window->display, data->focused_changed_id);
+
+ if (data->timeout_id)
+ g_source_remove (data->timeout_id);
+
+ g_free (data);
+}
+
+static gboolean
+focus_window_delayed_timeout (gpointer user_data)
+{
+ MetaWindowX11DelayedFocusData *data = user_data;
+ MetaWindow *window = data->window;
+ guint32 timestamp = data->timestamp;
+
+ data->timeout_id = 0;
+ meta_window_x11_delayed_focus_data_free (data);
+
+ meta_window_focus (window, timestamp);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+meta_window_x11_maybe_focus_delayed (MetaWindow *window,
+ guint32 timestamp)
+{
+ MetaWindowX11DelayedFocusData *data;
+
+ data = g_new0 (MetaWindowX11DelayedFocusData, 1);
+ data->window = window;
+ data->timestamp = timestamp;
+
+ data->unmanaged_id =
+ g_signal_connect_swapped (window, "unmanaged",
+ G_CALLBACK (meta_window_x11_delayed_focus_data_free),
+ data);
+
+ data->focused_changed_id =
+ g_signal_connect_swapped (window->display, "notify::focus-window",
+ G_CALLBACK (meta_window_x11_delayed_focus_data_free),
+ data);
+
+ data->timeout_id = g_timeout_add (TAKE_FOCUS_FALLBACK_DELAY_MS,
+ focus_window_delayed_timeout, data);
+}
+
static void
meta_window_x11_focus (MetaWindow *window,
guint32 timestamp)
@@ -771,14 +833,43 @@ meta_window_x11_focus (MetaWindow *window,
* Normally, we want to just leave the focus undisturbed until
* the window responds to WM_TAKE_FOCUS, but if we're unmanaging
* the current focus window we *need* to move the focus away, so
- * we focus the no_focus_window now (and set
- * display->focus_window to that) before sending WM_TAKE_FOCUS.
+ * we focus the no focus window before sending WM_TAKE_FOCUS,
+ * and eventually the default focus windwo excluding this one,
+ * if meanwhile we don't get any focus request.
*/
if (window->display->focus_window != NULL &&
window->display->focus_window->unmanaging)
- meta_display_focus_the_no_focus_window (window->display,
- window->screen,
- timestamp);
+ {
+ MetaWindow *focus_window = window;
+ MetaWorkspace *workspace = window->workspace;
+ MetaStack *stack = window->screen->stack;
+
+ while (TRUE)
+ {
+ focus_window = meta_stack_get_default_focus_window (stack,
+ workspace,
+ focus_window);
+ if (!focus_window)
+ break;
+
+ if (focus_window->unmanaging)
+ continue;
+
+ if (focus_window->input)
+ break;
+
+ if (focus_window->shaded && focus_window->frame)
+ break;
+ }
+
+ meta_display_focus_the_no_focus_window (window->display,
+ window->screen,
+ timestamp);
+
+ if (focus_window)
+ meta_window_x11_maybe_focus_delayed (focus_window,
+ timestamp);
+ }
}
request_take_focus (window, timestamp);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]