Re-implement support for the urgency hint, extend t/13-urgent.t
The actual rendering will follow
This commit is contained in:
parent
03c8da0a74
commit
32be3af109
|
@ -272,6 +272,10 @@ struct Con {
|
||||||
|
|
||||||
struct Window *window;
|
struct Window *window;
|
||||||
|
|
||||||
|
/* Should this container be marked urgent? This gets set when the window
|
||||||
|
* inside this container (if any) sets the urgency hint, for example. */
|
||||||
|
bool urgent;
|
||||||
|
|
||||||
/* ids/gc for the frame window */
|
/* ids/gc for the frame window */
|
||||||
xcb_window_t frame;
|
xcb_window_t frame;
|
||||||
xcb_gcontext_t gc;
|
xcb_gcontext_t gc;
|
||||||
|
|
|
@ -171,12 +171,14 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
xcb_window_t window, xcb_atom_t name,
|
xcb_window_t window, xcb_atom_t name,
|
||||||
xcb_get_property_reply_t *reply);
|
xcb_get_property_reply_t *reply);
|
||||||
|
|
||||||
|
#endif
|
||||||
/**
|
/**
|
||||||
* Handles the WM_HINTS property for extracting the urgency state of the window.
|
* Handles the WM_HINTS property for extracting the urgency state of the window.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
||||||
xcb_atom_t name, xcb_get_property_reply_t *reply);
|
xcb_atom_t name, xcb_get_property_reply_t *reply);
|
||||||
|
#if 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the transient for hints set by a window, signalizing that this
|
* Handles the transient for hints set by a window, signalizing that this
|
||||||
|
|
|
@ -90,14 +90,16 @@ void workspace_unmap_clients(xcb_connection_t *conn, Workspace *u_ws);
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void workspace_map_clients(xcb_connection_t *conn, Workspace *ws);
|
void workspace_map_clients(xcb_connection_t *conn, Workspace *ws);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Goes through all clients on the given workspace and updates the workspace’s
|
* Goes through all clients on the given workspace and updates the workspace’s
|
||||||
* urgent flag accordingly.
|
* urgent flag accordingly.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void workspace_update_urgent_flag(Workspace *ws);
|
void workspace_update_urgent_flag(Con *ws);
|
||||||
|
|
||||||
|
#if 0
|
||||||
/*
|
/*
|
||||||
* Returns the width of the workspace.
|
* Returns the width of the workspace.
|
||||||
*
|
*
|
||||||
|
|
|
@ -91,6 +91,10 @@ void con_focus(Con *con) {
|
||||||
con_focus(con->parent);
|
con_focus(con->parent);
|
||||||
|
|
||||||
focused = con;
|
focused = con;
|
||||||
|
if (con->urgent) {
|
||||||
|
con->urgent = false;
|
||||||
|
workspace_update_urgent_flag(con_get_workspace(con));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -810,6 +810,7 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handles the WM_HINTS property for extracting the urgency state of the window.
|
* Handles the WM_HINTS property for extracting the urgency state of the window.
|
||||||
|
@ -817,46 +818,49 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
|
||||||
*/
|
*/
|
||||||
int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
||||||
xcb_atom_t name, xcb_get_property_reply_t *reply) {
|
xcb_atom_t name, xcb_get_property_reply_t *reply) {
|
||||||
Client *client = table_get(&by_child, window);
|
Con *con = con_by_window_id(window);
|
||||||
if (client == NULL) {
|
if (con == NULL) {
|
||||||
DLOG("Received WM_HINTS for unknown client\n");
|
DLOG("Received WM_HINTS for unknown client\n");
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
xcb_wm_hints_t hints;
|
|
||||||
|
|
||||||
if (reply != NULL) {
|
|
||||||
if (!xcb_get_wm_hints_from_reply(&hints, reply))
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
if (!xcb_get_wm_hints_reply(conn, xcb_get_wm_hints_unchecked(conn, client->child), &hints, NULL))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Client *last_focused = SLIST_FIRST(&(c_ws->focus_stack));
|
|
||||||
if (!client->urgent && client == last_focused) {
|
|
||||||
DLOG("Ignoring urgency flag for current client\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the flag on the client directly */
|
|
||||||
client->urgent = (xcb_wm_hints_get_urgency(&hints) != 0);
|
|
||||||
CLIENT_LOG(client);
|
|
||||||
LOG("Urgency flag changed to %d\n", client->urgent);
|
|
||||||
|
|
||||||
workspace_update_urgent_flag(client->workspace);
|
|
||||||
redecorate_window(conn, client);
|
|
||||||
|
|
||||||
/* If the workspace this client is on is not visible, we need to redraw
|
|
||||||
* the workspace bar */
|
|
||||||
if (!workspace_is_visible(client->workspace)) {
|
|
||||||
Output *output = client->workspace->output;
|
|
||||||
render_workspace(conn, output, output->current_workspace);
|
|
||||||
xcb_flush(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_wm_hints_t hints;
|
||||||
|
|
||||||
|
if (reply != NULL) {
|
||||||
|
if (!xcb_get_wm_hints_from_reply(&hints, reply))
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
if (!xcb_get_wm_hints_reply(conn, xcb_get_wm_hints_unchecked(conn, con->window->id), &hints, NULL))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!con->urgent && focused == con) {
|
||||||
|
DLOG("Ignoring urgency flag for current client\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the flag on the client directly */
|
||||||
|
con->urgent = (xcb_wm_hints_get_urgency(&hints) != 0);
|
||||||
|
//CLIENT_LOG(con);
|
||||||
|
LOG("Urgency flag changed to %d\n", con->urgent);
|
||||||
|
|
||||||
|
workspace_update_urgent_flag(con_get_workspace(con));
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* If the workspace this client is on is not visible, we need to redraw
|
||||||
|
* the workspace bar */
|
||||||
|
if (!workspace_is_visible(client->workspace)) {
|
||||||
|
Output *output = client->workspace->output;
|
||||||
|
render_workspace(conn, output, output->current_workspace);
|
||||||
|
xcb_flush(conn);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handles the transient for hints set by a window, signalizing that this window is a popup window
|
* Handles the transient for hints set by a window, signalizing that this window is a popup window
|
||||||
* for some other window.
|
* for some other window.
|
||||||
|
|
|
@ -137,6 +137,9 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
|
||||||
ystr("orientation");
|
ystr("orientation");
|
||||||
y(integer, con->orientation);
|
y(integer, con->orientation);
|
||||||
|
|
||||||
|
ystr("urgent");
|
||||||
|
y(integer, con->urgent);
|
||||||
|
|
||||||
ystr("layout");
|
ystr("layout");
|
||||||
y(integer, con->layout);
|
y(integer, con->layout);
|
||||||
|
|
||||||
|
|
4
src/nc.c
4
src/nc.c
|
@ -2,6 +2,7 @@
|
||||||
* vim:ts=4:sw=4:expandtab
|
* vim:ts=4:sw=4:expandtab
|
||||||
*/
|
*/
|
||||||
#include <ev.h>
|
#include <ev.h>
|
||||||
|
#include <limits.h>
|
||||||
#include "all.h"
|
#include "all.h"
|
||||||
|
|
||||||
static int xkb_event_base;
|
static int xkb_event_base;
|
||||||
|
@ -254,6 +255,9 @@ int main(int argc, char *argv[]) {
|
||||||
/* Watch _NET_WM_NAME (title of the window encoded in UTF-8) */
|
/* Watch _NET_WM_NAME (title of the window encoded in UTF-8) */
|
||||||
xcb_property_set_handler(&prophs, atoms[_NET_WM_NAME], 128, handle_windowname_change, NULL);
|
xcb_property_set_handler(&prophs, atoms[_NET_WM_NAME], 128, handle_windowname_change, NULL);
|
||||||
|
|
||||||
|
/* Watch WM_HINTS (contains the urgent property) */
|
||||||
|
xcb_property_set_handler(&prophs, WM_HINTS, UINT_MAX, handle_hints, NULL);
|
||||||
|
|
||||||
/* Watch WM_NAME (title of the window encoded in COMPOUND_TEXT) */
|
/* Watch WM_NAME (title of the window encoded in COMPOUND_TEXT) */
|
||||||
xcb_watch_wm_name(&prophs, 128, handle_windowname_change_legacy, NULL);
|
xcb_watch_wm_name(&prophs, 128, handle_windowname_change_legacy, NULL);
|
||||||
|
|
||||||
|
|
|
@ -429,31 +429,37 @@ void workspace_unmap_clients(xcb_connection_t *conn, Workspace *u_ws) {
|
||||||
|
|
||||||
ignore_enter_notify_forall(conn, u_ws, false);
|
ignore_enter_notify_forall(conn, u_ws, false);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool get_urgency_flag(Con *con) {
|
||||||
|
Con *child;
|
||||||
|
TAILQ_FOREACH(child, &(con->nodes_head), nodes)
|
||||||
|
if (child->urgent || get_urgency_flag(child))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(child, &(con->floating_head), floating_windows)
|
||||||
|
if (child->urgent || get_urgency_flag(child))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Goes through all clients on the given workspace and updates the workspace’s
|
* Goes through all clients on the given workspace and updates the workspace’s
|
||||||
* urgent flag accordingly.
|
* urgent flag accordingly.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void workspace_update_urgent_flag(Workspace *ws) {
|
void workspace_update_urgent_flag(Con *ws) {
|
||||||
Client *current;
|
bool old_flag = ws->urgent;
|
||||||
bool old_flag = ws->urgent;
|
ws->urgent = get_urgency_flag(ws);
|
||||||
bool urgent = false;
|
DLOG("Workspace urgency flag changed from %d to %d\n", old_flag, ws->urgent);
|
||||||
|
|
||||||
SLIST_FOREACH(current, &(ws->focus_stack), focus_clients) {
|
if (old_flag != ws->urgent)
|
||||||
if (!current->urgent)
|
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"urgent\"}");
|
||||||
continue;
|
|
||||||
|
|
||||||
urgent = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ws->urgent = urgent;
|
|
||||||
|
|
||||||
if (old_flag != urgent)
|
|
||||||
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"urgent\"}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the width of the workspace.
|
* Returns the width of the workspace.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
#!perl
|
#!perl
|
||||||
# vim:ts=4:sw=4:expandtab
|
# vim:ts=4:sw=4:expandtab
|
||||||
# Beware that this test uses workspace 9 to perform some tests (it expects
|
|
||||||
# the workspace to be empty).
|
|
||||||
# TODO: skip it by default?
|
|
||||||
|
|
||||||
use i3test tests => 7;
|
use i3test tests => 10;
|
||||||
use X11::XCB qw(:all);
|
use X11::XCB qw(:all);
|
||||||
use Time::HiRes qw(sleep);
|
use Time::HiRes qw(sleep);
|
||||||
|
use List::Util qw(first);
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
use_ok('X11::XCB::Connection') or BAIL_OUT('Cannot load X11::XCB::Connection');
|
use_ok('X11::XCB::Connection') or BAIL_OUT('Cannot load X11::XCB::Connection');
|
||||||
|
@ -14,33 +12,68 @@ BEGIN {
|
||||||
|
|
||||||
my $x = X11::XCB::Connection->new;
|
my $x = X11::XCB::Connection->new;
|
||||||
|
|
||||||
my $i3 = i3;
|
my $i3 = i3("/tmp/nestedcons");
|
||||||
|
my $tmp = get_unused_workspace();
|
||||||
# Switch to the nineth workspace
|
$i3->command("workspace $tmp")->recv;
|
||||||
$i3->command('9')->recv;
|
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# Create two windows and put them in stacking mode
|
# Create two windows and put them in stacking mode
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
my $top = i3test::open_standard_window($x);
|
$i3->command('split v')->recv;
|
||||||
sleep 0.25;
|
|
||||||
my $bottom = i3test::open_standard_window($x);
|
|
||||||
sleep 0.25;
|
|
||||||
|
|
||||||
$i3->command('s')->recv;
|
my $top = i3test::open_standard_window($x);
|
||||||
|
my $bottom = i3test::open_standard_window($x);
|
||||||
|
|
||||||
|
my @urgent = grep { $_->{urgent} == 1 } @{get_ws_content($tmp)};
|
||||||
|
is(@urgent, 0, 'no window got the urgent flag');
|
||||||
|
|
||||||
|
#$i3->command('layout stacking')->recv;
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# Add the urgency hint, switch to a different workspace and back again
|
# Add the urgency hint, switch to a different workspace and back again
|
||||||
#####################################################################
|
#####################################################################
|
||||||
$top->add_hint('urgency');
|
$top->add_hint('urgency');
|
||||||
sleep 1;
|
sleep 0.5;
|
||||||
|
|
||||||
$i3->command('1')->recv;
|
@content = @{get_ws_content($tmp)};
|
||||||
$i3->command('9')->recv;
|
@urgent = grep { $_->{urgent} == 1 } @content;
|
||||||
$i3->command('1')->recv;
|
$top_info = first { $_->{window} == $top->id } @content;
|
||||||
|
$bottom_info = first { $_->{window} == $bottom->id } @content;
|
||||||
|
|
||||||
my $std = i3test::open_standard_window($x);
|
is($top_info->{urgent}, 1, 'top window is marked urgent');
|
||||||
sleep 0.25;
|
is($bottom_info->{urgent}, 0, 'bottom window is not marked urgent');
|
||||||
$std->add_hint('urgency');
|
is(@urgent, 1, 'exactly one window got the urgent flag');
|
||||||
sleep 1;
|
|
||||||
|
$i3->command('[id="' . $top->id . '"] focus')->recv;
|
||||||
|
|
||||||
|
@urgent = grep { $_->{urgent} == 1 } @{get_ws_content($tmp)};
|
||||||
|
is(@urgent, 0, 'no window got the urgent flag after focusing');
|
||||||
|
|
||||||
|
$top->add_hint('urgency');
|
||||||
|
sleep 0.5;
|
||||||
|
|
||||||
|
@urgent = grep { $_->{urgent} == 1 } @{get_ws_content($tmp)};
|
||||||
|
is(@urgent, 0, 'no window got the urgent flag after re-setting urgency hint');
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Check if the workspace urgency hint gets set/cleared correctly
|
||||||
|
#####################################################################
|
||||||
|
my $ws = get_ws($tmp);
|
||||||
|
is($ws->{urgent}, 0, 'urgent flag not set on workspace');
|
||||||
|
|
||||||
|
my $otmp = get_unused_workspace();
|
||||||
|
$i3->command("workspace $otmp")->recv;
|
||||||
|
|
||||||
|
$top->add_hint('urgency');
|
||||||
|
sleep 0.5;
|
||||||
|
|
||||||
|
$ws = get_ws($tmp);
|
||||||
|
is($ws->{urgent}, 1, 'urgent flag set on workspace');
|
||||||
|
|
||||||
|
$i3->command("workspace $tmp")->recv;
|
||||||
|
|
||||||
|
$ws = get_ws($tmp);
|
||||||
|
is($ws->{urgent}, 0, 'urgent flag not set on workspace after switching');
|
||||||
|
|
||||||
|
diag( "Testing i3, Perl $], $^X" );
|
||||||
|
|
Loading…
Reference in New Issue