[mutter] window-x11: Focus the default window with delay while waiting for take-focus
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] window-x11: Focus the default window with delay while waiting for take-focus
- Date: Mon, 24 Jun 2019 09:51:02 +0000 (UTC)
commit f71151a5dd990d935f3fbb39451f9b41f640b625
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
src/tests/meson.build | 1 +
...parent-delayed-focus-default-cancelled.metatest | 36 ++++++++
.../closed-transient-no-input-parent.metatest | 16 +++-
src/x11/window-x11.c | 95 +++++++++++++++++++++-
4 files changed, 142 insertions(+), 6 deletions(-)
---
diff --git a/src/tests/meson.build b/src/tests/meson.build
index 3d0a3f7a3..26bf3a8c1 100644
--- a/src/tests/meson.build
+++ b/src/tests/meson.build
@@ -114,6 +114,7 @@ stacking_tests = [
'closed-transient-no-input-no-take-focus-parent',
'closed-transient-no-input-no-take-focus-parents',
'closed-transient-no-input-parent',
+ 'closed-transient-no-input-parent-delayed-focus-default-cancelled',
'minimized',
'mixed-windows',
'set-parent',
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 1f492984e..b1d115160 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -50,6 +50,8 @@
#include "x11/window-props.h"
#include "x11/xprops.h"
+#define TAKE_FOCUS_FALLBACK_DELAY_MS 250
+
enum _MetaGtkEdgeConstraints
{
META_GTK_EDGE_CONSTRAINT_TOP_TILED = 1 << 0,
@@ -776,6 +778,64 @@ request_take_focus (MetaWindow *window,
send_icccm_message (window, display->x11_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);
+
+ g_clear_handle_id (&data->timeout_id, g_source_remove);
+ 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)
@@ -827,12 +887,41 @@ 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_unset_input_focus (window->display, timestamp);
+ {
+ MetaWindow *focus_window = window;
+ MetaWorkspace *workspace = window->workspace;
+ MetaStack *stack = workspace->display->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_unset_input_focus (window->display, 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]