From 59b33010848634cb8b3e5c91ac72d4bb69aae7b4 Mon Sep 17 00:00:00 2001
From: Daniel Mueller <deso@posteo.net>
Date: Sat, 30 Sep 2017 09:16:27 -0700
Subject: [PATCH 04/14] i3bar: Draw indication whether workspaces have windows
 or not

Awesome has the nice feature that it will indicate on each workspace
whether it contains windows or not by drawing a small rectangle along
with the workspace indication in the bar.
This change sets out to make i3 behave the same way. To accomplish this
task we introduce a new property, 'has_children', to the workspaces IPC
command that is indicative of whether a workspace has windows or not. We
then adjust i3 to inform IPC clients of workspace changes whenever a new
windows is created, destroyed, or moved to a different workspace.
---
 i3bar/include/workspaces.h |  1 +
 i3bar/src/workspaces.c     |  6 ++++++
 i3bar/src/xcb.c            | 15 +++++++++++++++
 src/con.c                  |  1 +
 src/handlers.c             |  3 +++
 src/ipc.c                  | 10 ++++++++++
 6 files changed, 36 insertions(+)

diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h
index 6c8e71..817aa1 100644
--- a/i3bar/include/workspaces.h
+++ b/i3bar/include/workspaces.h
@@ -38,6 +38,7 @@ struct i3_ws {
     bool visible;             /* If the ws is currently visible on an output */
     bool focused;             /* If the ws is currently focused */
     bool urgent;              /* If the urgent hint of the ws is set */
+    bool has_children;        /* If the current ws has children (i.e, windows) */
     struct i3_output *output; /* The current output of the ws */
 
     TAILQ_ENTRY(i3_ws) tailq; /* Pointer for the TAILQ-Macro */
diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c
index 26abf4..ed5705 100644
--- a/i3bar/src/workspaces.c
+++ b/i3bar/src/workspaces.c
@@ -47,6 +47,12 @@ static int workspaces_boolean_cb(void *params_, const int val) {
         return 1;
     }
 
+    if (!strcmp(params->cur_key, "has_children")) {
+        params->workspaces_walk->has_children = val;
+        FREE(params->cur_key);
+        return 1;
+    }
+
     FREE(params->cur_key);
 
     return 0;
diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c
index 2ae7fc..d47940 100644
--- a/i3bar/src/xcb.c
+++ b/i3bar/src/xcb.c
@@ -2162,6 +2162,21 @@ void draw_bars(bool unhide) {
                 draw_button(&(outputs_walk->buffer), fg_color, bg_color, border_color,
                             workspace_width, w, ws_walk->name_width, ws_walk->name);
 
+                if (ws_walk->has_children) {
+                    color_t rect_color = draw_util_hex_to_color("#ffffff");
+                    draw_util_rectangle(&(outputs_walk->buffer), rect_color,
+                                        workspace_width + logical_px(1),
+                                        2 * logical_px(1),
+                                        logical_px(6), logical_px(6));
+
+                    if (!ws_walk->visible) {
+                         draw_util_rectangle(&(outputs_walk->buffer), bg_color,
+                                             workspace_width + logical_px(2),
+                                             2 * logical_px(1) + logical_px(1),
+                                             logical_px(4), logical_px(4));
+                    }
+                }
+
                 workspace_width += w;
                 if (TAILQ_NEXT(ws_walk, tailq) != NULL) {
                     workspace_width += logical_px(ws_spacing_px);
diff --git a/src/con.c b/src/con.c
index 871915..c37d07 100644
--- a/src/con.c
+++ b/src/con.c
@@ -1491,6 +1491,7 @@ static bool _con_move_to_con(Con *con, Con *target, bool behind_focused, bool fi
     CALL(parent, on_remove_child);
 
     ipc_send_window_event("move", con);
+    ipc_send_workspace_event("reload", NULL, NULL);
     ewmh_update_wm_desktop();
     return true;
 }
diff --git a/src/handlers.c b/src/handlers.c
index 384005..96f601 100644
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -287,6 +287,8 @@ static void handle_map_request(const xcb_map_request_event_t *event) {
     add_ignore_event(event->sequence, -1);
 
     manage_window(event->window, cookie, false);
+    ipc_send_workspace_event("reload", NULL, NULL);
+    return;
 }
 
 /*
@@ -517,6 +519,7 @@ static void handle_unmap_notify_event(xcb_unmap_notify_event_t *event) {
 
     tree_close_internal(con, DONT_KILL_WINDOW, false);
     tree_render();
+    ipc_send_workspace_event("reload", NULL, NULL);
 
 ignore_end:
     /* If the client (as opposed to i3) destroyed or unmapped a window, an
diff --git a/src/ipc.c b/src/ipc.c
index 4ba0cb..72abff 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -420,6 +420,13 @@ void dump_node(yajl_gen gen, Con *con, bool inplace_restart) {
     ystr("urgent");
     y(bool, con->urgent);
 
+    /*
+     * We do not expose the newly introduced 'has_children' property
+     * here. It is only part of the 'get_workspaces' command in an
+     * attempt to not break functionality relying on i3-save-tree or the
+     * like.
+     */
+
     ystr("marks");
     y(array_open);
     mark_t *mark;
@@ -976,6 +983,9 @@ IPC_HANDLER(get_workspaces) {
             ystr("urgent");
             y(bool, ws->urgent);
 
+            ystr("has_children");
+            y(bool, con_has_children(ws));
+
             y(map_close);
         }
     }
-- 
2.52.0

