]> git.lizzy.rs Git - bspwm.git/blob - restore.c
Fail verbosely
[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, *primaryMonitorName = NULL;
116
117         for (int i = 0; i < num; i++) {
118                 if (keyeq("focusedMonitorName", t, json)) {
119                         free(focusedMonitorName);
120                         t++;
121                         focusedMonitorName = copy_string(json + t->start, t->end - t->start);
122                 } else if (keyeq("primaryMonitorName", t, json)) {
123                         free(primaryMonitorName);
124                         t++;
125                         primaryMonitorName = copy_string(json + t->start, t->end - t->start);
126                 } else if (keyeq("clientsCount", t, json)) {
127                         t++;
128                         sscanf(json + t->start, "%u", &clients_count);
129                 } else if (keyeq("monitors", t, json)) {
130                         t++;
131                         int s = t->size;
132                         t++;
133                         for (int j = 0; j < s; j++) {
134                                 monitor_t *m = restore_monitor(&t, json);
135                                 if (m->desk == NULL) {
136                                         add_desktop(m, make_desktop(NULL, XCB_NONE));
137                                 }
138                                 add_monitor(m);
139                         }
140                         continue;
141                 } else if (keyeq("focusHistory", t, json)) {
142                         t++;
143                         restore_history(&t, json);
144                         continue;
145                 } else if (keyeq("stackingList", t, json)) {
146                         t++;
147                         restore_stack(&t, json);
148                         continue;
149                 }
150                 t++;
151         }
152
153         if (focusedMonitorName != NULL) {
154                 coordinates_t loc;
155                 if (locate_monitor(focusedMonitorName, &loc)) {
156                         mon = loc.monitor;
157                 }
158         }
159
160         if (primaryMonitorName != NULL) {
161                 coordinates_t loc;
162                 if (locate_monitor(primaryMonitorName, &loc)) {
163                         pri_mon = loc.monitor;
164                 }
165         }
166
167         free(focusedMonitorName);
168         free(primaryMonitorName);
169
170         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
171                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
172                         refresh_presel_feebacks_in(d->root, d, m);
173                         restack_presel_feedback(d);
174                         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
175                                 uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
176                                 xcb_change_window_attributes(dpy, n->id, XCB_CW_EVENT_MASK, values);
177                         }
178                 }
179         }
180
181         ewmh_update_client_list(false);
182         ewmh_update_client_list(true);
183         ewmh_update_active_window();
184         ewmh_update_number_of_desktops();
185         ewmh_update_current_desktop();
186         ewmh_update_desktop_names();
187
188         free(tokens);
189         free(json);
190
191         return true;
192 }
193
194 #define RESTORE_INT(k, p) \
195         } else if (keyeq(#k, *t, json)) { \
196                 (*t)++; \
197                 sscanf(json + (*t)->start, "%i", p);
198
199 #define RESTORE_UINT(k, p) \
200         } else if (keyeq(#k, *t, json)) { \
201                 (*t)++; \
202                 sscanf(json + (*t)->start, "%u", p);
203
204 #define RESTORE_USINT(k, p) \
205         } else if (keyeq(#k, *t, json)) { \
206                 (*t)++; \
207                 sscanf(json + (*t)->start, "%hu", p);
208
209 #define RESTORE_DOUBLE(k, p) \
210         } else if (keyeq(#k, *t, json)) { \
211                 (*t)++; \
212                 sscanf(json + (*t)->start, "%lf", p);
213
214 #define RESTORE_ANY(k, p, f) \
215         } else if (keyeq(#k, *t, json)) { \
216                 (*t)++; \
217                 char *val = copy_string(json + (*t)->start, (*t)->end - (*t)->start); \
218                 f(val, p); \
219                 free(val);
220
221 #define RESTORE_BOOL(k, p)  RESTORE_ANY(k, p, parse_bool)
222
223 monitor_t *restore_monitor(jsmntok_t **t, char *json)
224 {
225         int num = (*t)->size;
226         (*t)++;
227         monitor_t *m = make_monitor(NULL, UINT32_MAX);
228         char *focusedDesktopName = NULL;
229
230         for (int i = 0; i < num; i++) {
231                 if (keyeq("name", *t, json)) {
232                         (*t)++;
233                         snprintf(m->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
234                 RESTORE_UINT(id, &m->id)
235                 RESTORE_UINT(randrId, &m->randr_id)
236                 RESTORE_BOOL(wired, &m->wired)
237                 RESTORE_UINT(stickyCount, &m->sticky_count)
238                 RESTORE_INT(windowGap, &m->window_gap)
239                 RESTORE_UINT(borderWidth, &m->border_width)
240                 } else if (keyeq("padding", *t, json)) {
241                         (*t)++;
242                         restore_padding(&m->padding, t, json);
243                         continue;
244                 } else if (keyeq("rectangle", *t, json)) {
245                         (*t)++;
246                         restore_rectangle(&m->rectangle, t, json);
247                         update_root(m, &m->rectangle);
248                         continue;
249                 } else if (keyeq("focusedDesktopName", *t, json)) {
250                         free(focusedDesktopName);
251                         (*t)++;
252                         focusedDesktopName = copy_string(json + (*t)->start, (*t)->end - (*t)->start);
253                 } else if (keyeq("desktops", *t, json)) {
254                         (*t)++;
255                         int s = (*t)->size;
256                         (*t)++;
257                         for (int j = 0; j < s; j++) {
258                                 desktop_t *d = restore_desktop(t, json);
259                                 add_desktop(m, d);
260                         }
261                         continue;
262                 } else {
263                         warn("Restore monitor: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
264                         (*t)++;
265                 }
266                 (*t)++;
267         }
268
269         if (focusedDesktopName != NULL) {
270                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
271                         if (streq(focusedDesktopName, d->name)) {
272                                 m->desk = d;
273                                 break;
274                         }
275                 }
276         }
277
278         free(focusedDesktopName);
279
280         return m;
281 }
282
283 desktop_t *restore_desktop(jsmntok_t **t, char *json)
284 {
285         int s = (*t)->size;
286         (*t)++;
287         desktop_t *d = make_desktop(NULL, UINT32_MAX);
288         xcb_window_t focusedNodeId = XCB_NONE;
289
290         for (int i = 0; i < s; i++) {
291                 if (keyeq("name", *t, json)) {
292                         (*t)++;
293                         snprintf(d->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
294                 RESTORE_UINT(id, &d->id)
295                 RESTORE_ANY(layout, &d->layout, parse_layout)
296                 RESTORE_INT(windowGap, &d->window_gap)
297                 RESTORE_UINT(borderWidth, &d->border_width)
298                 } else if (keyeq("focusedNodeId", *t, json)) {
299                         (*t)++;
300                         sscanf(json + (*t)->start, "%u", &focusedNodeId);
301                 } else if (keyeq("padding", *t, json)) {
302                         (*t)++;
303                         restore_padding(&d->padding, t, json);
304                         continue;
305                 } else if (keyeq("root", *t, json)) {
306                         (*t)++;
307                         d->root = restore_node(t, json);
308                         continue;
309                 } else {
310                         warn("Restore desktop: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
311                         (*t)++;
312                 }
313                 (*t)++;
314         }
315
316         if (focusedNodeId != XCB_NONE) {
317                 d->focus = find_by_id_in(d->root, focusedNodeId);
318         }
319
320         return d;
321 }
322
323 node_t *restore_node(jsmntok_t **t, char *json)
324 {
325         if ((*t)->type == JSMN_PRIMITIVE) {
326                 (*t)++;
327                 return NULL;
328         } else {
329                 int s = (*t)->size;
330                 (*t)++;
331                 /* hack to prevent a new ID from being generated */
332                 node_t *n = make_node(UINT32_MAX);
333
334                 for (int i = 0; i < s; i++) {
335                         if (keyeq("id", *t, json)) {
336                                 (*t)++;
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_BOOL(vacant, &n->vacant)
342                         RESTORE_BOOL(sticky, &n->sticky)
343                         RESTORE_BOOL(private, &n->private)
344                         RESTORE_BOOL(locked, &n->locked)
345                         } else if (keyeq("presel", *t, json)) {
346                                 (*t)++;
347                                 n->presel = restore_presel(t, json);
348                                 continue;
349                         } else if (keyeq("rectangle", *t, json)) {
350                                 (*t)++;
351                                 restore_rectangle(&n->rectangle, t, json);
352                                 continue;
353                         } else if (keyeq("firstChild", *t, json)) {
354                                 (*t)++;
355                                 node_t *fc = restore_node(t, json);
356                                 n->first_child = fc;
357                                 if (fc != NULL) {
358                                         fc->parent = n;
359                                 }
360                                 continue;
361                         } else if (keyeq("secondChild", *t, json)) {
362                                 (*t)++;
363                                 node_t *sc = restore_node(t, json);
364                                 n->second_child = sc;
365                                 if (sc != NULL) {
366                                         sc->parent = n;
367                                 }
368                                 continue;
369                         } else if (keyeq("client", *t, json)) {
370                                 (*t)++;
371                                 n->client = restore_client(t, json);
372                                 continue;
373                         } else {
374                                 warn("Restore node: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
375                                 (*t)++;
376                         }
377                         (*t)++;
378                 }
379
380                 return n;
381         }
382 }
383
384 presel_t *restore_presel(jsmntok_t **t, char *json)
385 {
386         if ((*t)->type == JSMN_PRIMITIVE) {
387                 (*t)++;
388                 return NULL;
389         } else {
390                 int s = (*t)->size;
391                 (*t)++;
392                 presel_t *p = make_presel();
393
394                 for (int i = 0; i < s; i++) {
395                         if (keyeq("splitRatio", *t, json)) {
396                                 (*t)++;
397                                 sscanf(json + (*t)->start, "%lf", &p->split_ratio);
398                         RESTORE_ANY(splitDir, &p->split_dir, parse_direction)
399                         }
400
401                         (*t)++;
402                 }
403
404                 return p;
405         }
406 }
407
408
409 client_t *restore_client(jsmntok_t **t, char *json)
410 {
411         if ((*t)->type == JSMN_PRIMITIVE) {
412                 (*t)++;
413                 return NULL;
414         } else {
415                 int s = (*t)->size;
416                 (*t)++;
417                 client_t *c = make_client();
418
419                 for (int i = 0; i < s; i++) {
420                         if (keyeq("className", *t, json)) {
421                                 (*t)++;
422                                 snprintf(c->class_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
423                         } else if (keyeq("instanceName", *t, json)) {
424                                 (*t)++;
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(visible, &c->visible)
433                         RESTORE_BOOL(icccmFocus, &c->icccm_focus)
434                         RESTORE_BOOL(icccmInput, &c->icccm_input)
435                         RESTORE_USINT(minWidth, &c->min_width)
436                         RESTORE_USINT(maxWidth, &c->max_width)
437                         RESTORE_USINT(minHeight, &c->min_height)
438                         RESTORE_USINT(maxHeight, &c->max_height)
439                         RESTORE_INT(wmStatesCount, &c->wm_states_count)
440                         } else if (keyeq("wmState", *t, json)) {
441                                 (*t)++;
442                                 restore_wm_state(c->wm_state, t, json);
443                                 continue;
444                         } else if (keyeq("tiledRectangle", *t, json)) {
445                                 (*t)++;
446                                 restore_rectangle(&c->tiled_rectangle, t, json);
447                                 continue;
448                         } else if (keyeq("floatingRectangle", *t, json)) {
449                                 (*t)++;
450                                 restore_rectangle(&c->floating_rectangle, t, json);
451                                 continue;
452                         } else {
453                                 warn("Restore client: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
454                                 (*t)++;
455                         }
456
457                         (*t)++;
458                 }
459
460                 return c;
461         }
462 }
463
464 void restore_rectangle(xcb_rectangle_t *r, jsmntok_t **t, char *json)
465 {
466         int s = (*t)->size;
467         (*t)++;
468
469         for (int i = 0; i < s; i++) {
470                 if (keyeq("x", *t, json)) {
471                         (*t)++;
472                         sscanf(json + (*t)->start, "%hi", &r->x);
473                 } else if (keyeq("y", *t, json)) {
474                         (*t)++;
475                         sscanf(json + (*t)->start, "%hi", &r->y);
476                 } else if (keyeq("width", *t, json)) {
477                         (*t)++;
478                         sscanf(json + (*t)->start, "%hu", &r->width);
479                 } else if (keyeq("height", *t, json)) {
480                         (*t)++;
481                         sscanf(json + (*t)->start, "%hu", &r->height);
482                 }
483                 (*t)++;
484         }
485 }
486
487 void restore_padding(padding_t *p, jsmntok_t **t, char *json)
488 {
489         int s = (*t)->size;
490         (*t)++;
491
492         for (int i = 0; i < s; i++) {
493                 if (keyeq("top", *t, json)) {
494                         (*t)++;
495                         sscanf(json + (*t)->start, "%i", &p->top);
496                 } else if (keyeq("right", *t, json)) {
497                         (*t)++;
498                         sscanf(json + (*t)->start, "%i", &p->right);
499                 } else if (keyeq("bottom", *t, json)) {
500                         (*t)++;
501                         sscanf(json + (*t)->start, "%i", &p->bottom);
502                 } else if (keyeq("left", *t, json)) {
503                         (*t)++;
504                         sscanf(json + (*t)->start, "%i", &p->left);
505                 }
506                 (*t)++;
507         }
508 }
509
510 void restore_history(jsmntok_t **t, char *json)
511 {
512         int s = (*t)->size;
513         (*t)++;
514
515         for (int i = 0; i < s; i++) {
516                 coordinates_t loc = {NULL, NULL, NULL};
517                 restore_coordinates(&loc, t, json);
518                 if (loc.monitor != NULL && loc.desktop != NULL) {
519                         history_add(loc.monitor, loc.desktop, loc.node);
520                 }
521         }
522 }
523
524 void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json)
525 {
526         int s = (*t)->size;
527         (*t)++;
528
529         for (int i = 0; i < s; i++) {
530                 if (keyeq("monitorName", *t, json)) {
531                         (*t)++;
532                         char *name = copy_string(json + (*t)->start, (*t)->end - (*t)->start);
533                         loc->monitor = find_monitor(name);
534                         free(name);
535                 } else if (keyeq("desktopName", *t, json)) {
536                         (*t)++;
537                         char *name = copy_string(json + (*t)->start, (*t)->end - (*t)->start);
538                         loc->desktop = find_desktop_in(name, loc->monitor);
539                         free(name);
540                 } else if (keyeq("nodeId", *t, json)) {
541                         (*t)++;
542                         uint32_t id;
543                         sscanf(json + (*t)->start, "%u", &id);
544                         loc->node = find_by_id_in(loc->desktop!=NULL?loc->desktop->root:NULL, id);
545                 }
546                 (*t)++;
547         }
548 }
549
550 void restore_stack(jsmntok_t **t, char *json)
551 {
552         int s = (*t)->size;
553         (*t)++;
554
555         for (int i = 0; i < s; i++) {
556                 uint32_t id;
557                 sscanf(json + (*t)->start, "%u", &id);
558                 coordinates_t loc;
559                 if (locate_window(id, &loc)) {
560                         stack_insert_after(stack_tail, loc.node);
561                 }
562                 (*t)++;
563         }
564 }
565
566 void restore_wm_state(xcb_atom_t *w, jsmntok_t **t, char *json)
567 {
568         int s = (*t)->size;
569         (*t)++;
570
571         for (int i = 0; i < s; i++) {
572                 sscanf(json + (*t)->start, "%u", &w[i]);
573                 (*t)++;
574         }
575 }
576
577 #undef RESTORE_INT
578 #undef RESTORE_UINT
579 #undef RESTORE_USINT
580 #undef RESTORE_DOUBLE
581 #undef RESTORE_ANY
582 #undef RESTORE_BOOL
583
584 bool keyeq(char *s, jsmntok_t *key, char *json)
585 {
586         size_t n = key->end - key->start;
587         return (strlen(s) == n && strncmp(s, json + key->start, n) == 0);
588 }