xmacro(_NET_WM_STATE_DEMANDS_ATTENTION)
xmacro(_NET_WM_STATE_MODAL)
xmacro(_NET_WM_STATE_HIDDEN)
+xmacro(_NET_WM_STATE_FOCUSED)
xmacro(_NET_WM_STATE)
xmacro(_NET_WM_WINDOW_TYPE)
xmacro(_NET_WM_WINDOW_TYPE_NORMAL)
*/
void ewmh_update_sticky(xcb_window_t window, bool sticky);
+/**
+ * Set or remove _NEW_WM_STATE_FOCUSED on the window.
+ *
+ */
+void ewmh_update_focused(xcb_window_t window, bool is_focused);
+
/**
* Set up the EWMH hints on the root window.
*
}
}
+/*
+ * Set or remove _NEW_WM_STATE_FOCUSED on the window.
+ *
+ */
+void ewmh_update_focused(xcb_window_t window, bool is_focused) {
+ if (is_focused) {
+ DLOG("Setting _NET_WM_STATE_FOCUSED for window = %d.\n", window);
+ xcb_add_property_atom(conn, window, A__NET_WM_STATE, A__NET_WM_STATE_FOCUSED);
+ } else {
+ DLOG("Removing _NET_WM_STATE_FOCUSED for window = %d.\n", window);
+ xcb_remove_property_atom(conn, window, A__NET_WM_STATE, A__NET_WM_STATE_FOCUSED);
+ }
+}
+
/*
* Set up the EWMH hints on the root window.
*
return NULL;
}
+/*
+ * Changes the atoms on the root window and the windows themselves to properly
+ * reflect the current focus for ewmh compliance.
+ *
+ */
+static void change_ewmh_focus(xcb_window_t new_focus, xcb_window_t old_focus) {
+ ewmh_update_active_window(new_focus);
+
+ if (new_focus != XCB_WINDOW_NONE) {
+ ewmh_update_focused(new_focus, true);
+ }
+
+ if (old_focus != XCB_WINDOW_NONE) {
+ ewmh_update_focused(old_focus, false);
+ }
+}
+
/*
* Initializes the X11 part for the given container. Called exactly once for
* every container from con_new().
to_focus, focused, focused->name);
send_take_focus(to_focus, last_timestamp);
- ewmh_update_active_window((con_has_managed_window(focused) ? focused->window->id : XCB_WINDOW_NONE));
+ change_ewmh_focus((con_has_managed_window(focused) ? focused->window->id : XCB_WINDOW_NONE), last_focused);
if (to_focus != last_focused && is_con_attached(focused))
ipc_send_window_event("focus", focused);
xcb_change_window_attributes(conn, focused->window->id, XCB_CW_EVENT_MASK, values);
}
- ewmh_update_active_window((con_has_managed_window(focused) ? focused->window->id : XCB_WINDOW_NONE));
+ change_ewmh_focus((con_has_managed_window(focused) ? focused->window->id : XCB_WINDOW_NONE), last_focused);
if (to_focus != XCB_NONE && to_focus != last_focused && focused->window != NULL && is_con_attached(focused))
ipc_send_window_event("focus", focused);
* root window in order to avoid an X11 fallback mechanism causing a ghosting effect (see #1378). */
DLOG("Still no window focused, better set focus to the EWMH support window (%d)\n", ewmh_window);
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, ewmh_window, last_timestamp);
- ewmh_update_active_window(XCB_WINDOW_NONE);
+ change_ewmh_focus(XCB_WINDOW_NONE, last_focused);
+
focused_id = ewmh_window;
}
kill_all_windows
events_for
listen_for_binding
+ is_net_wm_state_focused
);
=head1 NAME
return $command;
}
+=head2 is_net_wm_state_focused
+
+Returns true if the given window has the _NET_WM_STATE_FOCUSED atom.
+
+ ok(is_net_wm_state_focused($window), '_NET_WM_STATE_FOCUSED set');
+
+=cut
+sub is_net_wm_state_focused {
+ my ($window) = @_;
+
+ sync_with_i3;
+ my $atom = $x->atom(name => '_NET_WM_STATE_FOCUSED');
+ my $cookie = $x->get_property(
+ 0,
+ $window->{id},
+ $x->atom(name => '_NET_WM_STATE')->id,
+ GET_PROPERTY_TYPE_ANY,
+ 0,
+ 4096
+ );
+
+ my $reply = $x->get_property_reply($cookie->{sequence});
+ my $len = $reply->{length};
+ return 0 if $len == 0;
+
+ my @atoms = unpack("L$len", $reply->{value});
+ for (my $i = 0; $i < $len; $i++) {
+ return 1 if $atoms[$i] == $atom->id;
+ }
+
+ return 0;
+}
+
+
=head1 AUTHOR
Michael Stapelberg <michael@i3wm.org>
my $window = open_window;
ok(!recv_take_focus($window), 'did not receive ClientMessage');
+ ok(is_net_wm_state_focused($window), '_NET_WM_STATE_FOCUSED set');
my ($nodes) = get_ws_content($ws);
my $con = shift @$nodes;
$window->map;
ok(!recv_take_focus($window), 'did not receive ClientMessage');
+ ok(is_net_wm_state_focused($window), '_NET_WM_STATE_FOCUSED set');
my ($nodes) = get_ws_content($ws);
my $con = shift @$nodes;
my $window = open_window({ protocols => [ $take_focus ] });
ok(!recv_take_focus($window), 'did not receive ClientMessage');
+ ok(is_net_wm_state_focused($window), '_NET_WM_STATE_FOCUSED set');
my ($nodes) = get_ws_content($ws);
my $con = shift @$nodes;
--- /dev/null
+#!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)
+#
+# Tests for setting and removing the _NET_WM_STATE_FOCUSED atom properly.
+# Ticket: #2273
+use i3test;
+use X11::XCB qw(:all);
+
+my ($windowA, $windowB);
+
+fresh_workspace;
+$windowA = open_window;
+
+ok(is_net_wm_state_focused($windowA), 'a newly opened window that is focused should have _NET_WM_STATE_FOCUSED set');
+
+$windowB = open_window;
+
+ok(!is_net_wm_state_focused($windowA), 'when a another window is focused, the old window should not have _NET_WM_STATE_FOCUSED set');
+
+fresh_workspace;
+
+ok(!is_net_wm_state_focused($windowB), 'when focus moves to the ewmh support window, neither window should have _NET_WM_STATE_FOCUSED set');
+
+done_testing;