]> git.lizzy.rs Git - bspwm.git/blob - restore.c
Don't try to restore the state from zero tokens
[bspwm.git] / restore.c
1 /* Copyright (c) 2012, Bastien Dejean
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
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.
12  *
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.
23  */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include "bspwm.h"
30 #include "desktop.h"
31 #include "ewmh.h"
32 #include "history.h"
33 #include "monitor.h"
34 #include "query.h"
35 #include "stack.h"
36 #include "tree.h"
37 #include "settings.h"
38 #include "restore.h"
39 #include "window.h"
40 #include "parse.h"
41
42 bool restore_tree(const char *file_path)
43 {
44         size_t jslen;
45         char *json = read_string(file_path, &jslen);
46
47         if (json == NULL) {
48                 return false;
49         }
50
51         int nbtok = 256;
52         jsmn_parser parser;
53         jsmntok_t *tokens = malloc(nbtok * sizeof(jsmntok_t));
54
55         if (tokens == NULL) {
56                 perror("Restore tree: malloc");
57                 free(json);
58                 return false;
59         }
60
61         jsmn_init(&parser);
62         int ret;
63
64         while ((ret = jsmn_parse(&parser, json, jslen, tokens, nbtok)) == JSMN_ERROR_NOMEM) {
65                 nbtok *= 2;
66                 jsmntok_t *rtokens = realloc(tokens, nbtok * sizeof(jsmntok_t));
67                 if (rtokens == NULL) {
68                         perror("Restore tree: realloc");
69                         free(tokens);
70                         free(json);
71                         return false;
72                 } else {
73                         tokens = rtokens;
74                 }
75         }
76
77         if (ret < 0) {
78                 warn("Restore tree: jsmn_parse: ");
79                 switch (ret) {
80                         case JSMN_ERROR_NOMEM:
81                                 warn("not enough memory.\n");
82                                 break;
83                         case JSMN_ERROR_INVAL:
84                                 warn("found invalid character inside JSON string.\n");
85                                 break;
86                         case JSMN_ERROR_PART:
87                                 warn("not a full JSON packet.\n");
88                                 break;
89                         default:
90                                 warn("unknown error.\n");
91                                 break;
92                 }
93
94                 free(tokens);
95                 free(json);
96
97                 return false;
98         }
99
100         int num = tokens[0].size;
101
102         if (num < 1) {
103                 free(tokens);
104                 free(json);
105
106                 return false;
107         }
108
109         mon = NULL;
110         while (mon_head != NULL) {
111                 remove_monitor(mon_head);
112         }
113
114         jsmntok_t *t = tokens + 1;
115         char *focusedMonitorName = NULL;
116
117         for (int i = 0; i < num; i++) {
118                 if (keyeq("focusedMonitorName", t, json)) {
119                         free(focusedMonitorName);
120                         focusedMonitorName = copy_string(t+1, json);
121                         t++;
122                 } else if (keyeq("clientsCount", t, json)) {
123                         t++;
124                         sscanf(json + t->start, "%u", &clients_count);
125                 } else if (keyeq("monitors", t, json)) {
126                         t++;
127                         int s = t->size;
128                         t++;
129                         for (int j = 0; j < s; j++) {
130                                 monitor_t *m = restore_monitor(&t, json);
131                                 add_monitor(m);
132                         }
133                         continue;
134                 } else if (keyeq("focusHistory", t, json)) {
135                         t++;
136                         restore_history(&t, json);
137                         continue;
138                 } else if (keyeq("stackingList", t, json)) {
139                         t++;
140                         restore_stack(&t, json);
141                         continue;
142                 }
143                 t++;
144         }
145
146         if (focusedMonitorName != NULL) {
147                 coordinates_t loc;
148                 if (locate_monitor(focusedMonitorName, &loc)) {
149                         mon = loc.monitor;
150                 }
151         }
152
153         free(focusedMonitorName);
154
155         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
156                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
157                         refresh_presel_feebacks_in(d->root, d, m);
158                         restack_presel_feedback(d);
159                         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
160                                 uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
161                                 xcb_change_window_attributes(dpy, n->id, XCB_CW_EVENT_MASK, values);
162                         }
163                 }
164         }
165
166         ewmh_update_client_list(false);
167         ewmh_update_client_list(true);
168         ewmh_update_active_window();
169         ewmh_update_number_of_desktops();
170         ewmh_update_current_desktop();
171         ewmh_update_desktop_names();
172
173         free(tokens);
174         free(json);
175
176         return true;
177 }
178
179 #define RESTORE_INT(k, p) \
180         } else if (keyeq(#k, *t, json)) { \
181                 (*t)++; \
182                 sscanf(json + (*t)->start, "%i", p);
183
184 #define RESTORE_UINT(k, p) \
185         } else if (keyeq(#k, *t, json)) { \
186                 (*t)++; \
187                 sscanf(json + (*t)->start, "%u", p);
188
189 #define RESTORE_USINT(k, p) \
190         } else if (keyeq(#k, *t, json)) { \
191                 (*t)++; \
192                 sscanf(json + (*t)->start, "%hu", p);
193
194 #define RESTORE_DOUBLE(k, p) \
195         } else if (keyeq(#k, *t, json)) { \
196                 (*t)++; \
197                 sscanf(json + (*t)->start, "%lf", p);
198
199 #define RESTORE_ANY(k, p, f) \
200         } else if (keyeq(#k, *t, json)) { \
201                 (*t)++; \
202                 char *val = copy_string(*t, json); \
203                 f(val, p); \
204                 free(val);
205
206 #define RESTORE_BOOL(k, p)  RESTORE_ANY(k, p, parse_bool)
207
208 monitor_t *restore_monitor(jsmntok_t **t, char *json)
209 {
210         int num = (*t)->size;
211         (*t)++;
212         monitor_t *m = make_monitor(NULL);
213         char *focusedDesktopName = NULL;
214
215         for (int i = 0; i < num; i++) {
216                 if (keyeq("name", *t, json)) {
217                         (*t)++;
218                         snprintf(m->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
219                 RESTORE_UINT(id, &m->id)
220                 RESTORE_BOOL(wired, &m->wired)
221                 RESTORE_INT(topPadding, &m->top_padding)
222                 RESTORE_INT(rightPadding, &m->right_padding)
223                 RESTORE_INT(bottomPadding, &m->bottom_padding)
224                 RESTORE_INT(leftPadding, &m->left_padding)
225                 RESTORE_UINT(stickyCount, &m->sticky_count)
226                 } else if (keyeq("rectangle", *t, json)) {
227                         (*t)++;
228                         restore_rectangle(&m->rectangle, t, json);
229                         update_root(m, &m->rectangle);
230                         continue;
231                 } else if (keyeq("focusedDesktopName", *t, json)) {
232                         free(focusedDesktopName);
233                         (*t)++;
234                         focusedDesktopName = copy_string(*t, json);
235                 } else if (keyeq("desktops", *t, json)) {
236                         (*t)++;
237                         int s = (*t)->size;
238                         (*t)++;
239                         for (int j = 0; j < s; j++) {
240                                 desktop_t *d = restore_desktop(t, json);
241                                 add_desktop(m, d);
242                         }
243                         continue;
244                 } else {
245                         warn("Restore monitor: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
246                         (*t)++;
247                 }
248                 (*t)++;
249         }
250
251         if (focusedDesktopName != NULL) {
252                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
253                         if (streq(focusedDesktopName, d->name)) {
254                                 m->desk = d;
255                                 break;
256                         }
257                 }
258         }
259
260         free(focusedDesktopName);
261
262         return m;
263 }
264
265 desktop_t *restore_desktop(jsmntok_t **t, char *json)
266 {
267         int s = (*t)->size;
268         (*t)++;
269         desktop_t *d = make_desktop(NULL);
270         xcb_window_t focusedNodeId = XCB_NONE;
271
272         for (int i = 0; i < s; i++) {
273                 if (keyeq("name", *t, json)) {
274                         (*t)++;
275                         snprintf(d->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
276                 } else if (keyeq("layout", *t, json)) {
277                         (*t)++;
278                         char *val = copy_string(*t, json);
279                         layout_t lyt;
280                         if (parse_layout(val, &lyt)) {
281                                 d->layout = lyt;
282                         }
283                         free(val);
284                 RESTORE_INT(topPadding, &d->top_padding)
285                 RESTORE_INT(rightPadding, &d->right_padding)
286                 RESTORE_INT(bottomPadding, &d->bottom_padding)
287                 RESTORE_INT(leftPadding, &d->left_padding)
288                 RESTORE_INT(windowGap, &d->window_gap)
289                 RESTORE_UINT(borderWidth, &d->border_width)
290                 } else if (keyeq("focusedNodeId", *t, json)) {
291                         (*t)++;
292                         sscanf(json + (*t)->start, "%u", &focusedNodeId);
293                 } else if (keyeq("root", *t, json)) {
294                         (*t)++;
295                         d->root = restore_node(t, json);
296                         continue;
297                 } else {
298                         warn("Restore desktop: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
299                         (*t)++;
300                 }
301                 (*t)++;
302         }
303
304         if (focusedNodeId != XCB_NONE) {
305                 d->focus = find_by_id_in(d->root, focusedNodeId);
306         }
307
308         return d;
309 }
310
311 node_t *restore_node(jsmntok_t **t, char *json)
312 {
313         if ((*t)->type == JSMN_PRIMITIVE) {
314                 (*t)++;
315                 return NULL;
316         } else {
317                 int s = (*t)->size;
318                 (*t)++;
319                 /* hack to prevent a new ID from being generated */
320                 node_t *n = make_node(UINT32_MAX);
321
322                 for (int i = 0; i < s; i++) {
323                         if (keyeq("id", *t, json)) {
324                                 (*t)++;
325                                 sscanf(json + (*t)->start, "%u", &n->id);
326                         RESTORE_ANY(splitType, &n->split_type, parse_split_type)
327                         RESTORE_DOUBLE(splitRatio, &n->split_ratio)
328                         RESTORE_INT(birthRotation, &n->birth_rotation)
329                         RESTORE_ANY(vacant, &n->vacant, parse_bool)
330                         RESTORE_ANY(sticky, &n->sticky, parse_bool)
331                         RESTORE_ANY(private, &n->private, parse_bool)
332                         RESTORE_ANY(locked, &n->locked, parse_bool)
333                         } else if (keyeq("presel", *t, json)) {
334                                 (*t)++;
335                                 n->presel = restore_presel(t, json);
336                                 continue;
337                         } else if (keyeq("rectangle", *t, json)) {
338                                 (*t)++;
339                                 restore_rectangle(&n->rectangle, t, json);
340                                 continue;
341                         } else if (keyeq("firstChild", *t, json)) {
342                                 (*t)++;
343                                 node_t *fc = restore_node(t, json);
344                                 n->first_child = fc;
345                                 if (fc != NULL) {
346                                         fc->parent = n;
347                                 }
348                                 continue;
349                         } else if (keyeq("secondChild", *t, json)) {
350                                 (*t)++;
351                                 node_t *sc = restore_node(t, json);
352                                 n->second_child = sc;
353                                 if (sc != NULL) {
354                                         sc->parent = n;
355                                 }
356                                 continue;
357                         } else if (keyeq("client", *t, json)) {
358                                 (*t)++;
359                                 n->client = restore_client(t, json);
360                                 continue;
361                         } else {
362                                 warn("Restore node: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
363                                 (*t)++;
364                         }
365                         (*t)++;
366                 }
367
368                 return n;
369         }
370 }
371
372 presel_t *restore_presel(jsmntok_t **t, char *json)
373 {
374         if ((*t)->type == JSMN_PRIMITIVE) {
375                 (*t)++;
376                 return NULL;
377         } else {
378                 int s = (*t)->size;
379                 (*t)++;
380                 presel_t *p = make_presel();
381
382                 for (int i = 0; i < s; i++) {
383                         if (keyeq("splitRatio", *t, json)) {
384                                 (*t)++;
385                                 sscanf(json + (*t)->start, "%lf", &p->split_ratio);
386                         RESTORE_ANY(splitDir, &p->split_dir, parse_direction)
387                         }
388
389                         (*t)++;
390                 }
391
392                 return p;
393         }
394 }
395
396
397 client_t *restore_client(jsmntok_t **t, char *json)
398 {
399         if ((*t)->type == JSMN_PRIMITIVE) {
400                 (*t)++;
401                 return NULL;
402         } else {
403                 int s = (*t)->size;
404                 (*t)++;
405                 client_t *c = make_client();
406
407                 for (int i = 0; i < s; i++) {
408                         if (keyeq("className", *t, json)) {
409                                 (*t)++;
410                                 snprintf(c->class_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
411                         } else if (keyeq("instanceName", *t, json)) {
412                                 (*t)++;
413                                 snprintf(c->instance_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
414                         RESTORE_ANY(state, &c->state, parse_client_state)
415                         RESTORE_ANY(lastState, &c->last_state, parse_client_state)
416                         RESTORE_ANY(layer, &c->layer, parse_stack_layer)
417                         RESTORE_ANY(lastLayer, &c->last_layer, parse_stack_layer)
418                         RESTORE_UINT(borderWidth, &c->border_width)
419                         RESTORE_BOOL(urgent, &c->urgent)
420                         RESTORE_BOOL(icccmFocus, &c->icccm_focus)
421                         RESTORE_BOOL(icccmInput, &c->icccm_input)
422                         RESTORE_USINT(minWidth, &c->min_width)
423                         RESTORE_USINT(maxWidth, &c->max_width)
424                         RESTORE_USINT(minHeight, &c->min_height)
425                         RESTORE_USINT(maxHeight, &c->max_height)
426                         RESTORE_INT(wmStatesCount, &c->wm_states_count)
427                         } else if (keyeq("wmState", *t, json)) {
428                                 (*t)++;
429                                 restore_wm_state(c->wm_state, t, json);
430                                 continue;
431                         } else if (keyeq("tiledRectangle", *t, json)) {
432                                 (*t)++;
433                                 restore_rectangle(&c->tiled_rectangle, t, json);
434                                 continue;
435                         } else if (keyeq("floatingRectangle", *t, json)) {
436                                 (*t)++;
437                                 restore_rectangle(&c->floating_rectangle, t, json);
438                                 continue;
439                         } else {
440                                 warn("Restore client: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
441                                 (*t)++;
442                         }
443
444                         (*t)++;
445                 }
446
447                 return c;
448         }
449 }
450
451 void restore_rectangle(xcb_rectangle_t *r, jsmntok_t **t, char *json)
452 {
453         int s = (*t)->size;
454         (*t)++;
455
456         for (int i = 0; i < s; i++) {
457                 if (keyeq("x", *t, json)) {
458                         (*t)++;
459                         sscanf(json + (*t)->start, "%hi", &r->x);
460                 } else if (keyeq("y", *t, json)) {
461                         (*t)++;
462                         sscanf(json + (*t)->start, "%hi", &r->y);
463                 } else if (keyeq("width", *t, json)) {
464                         (*t)++;
465                         sscanf(json + (*t)->start, "%hu", &r->width);
466                 } else if (keyeq("height", *t, json)) {
467                         (*t)++;
468                         sscanf(json + (*t)->start, "%hu", &r->height);
469                 }
470                 (*t)++;
471         }
472 }
473
474 void restore_history(jsmntok_t **t, char *json)
475 {
476         int s = (*t)->size;
477         (*t)++;
478
479         for (int i = 0; i < s; i++) {
480                 coordinates_t loc = {NULL, NULL, NULL};
481                 restore_coordinates(&loc, t, json);
482                 if (loc.monitor != NULL && loc.desktop != NULL) {
483                         history_add(loc.monitor, loc.desktop, loc.node);
484                 }
485         }
486 }
487
488 void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json)
489 {
490         int s = (*t)->size;
491         (*t)++;
492
493         for (int i = 0; i < s; i++) {
494                 if (keyeq("monitorName", *t, json)) {
495                         (*t)++;
496                         char *name = copy_string(*t, json);
497                         loc->monitor = find_monitor(name);
498                         free(name);
499                 } else if (keyeq("desktopName", *t, json)) {
500                         (*t)++;
501                         char *name = copy_string(*t, json);
502                         loc->desktop = find_desktop_in(name, loc->monitor);
503                         free(name);
504                 } else if (keyeq("nodeId", *t, json)) {
505                         (*t)++;
506                         uint32_t id;
507                         sscanf(json + (*t)->start, "%u", &id);
508                         loc->node = find_by_id_in(loc->desktop!=NULL?loc->desktop->root:NULL, id);
509                 }
510                 (*t)++;
511         }
512 }
513
514 void restore_stack(jsmntok_t **t, char *json)
515 {
516         int s = (*t)->size;
517         (*t)++;
518
519         for (int i = 0; i < s; i++) {
520                 uint32_t id;
521                 sscanf(json + (*t)->start, "%u", &id);
522                 coordinates_t loc;
523                 if (locate_window(id, &loc)) {
524                         stack_insert_after(stack_tail, loc.node);
525                 }
526                 (*t)++;
527         }
528 }
529
530 void restore_wm_state(xcb_atom_t *w, jsmntok_t **t, char *json)
531 {
532         int s = (*t)->size;
533         (*t)++;
534
535         for (int i = 0; i < s; i++) {
536                 sscanf(json + (*t)->start, "%u", &w[i]);
537                 (*t)++;
538         }
539 }
540
541 #undef RESTORE_INT
542 #undef RESTORE_UINT
543 #undef RESTORE_USINT
544 #undef RESTORE_DOUBLE
545 #undef RESTORE_ANY
546 #undef RESTORE_BOOL
547
548 bool keyeq(char *s, jsmntok_t *key, char *json)
549 {
550         size_t n = key->end - key->start;
551         return (strlen(s) == n && strncmp(s, json + key->start, n) == 0);
552 }
553
554 char *copy_string(jsmntok_t *tok, char *json)
555 {
556         size_t len = tok->end - tok->start + 1;
557         char *res = malloc(len * sizeof(char));
558         if (res == NULL) {
559                 perror("Copy string: malloc");
560                 return NULL;
561         }
562         strncpy(res, json+tok->start, len-1);
563         res[len-1] = '\0';
564         return res;
565 }