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