From f36050b3038b5be2b24727310b09f9ebf8d71af4 Mon Sep 17 00:00:00 2001
From: Orestis Floros <orestisflo@gmail.com>
Date: Thu, 4 Nov 2021 21:41:55 +0100
Subject: [PATCH] Add title tab color

Fixes #4575
---
 docs/userguide                                |  4 ++
 include/configuration.h                       |  2 +
 parser-specs/config.spec                      |  2 +-
 .../changes/2-client.focused_tab_title        |  1 +
 src/config.c                                  |  1 +
 src/config_directives.c                       | 38 +++++++++++--------
 src/x.c                                       | 16 +++++---
 testcases/t/201-config-parser.t               | 13 ++++---
 8 files changed, 51 insertions(+), 26 deletions(-)
 create mode 100644 release-notes/changes/2-client.focused_tab_title

diff --git a/docs/userguide b/docs/userguide
index f3162264..264f6201 100644
--- a/docs/userguide
+++ b/docs/userguide
@@ -1057,6 +1057,10 @@ client.focused::
 client.focused_inactive::
 	A client which is the focused one of its container, but it does not have
 	the focus at the moment.
+client.focused_tab_title::
+    Tab or stack container title that is the parent of the focused container
+    but not directly focused. Defaults to focused_inactive if not specified and
+    does not use the indicator and child_border colors.
 client.unfocused::
 	A client which is not the focused one of its container.
 client.urgent::
diff --git a/include/configuration.h b/include/configuration.h
index be072cf8..843e156f 100644
--- a/include/configuration.h
+++ b/include/configuration.h
@@ -238,9 +238,11 @@ struct Config {
         color_t background;
         struct Colortriple focused;
         struct Colortriple focused_inactive;
+        struct Colortriple focused_tab_title;
         struct Colortriple unfocused;
         struct Colortriple urgent;
         struct Colortriple placeholder;
+        bool got_focused_tab_title;
     } client;
     struct config_bar {
         struct Colortriple focused;
diff --git a/parser-specs/config.spec b/parser-specs/config.spec
index a52a769f..b62491ed 100644
--- a/parser-specs/config.spec
+++ b/parser-specs/config.spec
@@ -56,7 +56,7 @@ state INITIAL:
   exectype = 'exec_always', 'exec'         -> EXEC
   colorclass = 'client.background'
       -> COLOR_SINGLE
-  colorclass = 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder'
+  colorclass = 'client.focused_inactive', 'client.focused_tab_title', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder'
       -> COLOR_BORDER
 
 # We ignore comments and 'set' lines (variables).
diff --git a/release-notes/changes/2-client.focused_tab_title b/release-notes/changes/2-client.focused_tab_title
new file mode 100644
index 00000000..04802192
--- /dev/null
+++ b/release-notes/changes/2-client.focused_tab_title
@@ -0,0 +1 @@
+Add client.focused_tab_title color option
diff --git a/src/config.c b/src/config.c
index c590f3c5..6159f261 100644
--- a/src/config.c
+++ b/src/config.c
@@ -197,6 +197,7 @@ bool load_configuration(const char *override_configpath, config_load_t load_type
     INIT_COLOR(config.client.focused_inactive, "#333333", "#5f676a", "#ffffff", "#484e50");
     INIT_COLOR(config.client.unfocused, "#333333", "#222222", "#888888", "#292d2e");
     INIT_COLOR(config.client.urgent, "#2f343a", "#900000", "#ffffff", "#900000");
+    config.client.got_focused_tab_title = false;
 
     /* border and indicator color are ignored for placeholder contents */
     INIT_COLOR(config.client.placeholder, "#000000", "#0c0c0c", "#ffffff", "#000000");
diff --git a/src/config_directives.c b/src/config_directives.c
index 3bb6e793..a9e6322b 100644
--- a/src/config_directives.c
+++ b/src/config_directives.c
@@ -467,24 +467,32 @@ CFGFUN(color_single, const char *colorclass, const char *color) {
 }
 
 CFGFUN(color, const char *colorclass, const char *border, const char *background, const char *text, const char *indicator, const char *child_border) {
-#define APPLY_COLORS(classname)                                                              \
-    do {                                                                                     \
-        if (strcmp(colorclass, "client." #classname) == 0) {                                 \
-            config.client.classname.border = draw_util_hex_to_color(border);                 \
-            config.client.classname.background = draw_util_hex_to_color(background);         \
-            config.client.classname.text = draw_util_hex_to_color(text);                     \
-            if (indicator != NULL) {                                                         \
-                config.client.classname.indicator = draw_util_hex_to_color(indicator);       \
-            }                                                                                \
-            if (child_border != NULL) {                                                      \
-                config.client.classname.child_border = draw_util_hex_to_color(child_border); \
-            } else {                                                                         \
-                config.client.classname.child_border = config.client.classname.background;   \
-            }                                                                                \
-        }                                                                                    \
+#define APPLY_COLORS(classname)                                                                              \
+    do {                                                                                                     \
+        if (strcmp(colorclass, "client." #classname) == 0) {                                                 \
+            if (strcmp("focused_tab_title", #classname) == 0) {                                              \
+                config.client.got_focused_tab_title = true;                                                  \
+                if (indicator || child_border) {                                                             \
+                    ELOG("indicator and child_border colors have no effect for client.focused_tab_title\n"); \
+                }                                                                                            \
+            }                                                                                                \
+            config.client.classname.border = draw_util_hex_to_color(border);                                 \
+            config.client.classname.background = draw_util_hex_to_color(background);                         \
+            config.client.classname.text = draw_util_hex_to_color(text);                                     \
+            if (indicator != NULL) {                                                                         \
+                config.client.classname.indicator = draw_util_hex_to_color(indicator);                       \
+            }                                                                                                \
+            if (child_border != NULL) {                                                                      \
+                config.client.classname.child_border = draw_util_hex_to_color(child_border);                 \
+            } else {                                                                                         \
+                config.client.classname.child_border = config.client.classname.background;                   \
+            }                                                                                                \
+            return;                                                                                          \
+        }                                                                                                    \
     } while (0)
 
     APPLY_COLORS(focused_inactive);
+    APPLY_COLORS(focused_tab_title);
     APPLY_COLORS(focused);
     APPLY_COLORS(unfocused);
     APPLY_COLORS(urgent);
diff --git a/src/x.c b/src/x.c
index cdc29876..c65b445e 100644
--- a/src/x.c
+++ b/src/x.c
@@ -490,14 +490,20 @@ void x_draw_decoration(Con *con) {
     struct deco_render_params *p = scalloc(1, sizeof(struct deco_render_params));
 
     /* find out which colors to use */
-    if (con->urgent)
+    if (con->urgent) {
         p->color = &config.client.urgent;
-    else if (con == focused || con_inside_focused(con))
+    } else if (con == focused || con_inside_focused(con)) {
         p->color = &config.client.focused;
-    else if (con == TAILQ_FIRST(&(parent->focus_head)))
-        p->color = &config.client.focused_inactive;
-    else
+    } else if (con == TAILQ_FIRST(&(parent->focus_head))) {
+        if (config.client.got_focused_tab_title && !leaf && con_descend_focused(con) == focused) {
+            /* Stacked/tabbed parent of focused container */
+            p->color = &config.client.focused_tab_title;
+        } else {
+            p->color = &config.client.focused_inactive;
+        }
+    } else {
         p->color = &config.client.unfocused;
+    }
 
     p->border_style = con_border_style(con);
 
diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t
index a87a7b89..3a21a8a0 100644
--- a/testcases/t/201-config-parser.t
+++ b/testcases/t/201-config-parser.t
@@ -476,16 +476,18 @@ is(parser_calls($config),
 ################################################################################
 
 $config = <<'EOT';
-client.focused          #4c7899 #285577 #ffffff #2e9ef4 #b34d4c
-client.focused_inactive #333333 #5f676a #ffffff #484e50
-client.unfocused        #333333 #222222 #888888 #292d2e
-client.urgent           #2f343a #900000 #ffffff #900000 #c00000
-client.placeholder      #000000 #0c0c0c #ffffff #000000
+client.focused           #4c7899 #285577 #ffffff #2e9ef4 #b34d4c
+client.focused_inactive  #333333 #5f676a #ffffff #484e50
+client.focused_tab_title #444444 #555555 #ffffff
+client.unfocused         #333333 #222222 #888888 #292d2e
+client.urgent            #2f343a #900000 #ffffff #900000 #c00000
+client.placeholder       #000000 #0c0c0c #ffffff #000000
 EOT
 
 $expected = <<'EOT';
 cfg_color(client.focused, #4c7899, #285577, #ffffff, #2e9ef4, #b34d4c)
 cfg_color(client.focused_inactive, #333333, #5f676a, #ffffff, #484e50, NULL)
+cfg_color(client.focused_tab_title, #444444, #555555, #ffffff, NULL, NULL)
 cfg_color(client.unfocused, #333333, #222222, #888888, #292d2e, NULL)
 cfg_color(client.urgent, #2f343a, #900000, #ffffff, #900000, #c00000)
 cfg_color(client.placeholder, #000000, #0c0c0c, #ffffff, #000000, NULL)
@@ -551,6 +553,7 @@ my $expected_all_tokens = "ERROR: CONFIG: Expected one of these tokens: <end>, '
         exec
         client.background
         client.focused_inactive
+        client.focused_tab_title
         client.focused
         client.unfocused
         client.urgent