]> git.sur5r.net Git - i3/i3/commitdiff
Merge pull request #1601 from Airblader/feature-titlebar-marks
authorMichael Stapelberg <stapelberg@users.noreply.github.com>
Mon, 30 Mar 2015 21:53:42 +0000 (23:53 +0200)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Mon, 30 Mar 2015 21:53:42 +0000 (23:53 +0200)
Show marks in the titlebar

docs/userguide
include/config.h
include/config_directives.h
include/data.h
parser-specs/config.spec
src/commands.c
src/config.c
src/config_directives.c
src/x.c
testcases/t/201-config-parser.t

index 5eb485542cb8c4f82eb475247f330b27cb641acf..2e42493c598bd017bb3d64b31557328f3c505f97 100644 (file)
@@ -1006,6 +1006,24 @@ focus::
 none::
     The window will neither be focused, nor be marked urgent.
 
+=== Drawing marks on window decoration
+
+If activated, marks on windows are drawn in their window decoration. However,
+any mark starting with an underscore in its name (+_+) will not be drawn even if
+this option is activated.
+
+The default for this option is +yes+.
+
+*Syntax*:
+-------------------
+show_marks [yes|no]
+-------------------
+
+*Example*:
+--------------
+show_marks yes
+--------------
+
 == Configuring i3bar
 
 The bar at the bottom of your monitor is drawn by a separate process called
@@ -1886,6 +1904,8 @@ The additional +--toggle+ option will remove the mark if the window already has
 this mark, add it if the window has none or replace the current mark if it has
 another mark.
 
+Refer to +show_marks+ if you don't want marks to be shown in the window decoration.
+
 *Syntax*:
 ------------------------------
 mark [--toggle] identifier
index 5b534fb7379a4aef5f485f7e3b80b9cd513ae6f7..fb11cbe3a743bf02b77a247968a39e297740e1b3 100644 (file)
@@ -179,6 +179,10 @@ struct Config {
         FOWA_NONE
     } focus_on_window_activation;
 
+    /** Specifies whether or not marks should be displayed in the window
+     * decoration. Marks starting with a "_" will be ignored either way. */
+    bool show_marks;
+
     /** The default border style for new windows. */
     border_style_t default_border;
 
index 8f99e64861dc48b3bf20f5f93c1ba38fa3863823..b9189b2cc3c5bbaccbf5142dc8b77397411765c2 100644 (file)
@@ -52,6 +52,7 @@ CFGFUN(force_xinerama, const char *value);
 CFGFUN(fake_outputs, const char *outputs);
 CFGFUN(force_display_urgency_hint, const long duration_ms);
 CFGFUN(focus_on_window_activation, const char *mode);
+CFGFUN(show_marks, const char *value);
 CFGFUN(hide_edge_borders, const char *borders);
 CFGFUN(assign, const char *workspace);
 CFGFUN(ipc_socket, const char *path);
index cec571e9df8eecf71f10c32ebb8c2098f8770d16..d40ed29296e1136669473a83060e1c7b48b71067 100644 (file)
@@ -543,6 +543,8 @@ struct Con {
 
     /* user-definable mark to jump to this container later */
     char *mark;
+    /* cached to decide whether a redraw is needed */
+    bool mark_changed;
 
     double percent;
 
index e23c37c884364e50f28d32425cd10ed4d1fd8853..81357206febdd6a2a6b2854b85ac7ebd3e59cf57 100644 (file)
@@ -39,6 +39,7 @@ state INITIAL:
   'fake_outputs', 'fake-outputs'           -> FAKE_OUTPUTS
   'force_display_urgency_hint'             -> FORCE_DISPLAY_URGENCY_HINT
   'focus_on_window_activation'             -> FOCUS_ON_WINDOW_ACTIVATION
+  'show_marks'                             -> SHOW_MARKS
   'workspace'                              -> WORKSPACE
   'ipc_socket', 'ipc-socket'               -> IPC_SOCKET
   'restart_state'                          -> RESTART_STATE
@@ -205,6 +206,11 @@ state FORCE_DISPLAY_URGENCY_HINT:
   duration_ms = number
       -> FORCE_DISPLAY_URGENCY_HINT_MS
 
+# show_marks
+state SHOW_MARKS:
+  value = word
+      -> call cfg_show_marks($value)
+
 state FORCE_DISPLAY_URGENCY_HINT_MS:
   'ms'
       ->
index 2aa1f53757b1b9d314332c3f3de84b2b08271093..dc60e974f796ad4b244c15d5a8b427be211f53af 100644 (file)
@@ -1046,6 +1046,7 @@ void cmd_mark(I3_CMD, char *mark, char *toggle) {
     owindow *current;
     TAILQ_FOREACH(current, &owindows, owindows) {
         DLOG("matching: %p / %s\n", current->con, current->con->name);
+        current->con->mark_changed = true;
         if (toggle != NULL && current->con->mark && strcmp(current->con->mark, mark) == 0) {
             DLOG("removing window mark %s\n", mark);
             FREE(current->con->mark);
@@ -1070,8 +1071,10 @@ void cmd_mark(I3_CMD, char *mark, char *toggle) {
         if (matched)
             continue;
 
-        if (con->mark && strcmp(con->mark, mark) == 0)
+        if (con->mark && strcmp(con->mark, mark) == 0) {
             FREE(con->mark);
+            con->mark_changed = true;
+        }
     }
 
     cmd_output->needs_tree_render = true;
@@ -1087,14 +1090,20 @@ void cmd_unmark(I3_CMD, char *mark) {
     if (mark == NULL) {
         Con *con;
         TAILQ_FOREACH(con, &all_cons, all_cons) {
+            if (con->mark == NULL)
+                continue;
+
             FREE(con->mark);
+            con->mark_changed = true;
         }
         DLOG("removed all window marks");
     } else {
         Con *con;
         TAILQ_FOREACH(con, &all_cons, all_cons) {
-            if (con->mark && strcmp(con->mark, mark) == 0)
+            if (con->mark && strcmp(con->mark, mark) == 0) {
                 FREE(con->mark);
+                con->mark_changed = true;
+            }
         }
         DLOG("removed window mark %s\n", mark);
     }
index 36b7a16331c234171c543e76c39e44d85e264e83..8a1cb99c168e1934bc28063d641ded33d47b47b3 100644 (file)
@@ -190,6 +190,8 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
     INIT_COLOR(config.bar.unfocused, "#333333", "#222222", "#888888", "#000000");
     INIT_COLOR(config.bar.urgent, "#2f343a", "#900000", "#ffffff", "#000000");
 
+    config.show_marks = true;
+
     config.default_border = BS_NORMAL;
     config.default_floating_border = BS_NORMAL;
     config.default_border_width = logical_px(2);
index 039cb29e65a4769b96e10b5690e595e69aa7b810..eddfaa3dab2321559cb983ca4829fe516b3b1104 100644 (file)
@@ -346,6 +346,10 @@ CFGFUN(focus_on_window_activation, const char *mode) {
     DLOG("Set new focus_on_window_activation mode = %i", config.focus_on_window_activation);
 }
 
+CFGFUN(show_marks, const char *value) {
+    config.show_marks = eval_boolstr(value);
+}
+
 CFGFUN(workspace, const char *workspace, const char *output) {
     DLOG("Assigning workspace \"%s\" to output \"%s\"\n", workspace, output);
     /* Check for earlier assignments of the same workspace so that we
diff --git a/src/x.c b/src/x.c
index 9dd09117cf72eaeb234b2f1c10b7c49a9e89b17b..d29d4befeb5fb944ae748954760d0d7120cb258e 100644 (file)
--- a/src/x.c
+++ b/src/x.c
@@ -363,6 +363,7 @@ void x_draw_decoration(Con *con) {
         (con->window == NULL || !con->window->name_x_changed) &&
         !parent->pixmap_recreated &&
         !con->pixmap_recreated &&
+        !con->mark_changed &&
         memcmp(p, con->deco_render_params, sizeof(struct deco_render_params)) == 0) {
         free(p);
         goto copy_pixmaps;
@@ -381,6 +382,7 @@ void x_draw_decoration(Con *con) {
 
     parent->pixmap_recreated = false;
     con->pixmap_recreated = false;
+    con->mark_changed = false;
 
     /* 2: draw the client.background, but only for the parts around the client_rect */
     if (con->window != NULL) {
@@ -531,10 +533,25 @@ void x_draw_decoration(Con *con) {
     //DLOG("indent_level = %d, indent_mult = %d\n", indent_level, indent_mult);
     int indent_px = (indent_level * 5) * indent_mult;
 
+    int mark_width = 0;
+    if (config.show_marks && con->mark != NULL && (con->mark)[0] != '_') {
+        char *formatted_mark;
+        sasprintf(&formatted_mark, "[%s]", con->mark);
+        i3String *mark = i3string_from_utf8(formatted_mark);
+        FREE(formatted_mark);
+        mark_width = predict_text_width(mark);
+
+        draw_text(mark, parent->pixmap, parent->pm_gc,
+                  con->deco_rect.x + con->deco_rect.width - mark_width - logical_px(2),
+                  con->deco_rect.y + text_offset_y, mark_width);
+
+        I3STRING_FREE(mark);
+    }
+
     draw_text(win->name,
               parent->pixmap, parent->pm_gc,
-              con->deco_rect.x + 2 + indent_px, con->deco_rect.y + text_offset_y,
-              con->deco_rect.width - 2 - indent_px);
+              con->deco_rect.x + logical_px(2) + indent_px, con->deco_rect.y + text_offset_y,
+              con->deco_rect.width - logical_px(2) - indent_px - mark_width - logical_px(2));
 
 after_title:
     /* Since we don’t clip the text at all, it might in some cases be painted
index a6b1fe0c2cfacd4bdbb23ef5722c0db24af9f45b..3314aaf7a6312cc4b0079da20f1df3c85e2769c1 100644 (file)
@@ -433,7 +433,7 @@ client.focused          #4c7899 #285577 #ffffff #2e9ef4
 EOT
 
 my $expected_all_tokens = <<'EOT';
-ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder'
+ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'show_marks', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder'
 EOT
 
 my $expected_end = <<'EOT';