+#include "window.h"
+#include "parse.h"
+
+bool restore_tree(const char *file_path)
+{
+ size_t jslen;
+ char *json = read_string(file_path, &jslen);
+
+ if (json == NULL) {
+ return false;
+ }
+
+ int nbtok = 256;
+ jsmn_parser parser;
+ jsmntok_t *tokens = malloc(nbtok * sizeof(jsmntok_t));
+
+ if (tokens == NULL) {
+ perror("Restore tree: malloc");
+ free(json);
+ return false;
+ }
+
+ jsmn_init(&parser);
+ int ret;
+
+ while ((ret = jsmn_parse(&parser, json, jslen, tokens, nbtok)) == JSMN_ERROR_NOMEM) {
+ nbtok *= 2;
+ jsmntok_t *rtokens = realloc(tokens, nbtok * sizeof(jsmntok_t));
+ if (rtokens == NULL) {
+ perror("Restore tree: realloc");
+ free(tokens);
+ free(json);
+ return false;
+ } else {
+ tokens = rtokens;
+ }
+ }
+
+ if (ret < 0) {
+ warn("Restore tree: jsmn_parse: ");
+ switch (ret) {
+ case JSMN_ERROR_NOMEM:
+ warn("not enough memory.\n");
+ break;
+ case JSMN_ERROR_INVAL:
+ warn("found invalid character inside JSON string.\n");
+ break;
+ case JSMN_ERROR_PART:
+ warn("not a full JSON packet.\n");
+ break;
+ default:
+ warn("unknown error.\n");
+ break;
+ }
+
+ free(tokens);
+ free(json);
+
+ return false;
+ }
+
+ int num = tokens[0].size;
+
+ if (num < 1) {
+ free(tokens);
+ free(json);
+
+ return false;
+ }
+
+ mon = NULL;
+ while (mon_head != NULL) {
+ remove_monitor(mon_head);
+ }
+
+ jsmntok_t *t = tokens + 1;
+ uint32_t focused_monitor_id = 0, primary_monitor_id = 0;
+
+ for (int i = 0; i < num; i++) {
+ if (keyeq("focusedMonitorId", t, json)) {
+ t++;
+ sscanf(json + t->start, "%u", &focused_monitor_id);
+ } else if (keyeq("primaryMonitorId", t, json)) {
+ t++;
+ sscanf(json + t->start, "%u", &primary_monitor_id);
+ } else if (keyeq("clientsCount", t, json)) {
+ t++;
+ sscanf(json + t->start, "%u", &clients_count);
+ } else if (keyeq("monitors", t, json)) {
+ t++;
+ int s = t->size;
+ t++;
+ for (int j = 0; j < s; j++) {
+ monitor_t *m = restore_monitor(&t, json);
+ if (m->desk == NULL) {
+ add_desktop(m, make_desktop(NULL, XCB_NONE));
+ }
+ add_monitor(m);
+ }
+ continue;
+ } else if (keyeq("focusHistory", t, json)) {
+ t++;
+ restore_history(&t, json);
+ continue;
+ } else if (keyeq("stackingList", t, json)) {
+ t++;
+ restore_stack(&t, json);
+ continue;
+ }
+ t++;
+ }
+
+ if (focused_monitor_id != 0) {
+ coordinates_t loc;
+ if (monitor_from_id(focused_monitor_id, &loc)) {
+ mon = loc.monitor;
+ }
+ }
+
+ if (primary_monitor_id != 0) {
+ coordinates_t loc;
+ if (monitor_from_id(primary_monitor_id, &loc)) {
+ pri_mon = loc.monitor;
+ }
+ }
+
+ for (monitor_t *m = mon_head; m != NULL; m = m->next) {
+ for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
+ refresh_presel_feebacks_in(d->root, d, m);
+ restack_presel_feedback(d);
+ for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
+ if (n->client == NULL) {
+ continue;
+ }
+ initialize_client(n);
+ uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
+ xcb_change_window_attributes(dpy, n->id, XCB_CW_EVENT_MASK, values);
+ }
+ }
+ }
+
+ ewmh_update_client_list(false);
+ ewmh_update_client_list(true);
+ ewmh_update_active_window();
+ ewmh_update_number_of_desktops();
+ ewmh_update_current_desktop();
+ ewmh_update_desktop_names();
+
+ free(tokens);
+ free(json);
+
+ return true;
+}
+
+#define RESTORE_INT(k, p) \
+ } else if (keyeq(#k, *t, json)) { \
+ (*t)++; \
+ sscanf(json + (*t)->start, "%i", p);
+
+#define RESTORE_UINT(k, p) \
+ } else if (keyeq(#k, *t, json)) { \
+ (*t)++; \
+ sscanf(json + (*t)->start, "%u", p);
+
+#define RESTORE_USINT(k, p) \
+ } else if (keyeq(#k, *t, json)) { \
+ (*t)++; \
+ sscanf(json + (*t)->start, "%hu", p);
+
+#define RESTORE_DOUBLE(k, p) \
+ } else if (keyeq(#k, *t, json)) { \
+ (*t)++; \
+ sscanf(json + (*t)->start, "%lf", p);
+
+#define RESTORE_ANY(k, p, f) \
+ } else if (keyeq(#k, *t, json)) { \
+ (*t)++; \
+ char *val = copy_string(json + (*t)->start, (*t)->end - (*t)->start); \
+ f(val, p); \
+ free(val);
+
+#define RESTORE_BOOL(k, p) RESTORE_ANY(k, p, parse_bool)
+
+monitor_t *restore_monitor(jsmntok_t **t, char *json)
+{
+ int num = (*t)->size;
+ (*t)++;
+ monitor_t *m = make_monitor(NULL, UINT32_MAX);
+ uint32_t focused_desktop_id = 0;
+
+ for (int i = 0; i < num; i++) {
+ if (keyeq("name", *t, json)) {
+ (*t)++;
+ snprintf(m->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
+ RESTORE_UINT(id, &m->id)
+ RESTORE_UINT(randrId, &m->randr_id)
+ RESTORE_BOOL(wired, &m->wired)
+ RESTORE_UINT(stickyCount, &m->sticky_count)
+ RESTORE_INT(windowGap, &m->window_gap)
+ RESTORE_UINT(borderWidth, &m->border_width)
+ RESTORE_UINT(focusedDesktopId, &focused_desktop_id)
+ } else if (keyeq("padding", *t, json)) {
+ (*t)++;
+ restore_padding(&m->padding, t, json);
+ continue;
+ } else if (keyeq("rectangle", *t, json)) {
+ (*t)++;
+ restore_rectangle(&m->rectangle, t, json);
+ update_root(m, &m->rectangle);
+ continue;
+ } else if (keyeq("desktops", *t, json)) {
+ (*t)++;
+ int s = (*t)->size;
+ (*t)++;
+ for (int j = 0; j < s; j++) {
+ desktop_t *d = restore_desktop(t, json);
+ add_desktop(m, d);
+ }
+ continue;
+ } else {
+ warn("Restore monitor: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
+ (*t)++;
+ }
+ (*t)++;
+ }
+
+ if (focused_desktop_id != 0) {
+ for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
+ if (d->id == focused_desktop_id) {
+ m->desk = d;
+ break;
+ }
+ }
+ }
+
+ return m;
+}