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.
42 bool restore_tree(const char *file_path)
45 char *json = read_string(file_path, &jslen);
53 jsmntok_t *tokens = malloc(nbtok * sizeof(jsmntok_t));
56 perror("Restore tree: malloc");
64 while ((ret = jsmn_parse(&parser, json, jslen, tokens, nbtok)) == JSMN_ERROR_NOMEM) {
66 jsmntok_t *rtokens = realloc(tokens, nbtok * sizeof(jsmntok_t));
67 if (rtokens == NULL) {
68 perror("Restore tree: realloc");
78 warn("Restore tree: jsmn_parse: ");
80 case JSMN_ERROR_NOMEM:
81 warn("not enough memory.\n");
83 case JSMN_ERROR_INVAL:
84 warn("found invalid character inside JSON string.\n");
87 warn("not a full JSON packet.\n");
90 warn("unknown error.\n");
100 int num = tokens[0].size;
110 while (mon_head != NULL) {
111 remove_monitor(mon_head);
114 jsmntok_t *t = tokens + 1;
115 char *focusedMonitorName = NULL, *primaryMonitorName = NULL;
117 for (int i = 0; i < num; i++) {
118 if (keyeq("focusedMonitorName", t, json)) {
119 free(focusedMonitorName);
120 focusedMonitorName = copy_string(t+1, json);
122 } else if (keyeq("primaryMonitorName", t, json)) {
123 free(primaryMonitorName);
124 primaryMonitorName = copy_string(t+1, json);
126 } else if (keyeq("clientsCount", t, json)) {
128 sscanf(json + t->start, "%u", &clients_count);
129 } else if (keyeq("monitors", t, json)) {
133 for (int j = 0; j < s; j++) {
134 monitor_t *m = restore_monitor(&t, json);
138 } else if (keyeq("focusHistory", t, json)) {
140 restore_history(&t, json);
142 } else if (keyeq("stackingList", t, json)) {
144 restore_stack(&t, json);
150 if (focusedMonitorName != NULL) {
152 if (locate_monitor(focusedMonitorName, &loc)) {
157 if (primaryMonitorName != NULL) {
159 if (locate_monitor(primaryMonitorName, &loc)) {
160 pri_mon = loc.monitor;
164 free(focusedMonitorName);
165 free(primaryMonitorName);
167 for (monitor_t *m = mon_head; m != NULL; m = m->next) {
168 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
169 refresh_presel_feebacks_in(d->root, d, m);
170 restack_presel_feedback(d);
171 for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
172 uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
173 xcb_change_window_attributes(dpy, n->id, XCB_CW_EVENT_MASK, values);
178 ewmh_update_client_list(false);
179 ewmh_update_client_list(true);
180 ewmh_update_active_window();
181 ewmh_update_number_of_desktops();
182 ewmh_update_current_desktop();
183 ewmh_update_desktop_names();
191 #define RESTORE_INT(k, p) \
192 } else if (keyeq(#k, *t, json)) { \
194 sscanf(json + (*t)->start, "%i", p);
196 #define RESTORE_UINT(k, p) \
197 } else if (keyeq(#k, *t, json)) { \
199 sscanf(json + (*t)->start, "%u", p);
201 #define RESTORE_USINT(k, p) \
202 } else if (keyeq(#k, *t, json)) { \
204 sscanf(json + (*t)->start, "%hu", p);
206 #define RESTORE_DOUBLE(k, p) \
207 } else if (keyeq(#k, *t, json)) { \
209 sscanf(json + (*t)->start, "%lf", p);
211 #define RESTORE_ANY(k, p, f) \
212 } else if (keyeq(#k, *t, json)) { \
214 char *val = copy_string(*t, json); \
218 #define RESTORE_BOOL(k, p) RESTORE_ANY(k, p, parse_bool)
220 monitor_t *restore_monitor(jsmntok_t **t, char *json)
222 int num = (*t)->size;
224 monitor_t *m = make_monitor(NULL);
225 char *focusedDesktopName = NULL;
227 for (int i = 0; i < num; i++) {
228 if (keyeq("name", *t, json)) {
230 snprintf(m->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
231 RESTORE_UINT(id, &m->id)
232 RESTORE_BOOL(wired, &m->wired)
233 RESTORE_INT(topPadding, &m->top_padding)
234 RESTORE_INT(rightPadding, &m->right_padding)
235 RESTORE_INT(bottomPadding, &m->bottom_padding)
236 RESTORE_INT(leftPadding, &m->left_padding)
237 RESTORE_UINT(stickyCount, &m->sticky_count)
238 } else if (keyeq("rectangle", *t, json)) {
240 restore_rectangle(&m->rectangle, t, json);
241 update_root(m, &m->rectangle);
243 } else if (keyeq("focusedDesktopName", *t, json)) {
244 free(focusedDesktopName);
246 focusedDesktopName = copy_string(*t, json);
247 } else if (keyeq("desktops", *t, json)) {
251 for (int j = 0; j < s; j++) {
252 desktop_t *d = restore_desktop(t, json);
257 warn("Restore monitor: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
263 if (focusedDesktopName != NULL) {
264 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
265 if (streq(focusedDesktopName, d->name)) {
272 free(focusedDesktopName);
277 desktop_t *restore_desktop(jsmntok_t **t, char *json)
281 desktop_t *d = make_desktop(NULL);
282 xcb_window_t focusedNodeId = XCB_NONE;
284 for (int i = 0; i < s; i++) {
285 if (keyeq("name", *t, json)) {
287 snprintf(d->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
288 } else if (keyeq("layout", *t, json)) {
290 char *val = copy_string(*t, json);
292 if (parse_layout(val, &lyt)) {
296 RESTORE_INT(topPadding, &d->top_padding)
297 RESTORE_INT(rightPadding, &d->right_padding)
298 RESTORE_INT(bottomPadding, &d->bottom_padding)
299 RESTORE_INT(leftPadding, &d->left_padding)
300 RESTORE_INT(windowGap, &d->window_gap)
301 RESTORE_UINT(borderWidth, &d->border_width)
302 } else if (keyeq("focusedNodeId", *t, json)) {
304 sscanf(json + (*t)->start, "%u", &focusedNodeId);
305 } else if (keyeq("root", *t, json)) {
307 d->root = restore_node(t, json);
310 warn("Restore desktop: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
316 if (focusedNodeId != XCB_NONE) {
317 d->focus = find_by_id_in(d->root, focusedNodeId);
323 node_t *restore_node(jsmntok_t **t, char *json)
325 if ((*t)->type == JSMN_PRIMITIVE) {
331 /* hack to prevent a new ID from being generated */
332 node_t *n = make_node(UINT32_MAX);
334 for (int i = 0; i < s; i++) {
335 if (keyeq("id", *t, json)) {
337 sscanf(json + (*t)->start, "%u", &n->id);
338 RESTORE_ANY(splitType, &n->split_type, parse_split_type)
339 RESTORE_DOUBLE(splitRatio, &n->split_ratio)
340 RESTORE_INT(birthRotation, &n->birth_rotation)
341 RESTORE_ANY(vacant, &n->vacant, parse_bool)
342 RESTORE_ANY(sticky, &n->sticky, parse_bool)
343 RESTORE_ANY(private, &n->private, parse_bool)
344 RESTORE_ANY(locked, &n->locked, parse_bool)
345 } else if (keyeq("presel", *t, json)) {
347 n->presel = restore_presel(t, json);
349 } else if (keyeq("rectangle", *t, json)) {
351 restore_rectangle(&n->rectangle, t, json);
353 } else if (keyeq("firstChild", *t, json)) {
355 node_t *fc = restore_node(t, json);
361 } else if (keyeq("secondChild", *t, json)) {
363 node_t *sc = restore_node(t, json);
364 n->second_child = sc;
369 } else if (keyeq("client", *t, json)) {
371 n->client = restore_client(t, json);
374 warn("Restore node: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
384 presel_t *restore_presel(jsmntok_t **t, char *json)
386 if ((*t)->type == JSMN_PRIMITIVE) {
392 presel_t *p = make_presel();
394 for (int i = 0; i < s; i++) {
395 if (keyeq("splitRatio", *t, json)) {
397 sscanf(json + (*t)->start, "%lf", &p->split_ratio);
398 RESTORE_ANY(splitDir, &p->split_dir, parse_direction)
409 client_t *restore_client(jsmntok_t **t, char *json)
411 if ((*t)->type == JSMN_PRIMITIVE) {
417 client_t *c = make_client();
419 for (int i = 0; i < s; i++) {
420 if (keyeq("className", *t, json)) {
422 snprintf(c->class_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
423 } else if (keyeq("instanceName", *t, json)) {
425 snprintf(c->instance_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
426 RESTORE_ANY(state, &c->state, parse_client_state)
427 RESTORE_ANY(lastState, &c->last_state, parse_client_state)
428 RESTORE_ANY(layer, &c->layer, parse_stack_layer)
429 RESTORE_ANY(lastLayer, &c->last_layer, parse_stack_layer)
430 RESTORE_UINT(borderWidth, &c->border_width)
431 RESTORE_BOOL(urgent, &c->urgent)
432 RESTORE_BOOL(icccmFocus, &c->icccm_focus)
433 RESTORE_BOOL(icccmInput, &c->icccm_input)
434 RESTORE_USINT(minWidth, &c->min_width)
435 RESTORE_USINT(maxWidth, &c->max_width)
436 RESTORE_USINT(minHeight, &c->min_height)
437 RESTORE_USINT(maxHeight, &c->max_height)
438 RESTORE_INT(wmStatesCount, &c->wm_states_count)
439 } else if (keyeq("wmState", *t, json)) {
441 restore_wm_state(c->wm_state, t, json);
443 } else if (keyeq("tiledRectangle", *t, json)) {
445 restore_rectangle(&c->tiled_rectangle, t, json);
447 } else if (keyeq("floatingRectangle", *t, json)) {
449 restore_rectangle(&c->floating_rectangle, t, json);
452 warn("Restore client: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
463 void restore_rectangle(xcb_rectangle_t *r, jsmntok_t **t, char *json)
468 for (int i = 0; i < s; i++) {
469 if (keyeq("x", *t, json)) {
471 sscanf(json + (*t)->start, "%hi", &r->x);
472 } else if (keyeq("y", *t, json)) {
474 sscanf(json + (*t)->start, "%hi", &r->y);
475 } else if (keyeq("width", *t, json)) {
477 sscanf(json + (*t)->start, "%hu", &r->width);
478 } else if (keyeq("height", *t, json)) {
480 sscanf(json + (*t)->start, "%hu", &r->height);
486 void restore_history(jsmntok_t **t, char *json)
491 for (int i = 0; i < s; i++) {
492 coordinates_t loc = {NULL, NULL, NULL};
493 restore_coordinates(&loc, t, json);
494 if (loc.monitor != NULL && loc.desktop != NULL) {
495 history_add(loc.monitor, loc.desktop, loc.node);
500 void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json)
505 for (int i = 0; i < s; i++) {
506 if (keyeq("monitorName", *t, json)) {
508 char *name = copy_string(*t, json);
509 loc->monitor = find_monitor(name);
511 } else if (keyeq("desktopName", *t, json)) {
513 char *name = copy_string(*t, json);
514 loc->desktop = find_desktop_in(name, loc->monitor);
516 } else if (keyeq("nodeId", *t, json)) {
519 sscanf(json + (*t)->start, "%u", &id);
520 loc->node = find_by_id_in(loc->desktop!=NULL?loc->desktop->root:NULL, id);
526 void restore_stack(jsmntok_t **t, char *json)
531 for (int i = 0; i < s; i++) {
533 sscanf(json + (*t)->start, "%u", &id);
535 if (locate_window(id, &loc)) {
536 stack_insert_after(stack_tail, loc.node);
542 void restore_wm_state(xcb_atom_t *w, jsmntok_t **t, char *json)
547 for (int i = 0; i < s; i++) {
548 sscanf(json + (*t)->start, "%u", &w[i]);
556 #undef RESTORE_DOUBLE
560 bool keyeq(char *s, jsmntok_t *key, char *json)
562 size_t n = key->end - key->start;
563 return (strlen(s) == n && strncmp(s, json + key->start, n) == 0);
566 char *copy_string(jsmntok_t *tok, char *json)
568 size_t len = tok->end - tok->start + 1;
569 char *res = malloc(len * sizeof(char));
571 perror("Copy string: malloc");
574 strncpy(res, json+tok->start, len-1);