+
+/*
+ *
+ * Checks if the given container has an urgent child.
+ *
+ */
+bool con_has_urgent_child(Con *con) {
+ Con *child;
+
+ if (con_is_leaf(con))
+ return con->urgent;
+
+ /* We are not interested in floating windows since they can only be
+ * attached to a workspace → nodes_head instead of focus_head */
+ TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
+ if (con_has_urgent_child(child))
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Make all parent containers urgent if con is urgent or clear the urgent flag
+ * of all parent containers if there are no more urgent children left.
+ *
+ */
+void con_update_parents_urgency(Con *con) {
+ Con *parent = con->parent;
+
+ bool new_urgency_value = con->urgent;
+ while (parent && parent->type != CT_WORKSPACE && parent->type != CT_DOCKAREA) {
+ if (new_urgency_value) {
+ parent->urgent = true;
+ } else {
+ /* We can only reset the urgency when the parent
+ * has no other urgent children */
+ if (!con_has_urgent_child(parent))
+ parent->urgent = false;
+ }
+ parent = parent->parent;
+ }
+}
+
+/*
+ * Set urgency flag to the container, all the parent containers and the workspace.
+ *
+ */
+void con_set_urgency(Con *con, bool urgent) {
+ if (focused == con) {
+ DLOG("Ignoring urgency flag for current client\n");
+ con->window->urgent.tv_sec = 0;
+ con->window->urgent.tv_usec = 0;
+ return;
+ }
+
+ if (con->urgency_timer == NULL) {
+ con->urgent = urgent;
+ } else
+ DLOG("Discarding urgency WM_HINT because timer is running\n");
+
+ //CLIENT_LOG(con);
+ if (con->window) {
+ if (con->urgent) {
+ gettimeofday(&con->window->urgent, NULL);
+ } else {
+ con->window->urgent.tv_sec = 0;
+ con->window->urgent.tv_usec = 0;
+ }
+ }
+
+ con_update_parents_urgency(con);
+
+ if (con->urgent == urgent)
+ LOG("Urgency flag changed to %d\n", con->urgent);
+
+ Con *ws;
+ /* Set the urgency flag on the workspace, if a workspace could be found
+ * (for dock clients, that is not the case). */
+ if ((ws = con_get_workspace(con)) != NULL)
+ workspace_update_urgent_flag(ws);
+}
+
+/*
+ * Create a string representing the subtree under con.
+ *
+ */
+char *con_get_tree_representation(Con *con) {
+ /* this code works as follows:
+ * 1) create a string with the layout type (D/V/H/T/S) and an opening bracket
+ * 2) append the tree representation of the children to the string
+ * 3) add closing bracket
+ *
+ * The recursion ends when we hit a leaf, in which case we return the
+ * class_instance of the contained window.
+ */
+
+ /* end of recursion */
+ if (con_is_leaf(con)) {
+ if (!con->window)
+ return sstrdup("nowin");
+
+ if (!con->window->class_instance)
+ return sstrdup("noinstance");
+
+ return sstrdup(con->window->class_instance);
+ }
+
+ char *buf;
+ /* 1) add the Layout type to buf */
+ if (con->layout == L_DEFAULT)
+ buf = sstrdup("D[");
+ else if (con->layout == L_SPLITV)
+ buf = sstrdup("V[");
+ else if (con->layout == L_SPLITH)
+ buf = sstrdup("H[");
+ else if (con->layout == L_TABBED)
+ buf = sstrdup("T[");
+ else if (con->layout == L_STACKED)
+ buf = sstrdup("S[");
+ else {
+ ELOG("BUG: Code not updated to account for new layout type\n");
+ assert(false);
+ }
+
+ /* 2) append representation of children */
+ Con *child;
+ TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
+ char *child_txt = con_get_tree_representation(child);
+
+ char *tmp_buf;
+ sasprintf(&tmp_buf, "%s%s%s", buf,
+ (TAILQ_FIRST(&(con->nodes_head)) == child ? "" : " "), child_txt);
+ free(buf);
+ buf = tmp_buf;
+ }
+
+ /* 3) close the brackets */
+ char *complete_buf;
+ sasprintf(&complete_buf, "%s]", buf);
+ free(buf);
+
+ return complete_buf;
+}