diff --git a/include/atoms.xmacro b/include/atoms.xmacro index f856559c..8798528a 100644 --- a/include/atoms.xmacro +++ b/include/atoms.xmacro @@ -30,6 +30,7 @@ xmacro(_NET_DESKTOP_NAMES) xmacro(_NET_DESKTOP_VIEWPORT) xmacro(_NET_ACTIVE_WINDOW) xmacro(_NET_CLOSE_WINDOW) +xmacro(_NET_WM_USER_TIME) xmacro(_NET_STARTUP_ID) xmacro(_NET_WORKAREA) xmacro(WM_PROTOCOLS) diff --git a/src/ewmh.c b/src/ewmh.c index b2260d64..a5c90175 100644 --- a/src/ewmh.c +++ b/src/ewmh.c @@ -263,7 +263,7 @@ void ewmh_setup_hints(void) { /* I’m not entirely sure if we need to keep _NET_WM_NAME on root. */ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3"); - /* only send the first 31 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */ + /* only send the first 32 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, /* number of atoms */ 32, supported_atoms); /* We need to map this window to be able to set the input focus to it if no other window is available to be focused. */ diff --git a/src/manage.c b/src/manage.c index 98051ec3..87d19ff8 100644 --- a/src/manage.c +++ b/src/manage.c @@ -90,7 +90,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki utf8_title_cookie, title_cookie, class_cookie, leader_cookie, transient_cookie, role_cookie, startup_id_cookie, wm_hints_cookie, - wm_normal_hints_cookie, motif_wm_hints_cookie; + wm_normal_hints_cookie, motif_wm_hints_cookie, wm_user_time_cookie; geomc = xcb_get_geometry(conn, d); @@ -161,6 +161,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki wm_hints_cookie = xcb_icccm_get_wm_hints(conn, window); wm_normal_hints_cookie = xcb_icccm_get_wm_normal_hints(conn, window); motif_wm_hints_cookie = GET_PROPERTY(A__MOTIF_WM_HINTS, 5 * sizeof(uint64_t)); + wm_user_time_cookie = GET_PROPERTY(A__NET_WM_USER_TIME, UINT32_MAX); DLOG("Managing window 0x%08x\n", window); @@ -532,6 +533,23 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki } } + if (set_focus) { + DLOG("Checking con = %p for _NET_WM_USER_TIME.\n", nc); + + uint32_t *wm_user_time; + xcb_get_property_reply_t *wm_user_time_reply = xcb_get_property_reply(conn, wm_user_time_cookie, NULL); + if (wm_user_time_reply != NULL && xcb_get_property_value_length(wm_user_time_reply) != 0 && + (wm_user_time = xcb_get_property_value(wm_user_time_reply)) && + wm_user_time[0] == 0) { + DLOG("_NET_WM_USER_TIME set to 0, not focusing con = %p.\n", nc); + set_focus = false; + } + + FREE(wm_user_time_reply); + } else { + xcb_discard_reply(conn, wm_user_time_cookie.sequence); + } + /* Defer setting focus after the 'new' event has been sent to ensure the * proper window event sequence. */ if (set_focus && !nc->window->doesnt_accept_focus && nc->mapped) { diff --git a/testcases/t/259-net-wm-user-time.t b/testcases/t/259-net-wm-user-time.t new file mode 100644 index 00000000..530b1167 --- /dev/null +++ b/testcases/t/259-net-wm-user-time.t @@ -0,0 +1,74 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Please read the following documents before working on tests: +# • http://build.i3wm.org/docs/testsuite.html +# (or docs/testsuite) +# +# • http://build.i3wm.org/docs/lib-i3test.html +# (alternatively: perldoc ./testcases/lib/i3test.pm) +# +# • http://build.i3wm.org/docs/ipc.html +# (or docs/ipc) +# +# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf +# (unless you are already familiar with Perl) +# +# Test for _NET_WM_USER_TIME. +# Ticket: #2064 +use i3test; +use X11::XCB 'PROP_MODE_REPLACE'; + +my ($ws, $other, $con); + +sub open_window_with_user_time { + my $wm_user_time = shift; + + my $window = open_window( + before_map => sub { + my ($window) = @_; + + my $atomname = $x->atom(name => '_NET_WM_USER_TIME'); + my $atomtype = $x->atom(name => 'CARDINAL'); + $x->change_property( + PROP_MODE_REPLACE, + $window->id, + $atomname->id, + $atomtype->id, + 32, + 1, + pack('L1', $wm_user_time), + ); + }, + ); + + return $window; +} + +##################################################################### +# 1: if _NET_WM_USER_TIME is set to 0, the window is not focused +# initially. +##################################################################### + +$ws = fresh_workspace; + +open_window; +$other = get_focused($ws); +open_window_with_user_time(0); + +is(get_focused($ws), $other, 'new window is not focused'); + +##################################################################### +# 2: if _NET_WM_USER_TIME is set to something other than 0, the +# window is focused anyway. +##################################################################### + +$ws = fresh_workspace; + +open_window; +$other = get_focused($ws); +open_window_with_user_time(42); + +isnt(get_focused($ws), $other, 'new window is focused'); + +done_testing;