mirror of
https://github.com/brl/mutter.git
synced 2024-11-23 16:40:41 -05:00
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
This commit is contained in:
parent
6022b23923
commit
f71151a5dd
@ -114,6 +114,7 @@ stacking_tests = [
|
|||||||
'closed-transient-no-input-no-take-focus-parent',
|
'closed-transient-no-input-no-take-focus-parent',
|
||||||
'closed-transient-no-input-no-take-focus-parents',
|
'closed-transient-no-input-no-take-focus-parents',
|
||||||
'closed-transient-no-input-parent',
|
'closed-transient-no-input-parent',
|
||||||
|
'closed-transient-no-input-parent-delayed-focus-default-cancelled',
|
||||||
'minimized',
|
'minimized',
|
||||||
'mixed-windows',
|
'mixed-windows',
|
||||||
'set-parent',
|
'set-parent',
|
||||||
|
@ -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
|
@ -1,3 +1,7 @@
|
|||||||
|
new_client 2 x11
|
||||||
|
create 2/1
|
||||||
|
show 2/1
|
||||||
|
|
||||||
new_client 1 x11
|
new_client 1 x11
|
||||||
create 1/1
|
create 1/1
|
||||||
show 1/1
|
show 1/1
|
||||||
@ -12,9 +16,15 @@ set_parent 1/3 2
|
|||||||
show 1/3
|
show 1/3
|
||||||
|
|
||||||
wait
|
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
|
destroy 1/3
|
||||||
|
dispatch
|
||||||
|
|
||||||
wait
|
assert_focused none
|
||||||
assert_stacking 1/1 1/2
|
assert_stacking 2/1 1/1 1/2
|
||||||
|
|
||||||
|
sleep 250
|
||||||
|
assert_focused 1/1
|
||||||
|
assert_stacking 2/1 1/1 1/2
|
||||||
|
@ -50,6 +50,8 @@
|
|||||||
#include "x11/window-props.h"
|
#include "x11/window-props.h"
|
||||||
#include "x11/xprops.h"
|
#include "x11/xprops.h"
|
||||||
|
|
||||||
|
#define TAKE_FOCUS_FALLBACK_DELAY_MS 250
|
||||||
|
|
||||||
enum _MetaGtkEdgeConstraints
|
enum _MetaGtkEdgeConstraints
|
||||||
{
|
{
|
||||||
META_GTK_EDGE_CONSTRAINT_TOP_TILED = 1 << 0,
|
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);
|
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
|
static void
|
||||||
meta_window_x11_focus (MetaWindow *window,
|
meta_window_x11_focus (MetaWindow *window,
|
||||||
guint32 timestamp)
|
guint32 timestamp)
|
||||||
@ -827,12 +887,41 @@ meta_window_x11_focus (MetaWindow *window,
|
|||||||
* Normally, we want to just leave the focus undisturbed until
|
* Normally, we want to just leave the focus undisturbed until
|
||||||
* the window responds to WM_TAKE_FOCUS, but if we're unmanaging
|
* the window responds to WM_TAKE_FOCUS, but if we're unmanaging
|
||||||
* the current focus window we *need* to move the focus away, so
|
* the current focus window we *need* to move the focus away, so
|
||||||
* we focus the no_focus_window now (and set
|
* we focus the no focus window before sending WM_TAKE_FOCUS,
|
||||||
* display->focus_window to that) 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 &&
|
if (window->display->focus_window != NULL &&
|
||||||
window->display->focus_window->unmanaging)
|
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);
|
request_take_focus (window, timestamp);
|
||||||
|
Loading…
Reference in New Issue
Block a user