]> git.lizzy.rs Git - bspwm.git/blob - src/restore.c
Allow (+|-)fraction in "node --ratio" command
[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
118         for (int i = 0; i < num; i++) {
119                 if (keyeq("focusedMonitorId", t, json)) {
120                         t++;
121                         sscanf(json + t->start, "%u", &focused_monitor_id);
122                 } else if (keyeq("primaryMonitorId", t, json)) {
123                         t++;
124                         sscanf(json + t->start, "%u", &primary_monitor_id);
125                 } else if (keyeq("clientsCount", t, json)) {
126                         t++;
127                         sscanf(json + t->start, "%u", &clients_count);
128                 } else if (keyeq("monitors", t, json)) {
129                         t++;
130                         int s = t->size;
131                         t++;
132                         for (int j = 0; j < s; j++) {
133                                 monitor_t *m = restore_monitor(&t, json);
134                                 if (m->desk == NULL) {
135                                         add_desktop(m, make_desktop(NULL, XCB_NONE));
136                                 }
137                                 add_monitor(m);
138                         }
139                         continue;
140                 } else if (keyeq("focusHistory", t, json)) {
141                         t++;
142                         restore_history(&t, json);
143                         continue;
144                 } else if (keyeq("stackingList", t, json)) {
145                         t++;
146                         restore_stack(&t, json);
147                         continue;
148                 }
149                 t++;
150         }
151
152         if (focused_monitor_id != 0) {
153                 coordinates_t loc;
154                 if (monitor_from_id(focused_monitor_id, &loc)) {
155                         mon = loc.monitor;
156                 }
157         }
158
159         if (primary_monitor_id != 0) {
160                 coordinates_t loc;
161                 if (monitor_from_id(primary_monitor_id, &loc)) {
162                         pri_mon = loc.monitor;
163                 }
164         }
165
166         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
167                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
168                         refresh_presel_feedbacks(m, d, d->root);
169                         restack_presel_feedbacks(d);
170                         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
171                                 if (n->client == NULL) {
172                                         continue;
173                                 }
174                                 initialize_client(n);
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                                 window_grab_buttons(n->id);
178                         }
179                 }
180         }
181
182         ewmh_update_client_list(false);
183         ewmh_update_client_list(true);
184         ewmh_update_active_window();
185         ewmh_update_number_of_desktops();
186         ewmh_update_current_desktop();
187         ewmh_update_desktop_names();
188         ewmh_update_desktop_viewport();
189
190         free(tokens);
191         free(json);
192
193         return true;
194 }
195
196 #define RESTORE_INT(k, p) \
197         } else if (keyeq(#k, *t, json)) { \
198                 (*t)++; \
199                 sscanf(json + (*t)->start, "%i", p);
200
201 #define RESTORE_UINT(k, p) \
202         } else if (keyeq(#k, *t, json)) { \
203                 (*t)++; \
204                 sscanf(json + (*t)->start, "%u", p);
205
206 #define RESTORE_USINT(k, p) \
207         } else if (keyeq(#k, *t, json)) { \
208                 (*t)++; \
209                 sscanf(json + (*t)->start, "%hu", p);
210
211 #define RESTORE_DOUBLE(k, p) \
212         } else if (keyeq(#k, *t, json)) { \
213                 (*t)++; \
214                 sscanf(json + (*t)->start, "%lf", p);
215
216 #define RESTORE_ANY(k, p, f) \
217         } else if (keyeq(#k, *t, json)) { \
218                 (*t)++; \
219                 char *val = copy_string(json + (*t)->start, (*t)->end - (*t)->start); \
220                 f(val, p); \
221                 free(val);
222
223 #define RESTORE_BOOL(k, p)  RESTORE_ANY(k, p, parse_bool)
224
225 monitor_t *restore_monitor(jsmntok_t **t, char *json)
226 {
227         int num = (*t)->size;
228         (*t)++;
229         monitor_t *m = make_monitor(NULL, NULL, UINT32_MAX);
230         uint32_t focused_desktop_id = 0;
231
232         for (int i = 0; i < num; i++) {
233                 if (keyeq("name", *t, json)) {
234                         (*t)++;
235                         snprintf(m->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
236                 RESTORE_UINT(id, &m->id)
237                 RESTORE_UINT(randrId, &m->randr_id)
238                 RESTORE_BOOL(wired, &m->wired)
239                 RESTORE_UINT(stickyCount, &m->sticky_count)
240                 RESTORE_INT(windowGap, &m->window_gap)
241                 RESTORE_UINT(borderWidth, &m->border_width)
242                 RESTORE_UINT(focusedDesktopId, &focused_desktop_id)
243                 } else if (keyeq("padding", *t, json)) {
244                         (*t)++;
245                         restore_padding(&m->padding, t, json);
246                         continue;
247                 } else if (keyeq("rectangle", *t, json)) {
248                         (*t)++;
249                         restore_rectangle(&m->rectangle, t, json);
250                         update_root(m, &m->rectangle);
251                         continue;
252                 } else if (keyeq("desktops", *t, json)) {
253                         (*t)++;
254                         int s = (*t)->size;
255                         (*t)++;
256                         for (int j = 0; j < s; j++) {
257                                 desktop_t *d = restore_desktop(t, json);
258                                 add_desktop(m, d);
259                         }
260                         continue;
261                 } else {
262                         warn("Restore monitor: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
263                         (*t)++;
264                 }
265                 (*t)++;
266         }
267
268         if (focused_desktop_id != 0) {
269                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
270                         if (d->id == focused_desktop_id) {
271                                 m->desk = d;
272                                 break;
273                         }
274                 }
275         }
276
277         return m;
278 }
279
280 desktop_t *restore_desktop(jsmntok_t **t, char *json)
281 {
282         int s = (*t)->size;
283         (*t)++;
284         desktop_t *d = make_desktop(NULL, UINT32_MAX);
285         xcb_window_t focusedNodeId = XCB_NONE;
286
287         for (int i = 0; i < s; i++) {
288                 if (keyeq("name", *t, json)) {
289                         (*t)++;
290                         snprintf(d->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
291                 RESTORE_UINT(id, &d->id)
292                 RESTORE_ANY(layout, &d->layout, parse_layout)
293                 RESTORE_INT(windowGap, &d->window_gap)
294                 RESTORE_UINT(borderWidth, &d->border_width)
295                 } else if (keyeq("focusedNodeId", *t, json)) {
296                         (*t)++;
297                         sscanf(json + (*t)->start, "%u", &focusedNodeId);
298                 } else if (keyeq("padding", *t, json)) {
299                         (*t)++;
300                         restore_padding(&d->padding, t, json);
301                         continue;
302                 } else if (keyeq("root", *t, json)) {
303                         (*t)++;
304                         d->root = restore_node(t, json);
305                         continue;
306                 } else {
307                         warn("Restore desktop: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
308                         (*t)++;
309                 }
310                 (*t)++;
311         }
312
313         if (focusedNodeId != XCB_NONE) {
314                 d->focus = find_by_id_in(d->root, focusedNodeId);
315         }
316
317         return d;
318 }
319
320 node_t *restore_node(jsmntok_t **t, char *json)
321 {
322         if ((*t)->type == JSMN_PRIMITIVE) {
323                 (*t)++;
324                 return NULL;
325         } else {
326                 int s = (*t)->size;
327                 (*t)++;
328                 /* hack to prevent a new ID from being generated */
329                 node_t *n = make_node(UINT32_MAX);
330
331                 for (int i = 0; i < s; i++) {
332                         if (keyeq("id", *t, json)) {
333                                 (*t)++;
334                                 sscanf(json + (*t)->start, "%u", &n->id);
335                         RESTORE_ANY(splitType, &n->split_type, parse_split_type)
336                         RESTORE_DOUBLE(splitRatio, &n->split_ratio)
337                         RESTORE_INT(birthRotation, &n->birth_rotation)
338                         RESTORE_BOOL(vacant, &n->vacant)
339                         RESTORE_BOOL(hidden, &n->hidden)
340                         RESTORE_BOOL(sticky, &n->sticky)
341                         RESTORE_BOOL(private, &n->private)
342                         RESTORE_BOOL(locked, &n->locked)
343                         } else if (keyeq("presel", *t, json)) {
344                                 (*t)++;
345                                 n->presel = restore_presel(t, json);
346                                 continue;
347                         } else if (keyeq("rectangle", *t, json)) {
348                                 (*t)++;
349                                 restore_rectangle(&n->rectangle, t, json);
350                                 continue;
351                         } else if (keyeq("firstChild", *t, json)) {
352                                 (*t)++;
353                                 node_t *fc = restore_node(t, json);
354                                 n->first_child = fc;
355                                 if (fc != NULL) {
356                                         fc->parent = n;
357                                 }
358                                 continue;
359                         } else if (keyeq("secondChild", *t, json)) {
360                                 (*t)++;
361                                 node_t *sc = restore_node(t, json);
362                                 n->second_child = sc;
363                                 if (sc != NULL) {
364                                         sc->parent = n;
365                                 }
366                                 continue;
367                         } else if (keyeq("client", *t, json)) {
368                                 (*t)++;
369                                 n->client = restore_client(t, json);
370                                 continue;
371                         } else {
372                                 warn("Restore node: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
373                                 (*t)++;
374                         }
375                         (*t)++;
376                 }
377
378                 return n;
379         }
380 }
381
382 presel_t *restore_presel(jsmntok_t **t, char *json)
383 {
384         if ((*t)->type == JSMN_PRIMITIVE) {
385                 (*t)++;
386                 return NULL;
387         } else {
388                 int s = (*t)->size;
389                 (*t)++;
390                 presel_t *p = make_presel();
391
392                 for (int i = 0; i < s; i++) {
393                         if (keyeq("splitRatio", *t, json)) {
394                                 (*t)++;
395                                 sscanf(json + (*t)->start, "%lf", &p->split_ratio);
396                         RESTORE_ANY(splitDir, &p->split_dir, parse_direction)
397                         }
398
399                         (*t)++;
400                 }
401
402                 return p;
403         }
404 }
405
406
407 client_t *restore_client(jsmntok_t **t, char *json)
408 {
409         if ((*t)->type == JSMN_PRIMITIVE) {
410                 (*t)++;
411                 return NULL;
412         } else {
413                 int s = (*t)->size;
414                 (*t)++;
415                 client_t *c = make_client();
416
417                 for (int i = 0; i < s; i++) {
418                         if (keyeq("className", *t, json)) {
419                                 (*t)++;
420                                 snprintf(c->class_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
421                         } else if (keyeq("instanceName", *t, json)) {
422                                 (*t)++;
423                                 snprintf(c->instance_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
424                         RESTORE_ANY(state, &c->state, parse_client_state)
425                         RESTORE_ANY(lastState, &c->last_state, parse_client_state)
426                         RESTORE_ANY(layer, &c->layer, parse_stack_layer)
427                         RESTORE_ANY(lastLayer, &c->last_layer, parse_stack_layer)
428                         RESTORE_UINT(borderWidth, &c->border_width)
429                         RESTORE_BOOL(urgent, &c->urgent)
430                         RESTORE_BOOL(shown, &c->shown)
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_padding(padding_t *p, 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("top", *t, json)) {
481                         (*t)++;
482                         sscanf(json + (*t)->start, "%i", &p->top);
483                 } else if (keyeq("right", *t, json)) {
484                         (*t)++;
485                         sscanf(json + (*t)->start, "%i", &p->right);
486                 } else if (keyeq("bottom", *t, json)) {
487                         (*t)++;
488                         sscanf(json + (*t)->start, "%i", &p->bottom);
489                 } else if (keyeq("left", *t, json)) {
490                         (*t)++;
491                         sscanf(json + (*t)->start, "%i", &p->left);
492                 }
493                 (*t)++;
494         }
495 }
496
497 void restore_history(jsmntok_t **t, char *json)
498 {
499         int s = (*t)->size;
500         (*t)++;
501
502         for (int i = 0; i < s; i++) {
503                 coordinates_t loc = {NULL, NULL, NULL};
504                 restore_coordinates(&loc, t, json);
505                 if (loc.monitor != NULL && loc.desktop != NULL) {
506                         history_add(loc.monitor, loc.desktop, loc.node);
507                 }
508         }
509 }
510
511 void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json)
512 {
513         int s = (*t)->size;
514         (*t)++;
515         uint32_t id = 0;
516
517         for (int i = 0; i < s; i++) {
518                 if (keyeq("monitorId", *t, json)) {
519                         (*t)++;
520                         sscanf(json + (*t)->start, "%u", &id);
521                         loc->monitor = find_monitor(id);
522                 } else if (keyeq("desktopId", *t, json)) {
523                         (*t)++;
524                         sscanf(json + (*t)->start, "%u", &id);
525                         loc->desktop = find_desktop_in(id, loc->monitor);
526                 } else if (keyeq("nodeId", *t, json)) {
527                         (*t)++;
528                         sscanf(json + (*t)->start, "%u", &id);
529                         loc->node = find_by_id_in(loc->desktop != NULL ? loc->desktop->root : NULL, id);
530                 }
531                 (*t)++;
532         }
533 }
534
535 void restore_stack(jsmntok_t **t, char *json)
536 {
537         int s = (*t)->size;
538         (*t)++;
539
540         for (int i = 0; i < s; i++) {
541                 uint32_t id;
542                 sscanf(json + (*t)->start, "%u", &id);
543                 coordinates_t loc;
544                 if (locate_window(id, &loc)) {
545                         stack_insert_after(stack_tail, loc.node);
546                 }
547                 (*t)++;
548         }
549 }
550
551 #undef RESTORE_INT
552 #undef RESTORE_UINT
553 #undef RESTORE_USINT
554 #undef RESTORE_DOUBLE
555 #undef RESTORE_ANY
556 #undef RESTORE_BOOL
557
558 bool keyeq(char *s, jsmntok_t *key, char *json)
559 {
560         size_t n = key->end - key->start;
561         return (strlen(s) == n && strncmp(s, json + key->start, n) == 0);
562 }