]> git.sur5r.net Git - i3/i3/blob - src/load_layout.c
Set marks to NULL after freeing
[i3/i3] / src / load_layout.c
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
6  *
7  * load_layout.c: Restore (parts of) the layout, for example after an inplace
8  *                restart.
9  *
10  */
11 #include "all.h"
12
13 #include <yajl/yajl_common.h>
14 #include <yajl/yajl_gen.h>
15 #include <yajl/yajl_parse.h>
16 #include <yajl/yajl_version.h>
17
18 /* TODO: refactor the whole parsing thing */
19
20 static char *last_key;
21 static Con *json_node;
22 static Con *to_focus;
23 static bool parsing_swallows;
24 static bool parsing_rect;
25 static bool parsing_deco_rect;
26 static bool parsing_window_rect;
27 static bool parsing_geometry;
28 static bool parsing_focus;
29 static bool parsing_marks;
30 struct Match *current_swallow;
31 static bool swallow_is_empty;
32 static int num_marks;
33 static char **marks;
34
35 /* This list is used for reordering the focus stack after parsing the 'focus'
36  * array. */
37 struct focus_mapping {
38     int old_id;
39
40     TAILQ_ENTRY(focus_mapping)
41     focus_mappings;
42 };
43
44 static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings =
45     TAILQ_HEAD_INITIALIZER(focus_mappings);
46
47 static int json_start_map(void *ctx) {
48     LOG("start of map, last_key = %s\n", last_key);
49     if (parsing_swallows) {
50         LOG("creating new swallow\n");
51         current_swallow = smalloc(sizeof(Match));
52         match_init(current_swallow);
53         current_swallow->dock = M_DONTCHECK;
54         TAILQ_INSERT_TAIL(&(json_node->swallow_head), current_swallow, matches);
55         swallow_is_empty = true;
56     } else {
57         if (!parsing_rect && !parsing_deco_rect && !parsing_window_rect && !parsing_geometry) {
58             if (last_key && strcasecmp(last_key, "floating_nodes") == 0) {
59                 DLOG("New floating_node\n");
60                 Con *ws = con_get_workspace(json_node);
61                 json_node = con_new_skeleton(NULL, NULL);
62                 json_node->name = NULL;
63                 json_node->parent = ws;
64                 DLOG("Parent is workspace = %p\n", ws);
65             } else {
66                 Con *parent = json_node;
67                 json_node = con_new_skeleton(NULL, NULL);
68                 json_node->name = NULL;
69                 json_node->parent = parent;
70             }
71         }
72     }
73     return 1;
74 }
75
76 static int json_end_map(void *ctx) {
77     LOG("end of map\n");
78     if (!parsing_swallows && !parsing_rect && !parsing_deco_rect && !parsing_window_rect && !parsing_geometry) {
79         /* Set a few default values to simplify manually crafted layout files. */
80         if (json_node->layout == L_DEFAULT) {
81             DLOG("Setting layout = L_SPLITH\n");
82             json_node->layout = L_SPLITH;
83         }
84
85         /* Sanity check: swallow criteria don’t make any sense on a split
86          * container. */
87         if (con_is_split(json_node) > 0 && !TAILQ_EMPTY(&(json_node->swallow_head))) {
88             DLOG("sanity check: removing swallows specification from split container\n");
89             while (!TAILQ_EMPTY(&(json_node->swallow_head))) {
90                 Match *match = TAILQ_FIRST(&(json_node->swallow_head));
91                 TAILQ_REMOVE(&(json_node->swallow_head), match, matches);
92                 match_free(match);
93                 free(match);
94             }
95         }
96
97         if (json_node->type == CT_WORKSPACE) {
98             /* Ensure the workspace has a name. */
99             DLOG("Attaching workspace. name = %s\n", json_node->name);
100             if (json_node->name == NULL || strcmp(json_node->name, "") == 0) {
101                 json_node->name = sstrdup("unnamed");
102             }
103
104             /* Prevent name clashes when appending a workspace, e.g. when the
105              * user tries to restore a workspace called “1” but already has a
106              * workspace called “1”. */
107             Con *output;
108             Con *workspace = NULL;
109             TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
110             GREP_FIRST(workspace, output_get_content(output), !strcasecmp(child->name, json_node->name));
111             char *base = sstrdup(json_node->name);
112             int cnt = 1;
113             while (workspace != NULL) {
114                 FREE(json_node->name);
115                 sasprintf(&(json_node->name), "%s_%d", base, cnt++);
116                 workspace = NULL;
117                 TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
118                 GREP_FIRST(workspace, output_get_content(output), !strcasecmp(child->name, json_node->name));
119             }
120             free(base);
121
122             /* Set num accordingly so that i3bar will properly sort it. */
123             json_node->num = ws_name_to_number(json_node->name);
124         }
125
126         // When appending JSON layout files that only contain the workspace
127         // _contents_, we might not have an upfront signal that the
128         // container we’re currently parsing is a floating container (like
129         // the “floating_nodes” key of the workspace container itself).
130         // That’s why we make sure the con is attached at the right place
131         // in the hierarchy in case it’s floating.
132         if (json_node->type == CT_FLOATING_CON) {
133             DLOG("fixing parent which currently is %p / %s\n", json_node->parent, json_node->parent->name);
134             json_node->parent = con_get_workspace(json_node->parent);
135
136             // Also set a size if none was supplied, otherwise the placeholder
137             // window cannot be created as X11 requests with width=0 or
138             // height=0 are invalid.
139             const Rect zero = {0, 0, 0, 0};
140             if (memcmp(&(json_node->rect), &zero, sizeof(Rect)) == 0) {
141                 DLOG("Geometry not set, combining children\n");
142                 Con *child;
143                 TAILQ_FOREACH(child, &(json_node->nodes_head), nodes) {
144                     DLOG("child geometry: %d x %d\n", child->geometry.width, child->geometry.height);
145                     json_node->rect.width += child->geometry.width;
146                     json_node->rect.height = max(json_node->rect.height, child->geometry.height);
147                 }
148             }
149
150             floating_check_size(json_node);
151         }
152
153         if (num_marks > 0) {
154             for (int i = 0; i < num_marks; i++) {
155                 con_mark(json_node, marks[i], MM_ADD);
156                 free(marks[i]);
157             }
158
159             free(marks);
160             marks = NULL;
161             num_marks = 0;
162         }
163
164         LOG("attaching\n");
165         con_attach(json_node, json_node->parent, true);
166         LOG("Creating window\n");
167         x_con_init(json_node);
168         json_node = json_node->parent;
169     }
170
171     if (parsing_swallows && swallow_is_empty) {
172         /* We parsed an empty swallow definition. This is an invalid layout
173          * definition, hence we reject it. */
174         ELOG("Layout file is invalid: found an empty swallow definition.\n");
175         return 0;
176     }
177
178     parsing_rect = false;
179     parsing_deco_rect = false;
180     parsing_window_rect = false;
181     parsing_geometry = false;
182     return 1;
183 }
184
185 static int json_end_array(void *ctx) {
186     LOG("end of array\n");
187     if (!parsing_swallows && !parsing_focus && !parsing_marks) {
188         con_fix_percent(json_node);
189     }
190     if (parsing_swallows) {
191         parsing_swallows = false;
192     }
193     if (parsing_marks) {
194         parsing_marks = false;
195     }
196
197     if (parsing_focus) {
198         /* Clear the list of focus mappings */
199         struct focus_mapping *mapping;
200         TAILQ_FOREACH_REVERSE(mapping, &focus_mappings, focus_mappings_head, focus_mappings) {
201             LOG("focus (reverse) %d\n", mapping->old_id);
202             Con *con;
203             TAILQ_FOREACH(con, &(json_node->focus_head), focused) {
204                 if (con->old_id != mapping->old_id)
205                     continue;
206                 LOG("got it! %p\n", con);
207                 /* Move this entry to the top of the focus list. */
208                 TAILQ_REMOVE(&(json_node->focus_head), con, focused);
209                 TAILQ_INSERT_HEAD(&(json_node->focus_head), con, focused);
210                 break;
211             }
212         }
213         while (!TAILQ_EMPTY(&focus_mappings)) {
214             mapping = TAILQ_FIRST(&focus_mappings);
215             TAILQ_REMOVE(&focus_mappings, mapping, focus_mappings);
216             free(mapping);
217         }
218         parsing_focus = false;
219     }
220     return 1;
221 }
222
223 static int json_key(void *ctx, const unsigned char *val, size_t len) {
224     LOG("key: %.*s\n", (int)len, val);
225     FREE(last_key);
226     last_key = scalloc(len + 1, 1);
227     memcpy(last_key, val, len);
228     if (strcasecmp(last_key, "swallows") == 0)
229         parsing_swallows = true;
230
231     if (strcasecmp(last_key, "rect") == 0)
232         parsing_rect = true;
233
234     if (strcasecmp(last_key, "deco_rect") == 0)
235         parsing_deco_rect = true;
236
237     if (strcasecmp(last_key, "window_rect") == 0)
238         parsing_window_rect = true;
239
240     if (strcasecmp(last_key, "geometry") == 0)
241         parsing_geometry = true;
242
243     if (strcasecmp(last_key, "focus") == 0)
244         parsing_focus = true;
245
246     if (strcasecmp(last_key, "marks") == 0) {
247         num_marks = 0;
248         parsing_marks = true;
249     }
250
251     return 1;
252 }
253
254 static int json_string(void *ctx, const unsigned char *val, size_t len) {
255     LOG("string: %.*s for key %s\n", (int)len, val, last_key);
256     if (parsing_swallows) {
257         char *sval;
258         sasprintf(&sval, "%.*s", len, val);
259         if (strcasecmp(last_key, "class") == 0) {
260             current_swallow->class = regex_new(sval);
261             swallow_is_empty = false;
262         } else if (strcasecmp(last_key, "instance") == 0) {
263             current_swallow->instance = regex_new(sval);
264             swallow_is_empty = false;
265         } else if (strcasecmp(last_key, "window_role") == 0) {
266             current_swallow->window_role = regex_new(sval);
267             swallow_is_empty = false;
268         } else if (strcasecmp(last_key, "title") == 0) {
269             current_swallow->title = regex_new(sval);
270             swallow_is_empty = false;
271         } else {
272             ELOG("swallow key %s unknown\n", last_key);
273         }
274         free(sval);
275     } else if (parsing_marks) {
276         char *mark;
277         sasprintf(&mark, "%.*s", (int)len, val);
278
279         marks = srealloc(marks, (++num_marks) * sizeof(char *));
280         marks[num_marks - 1] = sstrdup(mark);
281     } else {
282         if (strcasecmp(last_key, "name") == 0) {
283             json_node->name = scalloc(len + 1, 1);
284             memcpy(json_node->name, val, len);
285         } else if (strcasecmp(last_key, "title_format") == 0) {
286             json_node->title_format = scalloc(len + 1, 1);
287             memcpy(json_node->title_format, val, len);
288         } else if (strcasecmp(last_key, "sticky_group") == 0) {
289             json_node->sticky_group = scalloc(len + 1, 1);
290             memcpy(json_node->sticky_group, val, len);
291             LOG("sticky_group of this container is %s\n", json_node->sticky_group);
292         } else if (strcasecmp(last_key, "orientation") == 0) {
293             /* Upgrade path from older versions of i3 (doing an inplace restart
294              * to a newer version):
295              * "orientation" is dumped before "layout". Therefore, we store
296              * whether the orientation was horizontal or vertical in the
297              * last_split_layout. When we then encounter layout == "default",
298              * we will use the last_split_layout as layout instead. */
299             char *buf = NULL;
300             sasprintf(&buf, "%.*s", (int)len, val);
301             if (strcasecmp(buf, "none") == 0 ||
302                 strcasecmp(buf, "horizontal") == 0)
303                 json_node->last_split_layout = L_SPLITH;
304             else if (strcasecmp(buf, "vertical") == 0)
305                 json_node->last_split_layout = L_SPLITV;
306             else
307                 LOG("Unhandled orientation: %s\n", buf);
308             free(buf);
309         } else if (strcasecmp(last_key, "border") == 0) {
310             char *buf = NULL;
311             sasprintf(&buf, "%.*s", (int)len, val);
312             if (strcasecmp(buf, "none") == 0)
313                 json_node->border_style = BS_NONE;
314             else if (strcasecmp(buf, "1pixel") == 0) {
315                 json_node->border_style = BS_PIXEL;
316                 json_node->current_border_width = 1;
317             } else if (strcasecmp(buf, "pixel") == 0)
318                 json_node->border_style = BS_PIXEL;
319             else if (strcasecmp(buf, "normal") == 0)
320                 json_node->border_style = BS_NORMAL;
321             else
322                 LOG("Unhandled \"border\": %s\n", buf);
323             free(buf);
324         } else if (strcasecmp(last_key, "type") == 0) {
325             char *buf = NULL;
326             sasprintf(&buf, "%.*s", (int)len, val);
327             if (strcasecmp(buf, "root") == 0)
328                 json_node->type = CT_ROOT;
329             else if (strcasecmp(buf, "output") == 0)
330                 json_node->type = CT_OUTPUT;
331             else if (strcasecmp(buf, "con") == 0)
332                 json_node->type = CT_CON;
333             else if (strcasecmp(buf, "floating_con") == 0)
334                 json_node->type = CT_FLOATING_CON;
335             else if (strcasecmp(buf, "workspace") == 0)
336                 json_node->type = CT_WORKSPACE;
337             else if (strcasecmp(buf, "dockarea") == 0)
338                 json_node->type = CT_DOCKAREA;
339             else
340                 LOG("Unhandled \"type\": %s\n", buf);
341             free(buf);
342         } else if (strcasecmp(last_key, "layout") == 0) {
343             char *buf = NULL;
344             sasprintf(&buf, "%.*s", (int)len, val);
345             if (strcasecmp(buf, "default") == 0)
346                 /* This set above when we read "orientation". */
347                 json_node->layout = json_node->last_split_layout;
348             else if (strcasecmp(buf, "stacked") == 0)
349                 json_node->layout = L_STACKED;
350             else if (strcasecmp(buf, "tabbed") == 0)
351                 json_node->layout = L_TABBED;
352             else if (strcasecmp(buf, "dockarea") == 0)
353                 json_node->layout = L_DOCKAREA;
354             else if (strcasecmp(buf, "output") == 0)
355                 json_node->layout = L_OUTPUT;
356             else if (strcasecmp(buf, "splith") == 0)
357                 json_node->layout = L_SPLITH;
358             else if (strcasecmp(buf, "splitv") == 0)
359                 json_node->layout = L_SPLITV;
360             else
361                 LOG("Unhandled \"layout\": %s\n", buf);
362             free(buf);
363         } else if (strcasecmp(last_key, "workspace_layout") == 0) {
364             char *buf = NULL;
365             sasprintf(&buf, "%.*s", (int)len, val);
366             if (strcasecmp(buf, "default") == 0)
367                 json_node->workspace_layout = L_DEFAULT;
368             else if (strcasecmp(buf, "stacked") == 0)
369                 json_node->workspace_layout = L_STACKED;
370             else if (strcasecmp(buf, "tabbed") == 0)
371                 json_node->workspace_layout = L_TABBED;
372             else
373                 LOG("Unhandled \"workspace_layout\": %s\n", buf);
374             free(buf);
375         } else if (strcasecmp(last_key, "last_split_layout") == 0) {
376             char *buf = NULL;
377             sasprintf(&buf, "%.*s", (int)len, val);
378             if (strcasecmp(buf, "splith") == 0)
379                 json_node->last_split_layout = L_SPLITH;
380             else if (strcasecmp(buf, "splitv") == 0)
381                 json_node->last_split_layout = L_SPLITV;
382             else
383                 LOG("Unhandled \"last_splitlayout\": %s\n", buf);
384             free(buf);
385         } else if (strcasecmp(last_key, "mark") == 0) {
386             DLOG("Found deprecated key \"mark\".\n");
387
388             char *buf = NULL;
389             sasprintf(&buf, "%.*s", (int)len, val);
390
391             con_mark(json_node, buf, MM_REPLACE);
392         } else if (strcasecmp(last_key, "floating") == 0) {
393             char *buf = NULL;
394             sasprintf(&buf, "%.*s", (int)len, val);
395             if (strcasecmp(buf, "auto_off") == 0)
396                 json_node->floating = FLOATING_AUTO_OFF;
397             else if (strcasecmp(buf, "auto_on") == 0)
398                 json_node->floating = FLOATING_AUTO_ON;
399             else if (strcasecmp(buf, "user_off") == 0)
400                 json_node->floating = FLOATING_USER_OFF;
401             else if (strcasecmp(buf, "user_on") == 0)
402                 json_node->floating = FLOATING_USER_ON;
403             free(buf);
404         } else if (strcasecmp(last_key, "scratchpad_state") == 0) {
405             char *buf = NULL;
406             sasprintf(&buf, "%.*s", (int)len, val);
407             if (strcasecmp(buf, "none") == 0)
408                 json_node->scratchpad_state = SCRATCHPAD_NONE;
409             else if (strcasecmp(buf, "fresh") == 0)
410                 json_node->scratchpad_state = SCRATCHPAD_FRESH;
411             else if (strcasecmp(buf, "changed") == 0)
412                 json_node->scratchpad_state = SCRATCHPAD_CHANGED;
413             free(buf);
414         }
415     }
416     return 1;
417 }
418
419 static int json_int(void *ctx, long long val) {
420     LOG("int %lld for key %s\n", val, last_key);
421     /* For backwards compatibility with i3 < 4.8 */
422     if (strcasecmp(last_key, "type") == 0)
423         json_node->type = val;
424
425     if (strcasecmp(last_key, "fullscreen_mode") == 0)
426         json_node->fullscreen_mode = val;
427
428     if (strcasecmp(last_key, "num") == 0)
429         json_node->num = val;
430
431     if (strcasecmp(last_key, "current_border_width") == 0)
432         json_node->current_border_width = val;
433
434     if (strcasecmp(last_key, "depth") == 0)
435         json_node->depth = val;
436
437     if (!parsing_swallows && strcasecmp(last_key, "id") == 0)
438         json_node->old_id = val;
439
440     if (parsing_focus) {
441         struct focus_mapping *focus_mapping = scalloc(1, sizeof(struct focus_mapping));
442         focus_mapping->old_id = val;
443         TAILQ_INSERT_TAIL(&focus_mappings, focus_mapping, focus_mappings);
444     }
445
446     if (parsing_rect || parsing_window_rect || parsing_geometry) {
447         Rect *r;
448         if (parsing_rect)
449             r = &(json_node->rect);
450         else if (parsing_window_rect)
451             r = &(json_node->window_rect);
452         else
453             r = &(json_node->geometry);
454         if (strcasecmp(last_key, "x") == 0)
455             r->x = val;
456         else if (strcasecmp(last_key, "y") == 0)
457             r->y = val;
458         else if (strcasecmp(last_key, "width") == 0)
459             r->width = val;
460         else if (strcasecmp(last_key, "height") == 0)
461             r->height = val;
462         else
463             ELOG("WARNING: unknown key %s in rect\n", last_key);
464         DLOG("rect now: (%d, %d, %d, %d)\n",
465              r->x, r->y, r->width, r->height);
466     }
467     if (parsing_swallows) {
468         if (strcasecmp(last_key, "id") == 0) {
469             current_swallow->id = val;
470             swallow_is_empty = false;
471         }
472         if (strcasecmp(last_key, "dock") == 0) {
473             current_swallow->dock = val;
474             swallow_is_empty = false;
475         }
476         if (strcasecmp(last_key, "insert_where") == 0) {
477             current_swallow->insert_where = val;
478             swallow_is_empty = false;
479         }
480     }
481
482     return 1;
483 }
484
485 static int json_bool(void *ctx, int val) {
486     LOG("bool %d for key %s\n", val, last_key);
487     if (strcasecmp(last_key, "focused") == 0 && val) {
488         to_focus = json_node;
489     }
490
491     if (strcasecmp(last_key, "sticky") == 0)
492         json_node->sticky = val;
493
494     if (parsing_swallows) {
495         if (strcasecmp(last_key, "restart_mode") == 0) {
496             current_swallow->restart_mode = val;
497             swallow_is_empty = false;
498         }
499     }
500
501     return 1;
502 }
503
504 static int json_double(void *ctx, double val) {
505     LOG("double %f for key %s\n", val, last_key);
506     if (strcasecmp(last_key, "percent") == 0) {
507         json_node->percent = val;
508     }
509     return 1;
510 }
511
512 static json_content_t content_result;
513 static int content_level;
514
515 static int json_determine_content_deeper(void *ctx) {
516     content_level++;
517     return 1;
518 }
519
520 static int json_determine_content_shallower(void *ctx) {
521     content_level--;
522     return 1;
523 }
524
525 static int json_determine_content_string(void *ctx, const unsigned char *val, size_t len) {
526     if (strcasecmp(last_key, "type") != 0 || content_level > 1)
527         return 1;
528
529     DLOG("string = %.*s, last_key = %s\n", (int)len, val, last_key);
530     if (strncasecmp((const char *)val, "workspace", len) == 0)
531         content_result = JSON_CONTENT_WORKSPACE;
532     return 0;
533 }
534
535 /* Parses the given JSON file until it encounters the first “type” property to
536  * determine whether the file contains workspaces or regular containers, which
537  * is important to know when deciding where (and how) to append the contents.
538  * */
539 json_content_t json_determine_content(const char *filename) {
540     FILE *f;
541     if ((f = fopen(filename, "r")) == NULL) {
542         ELOG("Cannot open file \"%s\"\n", filename);
543         return JSON_CONTENT_UNKNOWN;
544     }
545     struct stat stbuf;
546     if (fstat(fileno(f), &stbuf) != 0) {
547         ELOG("Cannot fstat() \"%s\"\n", filename);
548         fclose(f);
549         return JSON_CONTENT_UNKNOWN;
550     }
551     char *buf = smalloc(stbuf.st_size);
552     int n = fread(buf, 1, stbuf.st_size, f);
553     if (n != stbuf.st_size) {
554         ELOG("File \"%s\" could not be read entirely, not loading.\n", filename);
555         fclose(f);
556         return JSON_CONTENT_UNKNOWN;
557     }
558     DLOG("read %d bytes\n", n);
559     // We default to JSON_CONTENT_CON because it is legal to not include
560     // “"type": "con"” in the JSON files for better readability.
561     content_result = JSON_CONTENT_CON;
562     content_level = 0;
563     yajl_gen g;
564     yajl_handle hand;
565     static yajl_callbacks callbacks = {
566         .yajl_string = json_determine_content_string,
567         .yajl_map_key = json_key,
568         .yajl_start_array = json_determine_content_deeper,
569         .yajl_start_map = json_determine_content_deeper,
570         .yajl_end_map = json_determine_content_shallower,
571         .yajl_end_array = json_determine_content_shallower,
572     };
573     g = yajl_gen_alloc(NULL);
574     hand = yajl_alloc(&callbacks, NULL, (void *)g);
575     /* Allowing comments allows for more user-friendly layout files. */
576     yajl_config(hand, yajl_allow_comments, true);
577     /* Allow multiple values, i.e. multiple nodes to attach */
578     yajl_config(hand, yajl_allow_multiple_values, true);
579     yajl_status stat;
580     setlocale(LC_NUMERIC, "C");
581     stat = yajl_parse(hand, (const unsigned char *)buf, n);
582     if (stat != yajl_status_ok && stat != yajl_status_client_canceled) {
583         unsigned char *str = yajl_get_error(hand, 1, (const unsigned char *)buf, n);
584         ELOG("JSON parsing error: %s\n", str);
585         yajl_free_error(hand, str);
586     }
587
588     setlocale(LC_NUMERIC, "");
589     yajl_complete_parse(hand);
590
591     fclose(f);
592
593     return content_result;
594 }
595
596 void tree_append_json(Con *con, const char *filename, char **errormsg) {
597     FILE *f;
598     if ((f = fopen(filename, "r")) == NULL) {
599         ELOG("Cannot open file \"%s\"\n", filename);
600         return;
601     }
602     struct stat stbuf;
603     if (fstat(fileno(f), &stbuf) != 0) {
604         ELOG("Cannot fstat() \"%s\"\n", filename);
605         fclose(f);
606         return;
607     }
608     char *buf = smalloc(stbuf.st_size);
609     int n = fread(buf, 1, stbuf.st_size, f);
610     if (n != stbuf.st_size) {
611         ELOG("File \"%s\" could not be read entirely, not loading.\n", filename);
612         fclose(f);
613         return;
614     }
615     DLOG("read %d bytes\n", n);
616     yajl_gen g;
617     yajl_handle hand;
618     static yajl_callbacks callbacks = {
619         .yajl_boolean = json_bool,
620         .yajl_integer = json_int,
621         .yajl_double = json_double,
622         .yajl_string = json_string,
623         .yajl_start_map = json_start_map,
624         .yajl_map_key = json_key,
625         .yajl_end_map = json_end_map,
626         .yajl_end_array = json_end_array,
627     };
628     g = yajl_gen_alloc(NULL);
629     hand = yajl_alloc(&callbacks, NULL, (void *)g);
630     /* Allowing comments allows for more user-friendly layout files. */
631     yajl_config(hand, yajl_allow_comments, true);
632     /* Allow multiple values, i.e. multiple nodes to attach */
633     yajl_config(hand, yajl_allow_multiple_values, true);
634     yajl_status stat;
635     json_node = con;
636     to_focus = NULL;
637     parsing_swallows = false;
638     parsing_rect = false;
639     parsing_deco_rect = false;
640     parsing_window_rect = false;
641     parsing_geometry = false;
642     parsing_focus = false;
643     parsing_marks = false;
644     setlocale(LC_NUMERIC, "C");
645     stat = yajl_parse(hand, (const unsigned char *)buf, n);
646     if (stat != yajl_status_ok) {
647         unsigned char *str = yajl_get_error(hand, 1, (const unsigned char *)buf, n);
648         ELOG("JSON parsing error: %s\n", str);
649         if (errormsg != NULL)
650             *errormsg = sstrdup((const char *)str);
651         yajl_free_error(hand, str);
652     }
653
654     /* In case not all containers were restored, we need to fix the
655      * percentages, otherwise i3 will crash immediately when rendering the
656      * next time. */
657     con_fix_percent(con);
658
659     setlocale(LC_NUMERIC, "");
660     yajl_complete_parse(hand);
661     yajl_free(hand);
662     yajl_gen_free(g);
663
664     fclose(f);
665     free(buf);
666     if (to_focus)
667         con_focus(to_focus);
668 }