+node_t *restore_node(jsmntok_t **t, char *json)
+{
+ if ((*t)->type == JSMN_PRIMITIVE) {
+ (*t)++;
+ return NULL;
+ } else {
+ int s = (*t)->size;
+ (*t)++;
+ /* hack to prevent a new ID from being generated */
+ node_t *n = make_node(UINT32_MAX);
+
+ for (int i = 0; i < s; i++) {
+ if (keyeq("id", *t, json)) {
+ (*t)++;
+ sscanf(json + (*t)->start, "%u", &n->id);
+ RESTORE_ANY(splitType, &n->split_type, parse_split_type)
+ RESTORE_DOUBLE(splitRatio, &n->split_ratio)
+ RESTORE_INT(birthRotation, &n->birth_rotation)
+ RESTORE_BOOL(vacant, &n->vacant)
+ RESTORE_BOOL(sticky, &n->sticky)
+ RESTORE_BOOL(private, &n->private)
+ RESTORE_BOOL(locked, &n->locked)
+ } else if (keyeq("presel", *t, json)) {
+ (*t)++;
+ n->presel = restore_presel(t, json);
+ continue;
+ } else if (keyeq("rectangle", *t, json)) {
+ (*t)++;
+ restore_rectangle(&n->rectangle, t, json);
+ continue;
+ } else if (keyeq("firstChild", *t, json)) {
+ (*t)++;
+ node_t *fc = restore_node(t, json);
+ n->first_child = fc;
+ if (fc != NULL) {
+ fc->parent = n;
+ }
+ continue;
+ } else if (keyeq("secondChild", *t, json)) {
+ (*t)++;
+ node_t *sc = restore_node(t, json);
+ n->second_child = sc;
+ if (sc != NULL) {
+ sc->parent = n;
+ }
+ continue;
+ } else if (keyeq("client", *t, json)) {
+ (*t)++;
+ n->client = restore_client(t, json);
+ continue;
+ } else {
+ warn("Restore node: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
+ (*t)++;
+ }
+ (*t)++;
+ }
+
+ return n;
+ }
+}
+
+presel_t *restore_presel(jsmntok_t **t, char *json)
+{
+ if ((*t)->type == JSMN_PRIMITIVE) {
+ (*t)++;
+ return NULL;
+ } else {
+ int s = (*t)->size;
+ (*t)++;
+ presel_t *p = make_presel();
+
+ for (int i = 0; i < s; i++) {
+ if (keyeq("splitRatio", *t, json)) {
+ (*t)++;
+ sscanf(json + (*t)->start, "%lf", &p->split_ratio);
+ RESTORE_ANY(splitDir, &p->split_dir, parse_direction)
+ }
+
+ (*t)++;
+ }
+
+ return p;
+ }
+}
+
+
+client_t *restore_client(jsmntok_t **t, char *json)
+{
+ if ((*t)->type == JSMN_PRIMITIVE) {
+ (*t)++;
+ return NULL;
+ } else {
+ int s = (*t)->size;
+ (*t)++;
+ client_t *c = make_client();
+
+ for (int i = 0; i < s; i++) {
+ if (keyeq("className", *t, json)) {
+ (*t)++;
+ snprintf(c->class_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
+ } else if (keyeq("instanceName", *t, json)) {
+ (*t)++;
+ snprintf(c->instance_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
+ RESTORE_ANY(state, &c->state, parse_client_state)
+ RESTORE_ANY(lastState, &c->last_state, parse_client_state)
+ RESTORE_ANY(layer, &c->layer, parse_stack_layer)
+ RESTORE_ANY(lastLayer, &c->last_layer, parse_stack_layer)
+ RESTORE_UINT(borderWidth, &c->border_width)
+ RESTORE_BOOL(urgent, &c->urgent)
+ RESTORE_BOOL(visible, &c->visible)
+ RESTORE_BOOL(icccmFocus, &c->icccm_focus)
+ RESTORE_BOOL(icccmInput, &c->icccm_input)
+ RESTORE_USINT(minWidth, &c->min_width)
+ RESTORE_USINT(maxWidth, &c->max_width)
+ RESTORE_USINT(minHeight, &c->min_height)
+ RESTORE_USINT(maxHeight, &c->max_height)
+ RESTORE_INT(wmStatesCount, &c->wm_states_count)
+ } else if (keyeq("wmState", *t, json)) {
+ (*t)++;
+ restore_wm_state(c->wm_state, t, json);
+ continue;
+ } else if (keyeq("tiledRectangle", *t, json)) {
+ (*t)++;
+ restore_rectangle(&c->tiled_rectangle, t, json);
+ continue;
+ } else if (keyeq("floatingRectangle", *t, json)) {
+ (*t)++;
+ restore_rectangle(&c->floating_rectangle, t, json);
+ continue;
+ } else {
+ warn("Restore client: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
+ (*t)++;
+ }
+
+ (*t)++;
+ }
+
+ return c;
+ }
+}
+
+void restore_rectangle(xcb_rectangle_t *r, jsmntok_t **t, char *json)
+{
+ int s = (*t)->size;
+ (*t)++;
+
+ for (int i = 0; i < s; i++) {
+ if (keyeq("x", *t, json)) {
+ (*t)++;
+ sscanf(json + (*t)->start, "%hi", &r->x);
+ } else if (keyeq("y", *t, json)) {
+ (*t)++;
+ sscanf(json + (*t)->start, "%hi", &r->y);
+ } else if (keyeq("width", *t, json)) {
+ (*t)++;
+ sscanf(json + (*t)->start, "%hu", &r->width);
+ } else if (keyeq("height", *t, json)) {
+ (*t)++;
+ sscanf(json + (*t)->start, "%hu", &r->height);
+ }
+ (*t)++;
+ }
+}
+
+void restore_padding(padding_t *p, jsmntok_t **t, char *json)
+{
+ int s = (*t)->size;
+ (*t)++;
+
+ for (int i = 0; i < s; i++) {
+ if (keyeq("top", *t, json)) {
+ (*t)++;
+ sscanf(json + (*t)->start, "%i", &p->top);
+ } else if (keyeq("right", *t, json)) {
+ (*t)++;
+ sscanf(json + (*t)->start, "%i", &p->right);
+ } else if (keyeq("bottom", *t, json)) {
+ (*t)++;
+ sscanf(json + (*t)->start, "%i", &p->bottom);
+ } else if (keyeq("left", *t, json)) {
+ (*t)++;
+ sscanf(json + (*t)->start, "%i", &p->left);
+ }
+ (*t)++;
+ }
+}
+
+void restore_history(jsmntok_t **t, char *json)
+{
+ int s = (*t)->size;
+ (*t)++;
+
+ for (int i = 0; i < s; i++) {
+ coordinates_t loc = {NULL, NULL, NULL};
+ restore_coordinates(&loc, t, json);
+ if (loc.monitor != NULL && loc.desktop != NULL) {
+ history_add(loc.monitor, loc.desktop, loc.node);
+ }
+ }
+}
+
+void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json)
+{
+ int s = (*t)->size;
+ (*t)++;
+
+ for (int i = 0; i < s; i++) {
+ if (keyeq("monitorName", *t, json)) {
+ (*t)++;
+ char *name = copy_string(json + (*t)->start, (*t)->end - (*t)->start);
+ loc->monitor = find_monitor(name);
+ free(name);
+ } else if (keyeq("desktopName", *t, json)) {
+ (*t)++;
+ char *name = copy_string(json + (*t)->start, (*t)->end - (*t)->start);
+ loc->desktop = find_desktop_in(name, loc->monitor);
+ free(name);
+ } else if (keyeq("nodeId", *t, json)) {
+ (*t)++;
+ uint32_t id;
+ sscanf(json + (*t)->start, "%u", &id);
+ loc->node = find_by_id_in(loc->desktop!=NULL?loc->desktop->root:NULL, id);
+ }
+ (*t)++;
+ }
+}
+
+void restore_stack(jsmntok_t **t, char *json)
+{
+ int s = (*t)->size;
+ (*t)++;
+
+ for (int i = 0; i < s; i++) {
+ uint32_t id;
+ sscanf(json + (*t)->start, "%u", &id);
+ coordinates_t loc;
+ if (locate_window(id, &loc)) {
+ stack_insert_after(stack_tail, loc.node);
+ }
+ (*t)++;
+ }
+}
+
+void restore_wm_state(xcb_atom_t *w, jsmntok_t **t, char *json)
+{
+ int s = (*t)->size;
+ (*t)++;
+
+ for (int i = 0; i < s; i++) {
+ sscanf(json + (*t)->start, "%u", &w[i]);
+ (*t)++;
+ }
+}
+
+#undef RESTORE_INT
+#undef RESTORE_UINT
+#undef RESTORE_USINT
+#undef RESTORE_DOUBLE
+#undef RESTORE_ANY
+#undef RESTORE_BOOL
+
+bool keyeq(char *s, jsmntok_t *key, char *json)