]> git.sur5r.net Git - i3/i3/commitdiff
Introduce "--add" for marking windows.
authorIngo Bürk <ingo.buerk@tngtech.com>
Mon, 19 Oct 2015 16:31:21 +0000 (18:31 +0200)
committerIngo Bürk <ingo.buerk@tngtech.com>
Thu, 22 Oct 2015 13:32:15 +0000 (15:32 +0200)
In order to keep compatibility to before allowing multiple marks on a window,
we introduce a flag "--add" that must be set to put more than one mark on a
window. The default, which is also available as "--replace", keeps the old
behavior of overwriting a mark when setting a new one.

fixes #2014

docs/userguide
include/commands.h
include/con.h
include/data.h
parser-specs/commands.spec
src/commands.c
src/con.c
src/load_layout.c
testcases/t/210-mark-unmark.t
testcases/t/255-multiple-marks.t

index f80f19f9e46edca56299bd53d64799caed595c26..e07e544d93b242560021ceb90d406fa1eb8a8dcb 100644 (file)
@@ -2115,17 +2115,21 @@ for this purpose: It lets you input a command and sends the command to i3. It
 can also prefix this command and display a custom prompt for the input dialog.
 
 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.
+this mark or add it otherwise. Note that you may need to use this in
+combination with +--add+ (see below) as any other marks will otherwise be
+removed.
+
+By default, a window can only have one mark. You can use the +--add+ flag to
+put more than one mark on a window.
 
 Refer to <<show_marks>> if you don't want marks to be shown in the window decoration.
 
 *Syntax*:
-------------------------------
-mark [--toggle] <identifier>
+----------------------------------------------
+mark [--add|--replace] [--toggle] <identifier>
 [con_mark="identifier"] focus
 unmark <identifier>
-------------------------------
+----------------------------------------------
 
 *Example (in a terminal)*:
 ------------------------------
index e0bb2f9279b15c6e3b7f69ac2deab83ac1fc9fd0..d3485f154fb7dac95c5c742f78fa2a9b6b6cec73 100644 (file)
@@ -115,10 +115,10 @@ void cmd_workspace_back_and_forth(I3_CMD);
 void cmd_workspace_name(I3_CMD, const char *name);
 
 /**
- * Implementation of 'mark [--toggle] <mark>'
+ * Implementation of 'mark [--add|--replace] [--toggle] <mark>'
  *
  */
-void cmd_mark(I3_CMD, const char *mark, const char *toggle);
+void cmd_mark(I3_CMD, const char *mark, const char *mode, const char *toggle);
 
 /**
  * Implementation of 'unmark [mark]'
index df94c1ae30cb730bf2385e65c49de30cba8471bb..b448b8c2b7ad524ad8cad7e7c7effbc478c13d43 100644 (file)
@@ -158,13 +158,13 @@ bool con_has_mark(Con *con, const char *mark);
  * Otherwise, the mark is assigned to the container.
  *
  */
-void con_mark_toggle(Con *con, const char *mark);
+void con_mark_toggle(Con *con, const char *mark, mark_mode_t mode);
 
 /**
  * Assigns a mark to the container.
  *
  */
-void con_mark(Con *con, const char *mark);
+void con_mark(Con *con, const char *mark, mark_mode_t mode);
 
 /**
  * If mark is NULL, this removes all existing marks.
index ee7f82c02bb6920379dec7b7c1dfe94a4938d17d..3a752c2e94e56932bbfaaee4f22e6ae12dbea2ff 100644 (file)
@@ -75,6 +75,9 @@ typedef enum { ADJ_NONE = 0,
                ADJ_UPPER_SCREEN_EDGE = (1 << 2),
                ADJ_LOWER_SCREEN_EDGE = (1 << 4) } adjacent_t;
 
+typedef enum { MM_REPLACE,
+               MM_ADD } mark_mode_t;
+
 /**
  * Container layouts. See Con::layout.
  */
index b3b5e3385fafc09259463d85367a8d404dc0b10a..475dc4bd33c2b99dec75d6f8814553db721e4a7f 100644 (file)
@@ -199,12 +199,14 @@ state FLOATING:
   floating = 'enable', 'disable', 'toggle'
       -> call cmd_floating($floating)
 
-# mark [--toggle] <mark>
+# mark [--add|--replace] [--toggle] <mark>
 state MARK:
+  mode = '--add', '--replace'
+      ->
   toggle = '--toggle'
       ->
   mark = string
-      -> call cmd_mark($mark, $toggle)
+      -> call cmd_mark($mark, $mode, $toggle)
 
 # unmark [mark]
 state UNMARK:
index ab9a41353d0e18b59356deea7916a4a68f7fdfa2..a9b98c5370414fd25e1fe86edfc493a4b580ca12 100644 (file)
@@ -1003,10 +1003,10 @@ void cmd_workspace_name(I3_CMD, const char *name) {
 }
 
 /*
- * Implementation of 'mark [--toggle] <mark>'
+ * Implementation of 'mark [--add|--replace] [--toggle] <mark>'
  *
  */
-void cmd_mark(I3_CMD, const char *mark, const char *toggle) {
+void cmd_mark(I3_CMD, const char *mark, const char *mode, const char *toggle) {
     HANDLE_EMPTY_MATCH;
 
     owindow *current = TAILQ_FIRST(&owindows);
@@ -1022,10 +1022,12 @@ void cmd_mark(I3_CMD, const char *mark, const char *toggle) {
     }
 
     DLOG("matching: %p / %s\n", current->con, current->con->name);
+
+    mark_mode_t mark_mode = (mode == NULL || strcmp(mode, "--replace") == 0) ? MM_REPLACE : MM_ADD;
     if (toggle != NULL) {
-        con_mark_toggle(current->con, mark);
+        con_mark_toggle(current->con, mark, mark_mode);
     } else {
-        con_mark(current->con, mark);
+        con_mark(current->con, mark, mark_mode);
     }
 
     cmd_output->needs_tree_render = true;
index bf7dd5451dd25b6c4dc70078f8080fb3d2f2a459..9238acad27c2c1bdd7c11c2d31f5353096943d9a 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -540,14 +540,14 @@ bool con_has_mark(Con *con, const char *mark) {
  * Otherwise, the mark is assigned to the container.
  *
  */
-void con_mark_toggle(Con *con, const char *mark) {
+void con_mark_toggle(Con *con, const char *mark, mark_mode_t mode) {
     assert(con != NULL);
     DLOG("Toggling mark \"%s\" on con = %p.\n", mark, con);
 
     if (con_has_mark(con, mark)) {
         con_unmark(mark);
     } else {
-        con_mark(con, mark);
+        con_mark(con, mark, mode);
     }
 }
 
@@ -555,11 +555,19 @@ void con_mark_toggle(Con *con, const char *mark) {
  * Assigns a mark to the container.
  *
  */
-void con_mark(Con *con, const char *mark) {
+void con_mark(Con *con, const char *mark, mark_mode_t mode) {
     assert(con != NULL);
     DLOG("Setting mark \"%s\" on con = %p.\n", mark, con);
 
     con_unmark(mark);
+    if (mode == MM_REPLACE) {
+        DLOG("Removing all existing marks on con = %p.\n", con);
+
+        mark_t *current;
+        TAILQ_FOREACH(current, &(con->marks_head), marks) {
+            con_unmark(current->name);
+        }
+    }
 
     mark_t *new = scalloc(1, sizeof(mark_t));
     new->name = sstrdup(mark);
index 68c4f4a2bb244048a08c185b2d6f73a814bd86d9..dc84c607f019984aaf4b453d86f87a4b9a736898 100644 (file)
@@ -246,7 +246,7 @@ static int json_string(void *ctx, const unsigned char *val, size_t len) {
         char *mark;
         sasprintf(&mark, "%.*s", (int)len, val);
 
-        con_mark(json_node, mark);
+        con_mark(json_node, mark, MM_ADD);
     } else {
         if (strcasecmp(last_key, "name") == 0) {
             json_node->name = scalloc(len + 1, 1);
@@ -354,7 +354,7 @@ static int json_string(void *ctx, const unsigned char *val, size_t len) {
             char *buf = NULL;
             sasprintf(&buf, "%.*s", (int)len, val);
 
-            con_mark(json_node, buf);
+            con_mark(json_node, buf, MM_REPLACE);
         } else if (strcasecmp(last_key, "floating") == 0) {
             char *buf = NULL;
             sasprintf(&buf, "%.*s", (int)len, val);
index 39fc090464375ca38f4b1217dfc8460d81f9c3b0..446d54653f4f9e0cd57327630160fa43c5b27ae7 100644 (file)
@@ -118,7 +118,17 @@ cmd 'mark --toggle important';
 is_deeply(get_mark_for_window_on_workspace($tmp, $con), [ 'important' ], 'container now has the mark');
 
 ##############################################################
-# 7: mark a con, toggle the mark on another con,
+# 7: mark a con, toggle a different mark, check it is marked
+#    with the new mark
+##############################################################
+
+$con = open_window;
+cmd 'mark boring';
+cmd 'mark --replace --toggle important';
+is_deeply(get_mark_for_window_on_workspace($tmp, $con), [ 'important' ], 'container has the most recent mark');
+
+##############################################################
+# 8: mark a con, toggle the mark on another con,
 #    check only the latter has the mark
 ##############################################################
 
@@ -133,7 +143,7 @@ is_deeply(get_mark_for_window_on_workspace($tmp, $first), [ 'important' ], 'left
 ok(!get_mark_for_window_on_workspace($tmp, $second), 'second containr no longer has the mark');
 
 ##############################################################
-# 8: try to mark two cons with the same mark and check that
+# 9: try to mark two cons with the same mark and check that
 #    it fails
 ##############################################################
 
index d6d86e2343265db607b7d2fb192edf29d7d6ae1f..925e39db656c126e7cecc10115e256a06a054072 100644 (file)
@@ -38,8 +38,8 @@ sub get_mark_for_window_on_workspace {
 
 $ws = fresh_workspace;
 $con = open_window;
-cmd 'mark A';
-cmd 'mark B';
+cmd 'mark --add A';
+cmd 'mark --add B';
 
 is_deeply(sort(get_marks()), [ 'A', 'B' ], 'both marks exist');
 is_deeply(get_mark_for_window_on_workspace($ws, $con), [ 'A', 'B' ], 'both marks are on the same window');
@@ -54,9 +54,9 @@ $ws = fresh_workspace;
 $con = open_window;
 cmd 'mark A';
 
-cmd 'mark --toggle B';
+cmd 'mark --add --toggle B';
 is_deeply(get_mark_for_window_on_workspace($ws, $con), [ 'A', 'B' ], 'both marks are on the same window');
-cmd 'mark --toggle B';
+cmd 'mark --add --toggle B';
 is_deeply(get_mark_for_window_on_workspace($ws, $con), [ 'A' ], 'only mark B has been removed');
 
 cmd 'unmark';
@@ -67,9 +67,9 @@ cmd 'unmark';
 
 $ws = fresh_workspace;
 $con = open_window;
-cmd 'mark A';
-cmd 'mark B';
-cmd 'mark C';
+cmd 'mark --add A';
+cmd 'mark --add B';
+cmd 'mark --add C';
 
 cmd 'unmark B';
 is_deeply(get_mark_for_window_on_workspace($ws, $con), [ 'A', 'C' ], 'only mark B has been removed');
@@ -82,11 +82,11 @@ cmd 'unmark';
 
 $ws = fresh_workspace;
 $con = open_window;
-cmd 'mark A';
-cmd 'mark B';
+cmd 'mark --add A';
+cmd 'mark --add B';
 open_window;
 
-cmd '[con_mark=B] mark C';
+cmd '[con_mark=B] mark --add C';
 is_deeply(get_mark_for_window_on_workspace($ws, $con), [ 'A', 'B', 'C' ], 'matching on a mark works with multiple marks');
 
 cmd 'unmark';