the focus at the moment.
client.unfocused::
A client which is not the focused one of its container.
+client.urgent::
+ A client which has its urgency hint activated.
bar.focused::
The current workspace in the bottom bar.
bar.unfocused::
All other workspaces in the bottom bar.
+bar.urgent::
+ A workspace which has at least one client with an activated urgency hint.
Colors are in HTML hex format, see below.
struct Colortriple focused;
struct Colortriple focused_inactive;
struct Colortriple unfocused;
+ struct Colortriple urgent;
} client;
struct config_bar {
struct Colortriple focused;
struct Colortriple unfocused;
+ struct Colortriple urgent;
} bar;
};
/** Temporary flag needed for re-querying xinerama screens */
bool reassigned;
+ /** True if any client on this workspace has its urgent flag set */
+ bool urgent;
+
/** the client who is started in fullscreen mode on this workspace,
* NULL if there is none */
Client *fullscreen_client;
* the screen and its requested size is used */
bool dock;
+ /** True if the client set the urgency flag in its WM_HINTS property */
+ bool urgent;
+
/* After leaving fullscreen mode, a client needs to be reconfigured
* (configuration = setting X, Y, width and height). By setting the
* force_reconfigure flag, render_layout() will reconfigure the
xcb_window_t window, xcb_atom_t name,
xcb_get_property_reply_t *reply);
+/**
+ * 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);
+
/**
* Handles the transient for hints set by a window, signalizing that this
* window is a popup window for some other window.
*/
void workspace_unmap_clients(xcb_connection_t *conn, Workspace *u_ws);
-
+/**
+ * Maps all clients (and stack windows) of the given workspace.
+ *
+ */
void workspace_map_clients(xcb_connection_t *conn, Workspace *ws);
+/**
+ * Goes through all clients on the given workspace and updates the workspace’s
+ * urgent flag accordingly.
+ *
+ */
+void workspace_update_urgent_flag(Workspace *ws);
+
#endif
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");
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)
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) {
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;
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.
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:
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 */
/* 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");
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]);
ignore_enter_notify_forall(conn, u_ws, false);
}
+/*
+ * Goes through all clients on the given workspace and updates the workspace’s
+ * 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;
+}