From eb53ec83b91f097914fdf4cbba433a14e9f5ff3d Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Wed, 7 Nov 2018 01:06:20 +0200 Subject: [PATCH] load_layout: Correctly mark non-leaf containers Example problematic layout: { "layout": "splith", "marks": ["H1"], "nodes": [ { "swallows": [ { "class": "^a$" } ] } ] } Since the marks were added to the json_node during end_map, the container that ended up getting the "H1" mark was the child instead of the parent. --- src/load_layout.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/load_layout.c b/src/load_layout.c index 5a340d2c..b4d2a688 100644 --- a/src/load_layout.c +++ b/src/load_layout.c @@ -31,7 +31,15 @@ static bool parsing_marks; struct Match *current_swallow; static bool swallow_is_empty; static int num_marks; -static char **marks; +/* We need to save each container that needs to be marked if we want to support + * marking non-leaf containers. In their case, the end_map for their children is + * called before their own end_map, so marking json_node would end up marking + * the latest child. We can't just mark containers immediately after we parse a + * mark because of #2511. */ +struct pending_marks { + char *mark; + Con *con_to_be_marked; +} * marks; /* This list is used for reordering the focus stack after parsing the 'focus' * array. */ @@ -149,8 +157,10 @@ static int json_end_map(void *ctx) { if (num_marks > 0) { for (int i = 0; i < num_marks; i++) { - con_mark(json_node, marks[i], MM_ADD); - free(marks[i]); + Con *con = marks[i].con_to_be_marked; + char *mark = marks[i].mark; + con_mark(con, mark, MM_ADD); + free(mark); } FREE(marks); @@ -274,8 +284,9 @@ static int json_string(void *ctx, const unsigned char *val, size_t len) { char *mark; sasprintf(&mark, "%.*s", (int)len, val); - marks = srealloc(marks, (++num_marks) * sizeof(char *)); - marks[num_marks - 1] = sstrdup(mark); + marks = srealloc(marks, (++num_marks) * sizeof(struct pending_marks)); + marks[num_marks - 1].mark = sstrdup(mark); + marks[num_marks - 1].con_to_be_marked = json_node; } else { if (strcasecmp(last_key, "name") == 0) { json_node->name = scalloc(len + 1, 1);