Implement the urgency hint for windows/workspaces

Thanks to Mikael for bringing it to my mind. This change introduces
two new color classes, client.urgent and bar.urgent. By default,
urgent clients are drawn in red (colors by Atsutane).
This commit is contained in:
Michael Stapelberg
2009-09-06 22:40:11 +02:00
parent e893902585
commit 2ff2a6a315
11 changed files with 125 additions and 15 deletions

View File

@ -210,6 +210,10 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
config.client.unfocused.background = get_colorpixel(conn, "#222222");
config.client.unfocused.text = get_colorpixel(conn, "#888888");
config.client.urgent.border = get_colorpixel(conn, "#2f343a");
config.client.urgent.background = get_colorpixel(conn, "#900000");
config.client.urgent.text = get_colorpixel(conn, "#ffffff");
config.bar.focused.border = get_colorpixel(conn, "#4c7899");
config.bar.focused.background = get_colorpixel(conn, "#285577");
config.bar.focused.text = get_colorpixel(conn, "#ffffff");
@ -218,6 +222,10 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
config.bar.unfocused.background = get_colorpixel(conn, "#222222");
config.bar.unfocused.text = get_colorpixel(conn, "#888888");
config.bar.urgent.border = get_colorpixel(conn, "#2f343a");
config.bar.urgent.background = get_colorpixel(conn, "#900000");
config.bar.urgent.text = get_colorpixel(conn, "#ffffff");
FILE *handle;
if (override_configpath != NULL) {
if ((handle = fopen(override_configpath, "r")) == NULL)
@ -260,8 +268,10 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
OPTION_COLORTRIPLE("client.focused", client.focused);
OPTION_COLORTRIPLE("client.focused_inactive", client.focused_inactive);
OPTION_COLORTRIPLE("client.unfocused", client.unfocused);
OPTION_COLORTRIPLE("client.urgent", client.urgent);
OPTION_COLORTRIPLE("bar.focused", bar.focused);
OPTION_COLORTRIPLE("bar.unfocused", bar.unfocused);
OPTION_COLORTRIPLE("bar.urgent", bar.urgent);
/* exec-lines (autostart) */
if (strcasecmp(key, "exec") == 0) {

View File

@ -933,8 +933,10 @@ int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t *
decorate_window(conn, client, client->frame, client->titlegc, 0, 0);
else {
uint32_t background_color;
if (client->urgent)
background_color = config.client.urgent.background;
/* Distinguish if the window is currently focused… */
if (CUR_CELL->currently_focused == client)
else if (CUR_CELL->currently_focused == client)
background_color = config.client.focused.background;
/* …or if it is the focused window in a not focused container */
else background_color = config.client.focused_inactive.background;
@ -1100,6 +1102,43 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
return 1;
}
/*
* 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,
xcb_atom_t name, xcb_get_property_reply_t *reply) {
Client *client = table_get(&by_child, window);
if (client == NULL) {
LOG("Received WM_HINTS for unknown client\n");
return 1;
}
xcb_wm_hints_t hints;
if (reply != NULL)
xcb_get_wm_hints_from_reply(&hints, reply);
else
xcb_get_wm_hints_reply(conn, xcb_get_wm_hints_unchecked(conn, client->child), &hints, NULL);
/* 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)) {
i3Screen *screen = client->workspace->screen;
render_workspace(conn, screen, &(workspaces[screen->current_workspace]));
xcb_flush(conn);
}
return 1;
}
/*
* Handles the transient for hints set by a window, signalizing that this window is a popup window
* for some other window.

View File

@ -125,18 +125,23 @@ void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t draw
return;
last_focused = SLIST_FIRST(&(client->workspace->focus_stack));
if (client_is_floating(client)) {
if (last_focused == client)
color = &(config.client.focused);
else color = &(config.client.unfocused);
} else {
if (client->container->currently_focused == client) {
/* Distinguish if the window is currently focused… */
if (last_focused == client && c_ws == client->workspace)
/* Is the window urgent? */
if (client->urgent)
color = &(config.client.urgent);
else {
if (client_is_floating(client)) {
if (last_focused == client)
color = &(config.client.focused);
/* …or if it is the focused window in a not focused container */
else color = &(config.client.focused_inactive);
} else color = &(config.client.unfocused);
else color = &(config.client.unfocused);
} else {
if (client->container->currently_focused == client) {
/* Distinguish if the window is currently focused… */
if (last_focused == client && c_ws == client->workspace)
color = &(config.client.focused);
/* …or if it is the focused window in a not focused container */
else color = &(config.client.focused_inactive);
} else color = &(config.client.unfocused);
}
}
/* Our plan is the following:
@ -515,10 +520,15 @@ static void render_internal_bar(xcb_connection_t *conn, Workspace *r_ws, int wid
if (workspaces[c].screen != screen)
continue;
struct Colortriple *color = (screen->current_workspace == c ? &(config.bar.focused) :
&(config.bar.unfocused));
struct Colortriple *color;
Workspace *ws = &workspaces[c];
if (screen->current_workspace == c)
color = &(config.bar.focused);
else if (ws->urgent)
color = &(config.bar.urgent);
else color = &(config.bar.unfocused);
/* Draw the outer rect */
xcb_draw_rect(conn, screen->bar, screen->bargc, color->border,
drawn, /* x */

View File

@ -398,6 +398,9 @@ int main(int argc, char *argv[], char *env[]) {
/* Watch WM_CLIENT_LEADER (= logical parent window for toolbars etc.) */
xcb_property_set_handler(&prophs, atoms[WM_CLIENT_LEADER], UINT_MAX, handle_clientleader_change, NULL);
/* Watch WM_HINTS (contains the urgent property) */
xcb_property_set_handler(&prophs, WM_HINTS, UINT_MAX, handle_hints, NULL);
/* Set up the atoms we support */
check_error(conn, xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED],
ATOM, 32, 7, atoms), "Could not set _NET_SUPPORTED");

View File

@ -105,6 +105,7 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_CLASS);
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NORMAL_HINTS);
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_HINTS);
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_TRANSIENT_FOR);
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[WM_CLIENT_LEADER]);
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[_NET_WM_NAME]);

View File

@ -351,3 +351,21 @@ void workspace_unmap_clients(xcb_connection_t *conn, Workspace *u_ws) {
ignore_enter_notify_forall(conn, u_ws, false);
}
/*
* Goes through all clients on the given workspace and updates the workspaces
* urgent flag accordingly.
*
*/
void workspace_update_urgent_flag(Workspace *ws) {
Client *current;
SLIST_FOREACH(current, &(ws->focus_stack), focus_clients) {
if (!current->urgent)
continue;
ws->urgent = true;
return;
}
ws->urgent = false;
}