1 /* Copyright (c) 2012, Bastien Dejean
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #include "subscribe.h"
44 bool restore_state(const char *file_path)
47 char *json = read_string(file_path, &jslen);
55 jsmntok_t *tokens = malloc(nbtok * sizeof(jsmntok_t));
58 perror("Restore tree: malloc");
66 while ((ret = jsmn_parse(&parser, json, jslen, tokens, nbtok)) == JSMN_ERROR_NOMEM) {
68 jsmntok_t *rtokens = realloc(tokens, nbtok * sizeof(jsmntok_t));
69 if (rtokens == NULL) {
70 perror("Restore tree: realloc");
80 warn("Restore tree: jsmn_parse: ");
82 case JSMN_ERROR_NOMEM:
83 warn("not enough memory.\n");
85 case JSMN_ERROR_INVAL:
86 warn("found invalid character inside JSON string.\n");
89 warn("not a full JSON packet.\n");
92 warn("unknown error.\n");
102 int num = tokens[0].size;
112 while (mon_head != NULL) {
113 remove_monitor(mon_head);
116 jsmntok_t *t = tokens + 1;
117 uint32_t focused_monitor_id = 0, primary_monitor_id = 0;
118 jsmntok_t *focus_history_token = NULL, *stacking_list_token = NULL;
120 for (int i = 0; i < num; i++) {
121 if (keyeq("focusedMonitorId", t, json)) {
123 sscanf(json + t->start, "%u", &focused_monitor_id);
124 } else if (keyeq("primaryMonitorId", t, json)) {
126 sscanf(json + t->start, "%u", &primary_monitor_id);
127 } else if (keyeq("clientsCount", t, json)) {
129 sscanf(json + t->start, "%u", &clients_count);
130 } else if (keyeq("monitors", t, json)) {
134 for (int j = 0; j < s; j++) {
135 monitor_t *m = restore_monitor(&t, json);
136 if (m->desk == NULL) {
137 add_desktop(m, make_desktop(NULL, XCB_NONE));
142 } else if (keyeq("focusHistory", t, json)) {
145 focus_history_token = t;
147 restore_history(&t, json);
149 } else if (keyeq("stackingList", t, json)) {
152 stacking_list_token = t;
154 restore_stack(&t, json);
156 } else if (keyeq("eventSubscribers", t, json)) {
158 restore_subscribers(&t, json);
164 if (focused_monitor_id != 0) {
166 if (monitor_from_id(focused_monitor_id, &loc)) {
171 if (primary_monitor_id != 0) {
173 if (monitor_from_id(primary_monitor_id, &loc)) {
174 pri_mon = loc.monitor;
178 if (focus_history_token != NULL) {
179 restore_history(&focus_history_token, json);
182 if (stacking_list_token != NULL) {
183 restore_stack(&stacking_list_token, json);
186 for (monitor_t *m = mon_head; m != NULL; m = m->next) {
187 m->id = xcb_generate_id(dpy);
188 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
189 d->id = xcb_generate_id(dpy);
190 regenerate_ids_in(d->root);
191 refresh_presel_feedbacks(m, d, d->root);
192 restack_presel_feedbacks(d);
194 for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
195 if (n->client == NULL) {
198 initialize_client(n);
199 uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
200 xcb_change_window_attributes(dpy, n->id, XCB_CW_EVENT_MASK, values);
201 window_grab_buttons(n->id);
206 ewmh_update_number_of_desktops();
207 ewmh_update_desktop_names();
208 ewmh_update_desktop_viewport();
209 ewmh_update_current_desktop();
210 ewmh_update_client_list(false);
211 ewmh_update_client_list(true);
212 ewmh_update_active_window();
220 #define RESTORE_INT(k, p) \
221 } else if (keyeq(#k, *t, json)) { \
223 sscanf(json + (*t)->start, "%i", p);
225 #define RESTORE_UINT(k, p) \
226 } else if (keyeq(#k, *t, json)) { \
228 sscanf(json + (*t)->start, "%u", p);
230 #define RESTORE_USINT(k, p) \
231 } else if (keyeq(#k, *t, json)) { \
233 sscanf(json + (*t)->start, "%hu", p);
235 #define RESTORE_DOUBLE(k, p) \
236 } else if (keyeq(#k, *t, json)) { \
238 sscanf(json + (*t)->start, "%lf", p);
240 #define RESTORE_ANY(k, p, f) \
241 } else if (keyeq(#k, *t, json)) { \
243 char *val = copy_string(json + (*t)->start, (*t)->end - (*t)->start); \
247 #define RESTORE_BOOL(k, p) RESTORE_ANY(k, p, parse_bool)
249 monitor_t *restore_monitor(jsmntok_t **t, char *json)
251 int num = (*t)->size;
253 monitor_t *m = make_monitor(NULL, NULL, UINT32_MAX);
254 uint32_t focused_desktop_id = 0;
256 for (int i = 0; i < num; i++) {
257 if (keyeq("name", *t, json)) {
259 snprintf(m->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
260 RESTORE_UINT(id, &m->id)
261 RESTORE_UINT(randrId, &m->randr_id)
262 RESTORE_BOOL(wired, &m->wired)
263 RESTORE_UINT(stickyCount, &m->sticky_count)
264 RESTORE_INT(windowGap, &m->window_gap)
265 RESTORE_UINT(borderWidth, &m->border_width)
266 RESTORE_UINT(focusedDesktopId, &focused_desktop_id)
267 } else if (keyeq("padding", *t, json)) {
269 restore_padding(&m->padding, t, json);
271 } else if (keyeq("rectangle", *t, json)) {
273 restore_rectangle(&m->rectangle, t, json);
274 update_root(m, &m->rectangle);
276 } else if (keyeq("desktops", *t, json)) {
280 for (int j = 0; j < s; j++) {
281 desktop_t *d = restore_desktop(t, json);
286 warn("Restore monitor: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
292 if (focused_desktop_id != 0) {
293 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
294 if (d->id == focused_desktop_id) {
304 desktop_t *restore_desktop(jsmntok_t **t, char *json)
308 desktop_t *d = make_desktop(NULL, UINT32_MAX);
309 xcb_window_t focusedNodeId = XCB_NONE;
311 for (int i = 0; i < s; i++) {
312 if (keyeq("name", *t, json)) {
314 snprintf(d->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
315 RESTORE_UINT(id, &d->id)
316 RESTORE_ANY(layout, &d->layout, parse_layout)
317 RESTORE_ANY(userLayout, &d->user_layout, parse_layout)
318 RESTORE_INT(windowGap, &d->window_gap)
319 RESTORE_UINT(borderWidth, &d->border_width)
320 } else if (keyeq("focusedNodeId", *t, json)) {
322 sscanf(json + (*t)->start, "%u", &focusedNodeId);
323 } else if (keyeq("padding", *t, json)) {
325 restore_padding(&d->padding, t, json);
327 } else if (keyeq("root", *t, json)) {
329 d->root = restore_node(t, json);
332 warn("Restore desktop: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
338 if (focusedNodeId != XCB_NONE) {
339 d->focus = find_by_id_in(d->root, focusedNodeId);
345 node_t *restore_node(jsmntok_t **t, char *json)
347 if ((*t)->type == JSMN_PRIMITIVE) {
353 /* hack to prevent a new ID from being generated */
354 node_t *n = make_node(UINT32_MAX);
356 for (int i = 0; i < s; i++) {
357 if (keyeq("id", *t, json)) {
359 sscanf(json + (*t)->start, "%u", &n->id);
360 RESTORE_ANY(splitType, &n->split_type, parse_split_type)
361 RESTORE_DOUBLE(splitRatio, &n->split_ratio)
362 RESTORE_BOOL(vacant, &n->vacant)
363 RESTORE_BOOL(hidden, &n->hidden)
364 RESTORE_BOOL(sticky, &n->sticky)
365 RESTORE_BOOL(private, &n->private)
366 RESTORE_BOOL(locked, &n->locked)
367 RESTORE_BOOL(marked, &n->marked)
368 } else if (keyeq("presel", *t, json)) {
370 n->presel = restore_presel(t, json);
372 } else if (keyeq("rectangle", *t, json)) {
374 restore_rectangle(&n->rectangle, t, json);
376 } else if (keyeq("constraints", *t, json)) {
378 restore_constraints(&n->constraints, t, json);
380 } else if (keyeq("firstChild", *t, json)) {
382 node_t *fc = restore_node(t, json);
388 } else if (keyeq("secondChild", *t, json)) {
390 node_t *sc = restore_node(t, json);
391 n->second_child = sc;
396 } else if (keyeq("client", *t, json)) {
398 n->client = restore_client(t, json);
401 warn("Restore node: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
411 presel_t *restore_presel(jsmntok_t **t, char *json)
413 if ((*t)->type == JSMN_PRIMITIVE) {
419 presel_t *p = make_presel();
421 for (int i = 0; i < s; i++) {
422 if (keyeq("splitRatio", *t, json)) {
424 sscanf(json + (*t)->start, "%lf", &p->split_ratio);
425 RESTORE_ANY(splitDir, &p->split_dir, parse_direction)
436 client_t *restore_client(jsmntok_t **t, char *json)
438 if ((*t)->type == JSMN_PRIMITIVE) {
444 client_t *c = make_client();
446 for (int i = 0; i < s; i++) {
447 if (keyeq("className", *t, json)) {
449 snprintf(c->class_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
450 } else if (keyeq("instanceName", *t, json)) {
452 snprintf(c->instance_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
453 RESTORE_ANY(state, &c->state, parse_client_state)
454 RESTORE_ANY(lastState, &c->last_state, parse_client_state)
455 RESTORE_ANY(layer, &c->layer, parse_stack_layer)
456 RESTORE_ANY(lastLayer, &c->last_layer, parse_stack_layer)
457 RESTORE_UINT(borderWidth, &c->border_width)
458 RESTORE_BOOL(urgent, &c->urgent)
459 RESTORE_BOOL(shown, &c->shown)
460 } else if (keyeq("tiledRectangle", *t, json)) {
462 restore_rectangle(&c->tiled_rectangle, t, json);
464 } else if (keyeq("floatingRectangle", *t, json)) {
466 restore_rectangle(&c->floating_rectangle, t, json);
469 warn("Restore client: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
480 void restore_rectangle(xcb_rectangle_t *r, jsmntok_t **t, char *json)
485 for (int i = 0; i < s; i++) {
486 if (keyeq("x", *t, json)) {
488 sscanf(json + (*t)->start, "%hi", &r->x);
489 } else if (keyeq("y", *t, json)) {
491 sscanf(json + (*t)->start, "%hi", &r->y);
492 } else if (keyeq("width", *t, json)) {
494 sscanf(json + (*t)->start, "%hu", &r->width);
495 } else if (keyeq("height", *t, json)) {
497 sscanf(json + (*t)->start, "%hu", &r->height);
503 void restore_constraints(constraints_t *c, jsmntok_t **t, char *json)
508 for (int i = 0; i < s; i++) {
509 if (keyeq("min_width", *t, json)) {
511 sscanf(json + (*t)->start, "%hu", &c->min_width);
512 } else if (keyeq("min_height", *t, json)) {
514 sscanf(json + (*t)->start, "%hu", &c->min_height);
520 void restore_padding(padding_t *p, jsmntok_t **t, char *json)
525 for (int i = 0; i < s; i++) {
526 if (keyeq("top", *t, json)) {
528 sscanf(json + (*t)->start, "%i", &p->top);
529 } else if (keyeq("right", *t, json)) {
531 sscanf(json + (*t)->start, "%i", &p->right);
532 } else if (keyeq("bottom", *t, json)) {
534 sscanf(json + (*t)->start, "%i", &p->bottom);
535 } else if (keyeq("left", *t, json)) {
537 sscanf(json + (*t)->start, "%i", &p->left);
543 void restore_history(jsmntok_t **t, char *json)
548 for (int i = 0; i < s; i++) {
549 coordinates_t loc = {NULL, NULL, NULL};
550 restore_coordinates(&loc, t, json);
551 if (loc.monitor != NULL && loc.desktop != NULL) {
552 history_add(loc.monitor, loc.desktop, loc.node, true);
557 void restore_subscribers(jsmntok_t **t, char *json)
562 for (int i = 0; i < s; i++) {
563 subscriber_list_t *s = make_subscriber(NULL, NULL, 0, 0);
564 restore_subscriber(s, t, json);
569 void restore_subscriber(subscriber_list_t *s, jsmntok_t **t, char *json)
574 for (int i = 0; i < n; i++) {
575 if (keyeq("fileDescriptor", *t, json)) {
578 sscanf(json + (*t)->start, "%i", &fd);
579 s->stream = fdopen(fd, "w");
580 } else if (keyeq("fifoPath", *t, json)) {
583 s->fifo_path = copy_string(json + (*t)->start, (*t)->end - (*t)->start);
584 RESTORE_INT(field, &s->field)
585 RESTORE_INT(count, &s->count)
591 void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json)
597 for (int i = 0; i < s; i++) {
598 if (keyeq("monitorId", *t, json)) {
600 sscanf(json + (*t)->start, "%u", &id);
601 loc->monitor = find_monitor(id);
602 } else if (keyeq("desktopId", *t, json)) {
604 sscanf(json + (*t)->start, "%u", &id);
605 loc->desktop = find_desktop_in(id, loc->monitor);
606 } else if (keyeq("nodeId", *t, json)) {
608 sscanf(json + (*t)->start, "%u", &id);
609 loc->node = find_by_id_in(loc->desktop != NULL ? loc->desktop->root : NULL, id);
615 void restore_stack(jsmntok_t **t, char *json)
620 for (int i = 0; i < s; i++) {
622 sscanf(json + (*t)->start, "%u", &id);
624 if (locate_window(id, &loc)) {
625 stack_insert_after(stack_tail, loc.node);
634 #undef RESTORE_DOUBLE
638 bool keyeq(char *s, jsmntok_t *key, char *json)
640 size_t n = key->end - key->start;
641 return (strlen(s) == n && strncmp(s, json + key->start, n) == 0);