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