i3
load_layout.c
Go to the documentation of this file.
1 #undef I3__FILE__
2 #define I3__FILE__ "load_layout.c"
3 /*
4  * vim:ts=4:sw=4:expandtab
5  *
6  * i3 - an improved dynamic tiling window manager
7  * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
8  *
9  * load_layout.c: Restore (parts of) the layout, for example after an inplace
10  * restart.
11  *
12  */
13 #include "all.h"
14 
15 #include <yajl/yajl_common.h>
16 #include <yajl/yajl_gen.h>
17 #include <yajl/yajl_parse.h>
18 #include <yajl/yajl_version.h>
19 
20 /* TODO: refactor the whole parsing thing */
21 
22 static char *last_key;
23 static Con *json_node;
24 static Con *to_focus;
25 static bool parsing_swallows;
26 static bool parsing_rect;
27 static bool parsing_deco_rect;
28 static bool parsing_window_rect;
29 static bool parsing_geometry;
30 static bool parsing_focus;
32 
33 /* This list is used for reordering the focus stack after parsing the 'focus'
34  * array. */
35 struct focus_mapping {
36  int old_id;
37  TAILQ_ENTRY(focus_mapping) focus_mappings;
38 };
39 
40 static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings =
41  TAILQ_HEAD_INITIALIZER(focus_mappings);
42 
43 static int json_start_map(void *ctx) {
44  LOG("start of map, last_key = %s\n", last_key);
45  if (parsing_swallows) {
46  LOG("creating new swallow\n");
47  current_swallow = smalloc(sizeof(Match));
48  match_init(current_swallow);
49  TAILQ_INSERT_TAIL(&(json_node->swallow_head), current_swallow, matches);
50  } else {
52  if (last_key && strcasecmp(last_key, "floating_nodes") == 0) {
53  DLOG("New floating_node\n");
54  Con *ws = con_get_workspace(json_node);
55  json_node = con_new_skeleton(NULL, NULL);
56  json_node->name = NULL;
57  json_node->parent = ws;
58  DLOG("Parent is workspace = %p\n", ws);
59  } else {
60  Con *parent = json_node;
61  json_node = con_new_skeleton(NULL, NULL);
62  json_node->name = NULL;
63  json_node->parent = parent;
64  }
65  }
66  }
67  return 1;
68 }
69 
70 static int json_end_map(void *ctx) {
71  LOG("end of map\n");
73  /* Set a few default values to simplify manually crafted layout files. */
74  if (json_node->layout == L_DEFAULT) {
75  DLOG("Setting layout = L_SPLITH\n");
76  json_node->layout = L_SPLITH;
77  }
78 
79  /* Sanity check: swallow criteria don’t make any sense on a split
80  * container. */
81  if (con_is_split(json_node) > 0 && !TAILQ_EMPTY(&(json_node->swallow_head))) {
82  DLOG("sanity check: removing swallows specification from split container\n");
83  while (!TAILQ_EMPTY(&(json_node->swallow_head))) {
84  Match *match = TAILQ_FIRST(&(json_node->swallow_head));
85  TAILQ_REMOVE(&(json_node->swallow_head), match, matches);
86  match_free(match);
87  }
88  }
89 
90  if (json_node->type == CT_WORKSPACE) {
91  /* Ensure the workspace has a name. */
92  DLOG("Attaching workspace. name = %s\n", json_node->name);
93  if (json_node->name == NULL || strcmp(json_node->name, "") == 0) {
94  json_node->name = sstrdup("unnamed");
95  }
96 
97  /* Prevent name clashes when appending a workspace, e.g. when the
98  * user tries to restore a workspace called “1” but already has a
99  * workspace called “1”. */
100  Con *output;
101  Con *workspace = NULL;
102  TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
103  GREP_FIRST(workspace, output_get_content(output), !strcasecmp(child->name, json_node->name));
104  char *base = sstrdup(json_node->name);
105  int cnt = 1;
106  while (workspace != NULL) {
107  FREE(json_node->name);
108  sasprintf(&(json_node->name), "%s_%d", base, cnt++);
109  workspace = NULL;
110  TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
111  GREP_FIRST(workspace, output_get_content(output), !strcasecmp(child->name, json_node->name));
112  }
113  free(base);
114 
115  /* Set num accordingly so that i3bar will properly sort it. */
116  json_node->num = ws_name_to_number(json_node->name);
117  }
118 
119  LOG("attaching\n");
120  con_attach(json_node, json_node->parent, true);
121  LOG("Creating window\n");
122  x_con_init(json_node, json_node->depth);
123  json_node = json_node->parent;
124  }
125 
126  parsing_rect = false;
127  parsing_deco_rect = false;
128  parsing_window_rect = false;
129  parsing_geometry = false;
130  return 1;
131 }
132 
133 static int json_end_array(void *ctx) {
134  LOG("end of array\n");
135  if (!parsing_swallows && !parsing_focus) {
136  con_fix_percent(json_node);
137  }
138  if (parsing_swallows) {
139  parsing_swallows = false;
140  }
141  if (parsing_focus) {
142  /* Clear the list of focus mappings */
143  struct focus_mapping *mapping;
144  TAILQ_FOREACH_REVERSE(mapping, &focus_mappings, focus_mappings_head, focus_mappings) {
145  LOG("focus (reverse) %d\n", mapping->old_id);
146  Con *con;
147  TAILQ_FOREACH(con, &(json_node->focus_head), focused) {
148  if (con->old_id != mapping->old_id)
149  continue;
150  LOG("got it! %p\n", con);
151  /* Move this entry to the top of the focus list. */
152  TAILQ_REMOVE(&(json_node->focus_head), con, focused);
153  TAILQ_INSERT_HEAD(&(json_node->focus_head), con, focused);
154  break;
155  }
156  }
157  while (!TAILQ_EMPTY(&focus_mappings)) {
158  mapping = TAILQ_FIRST(&focus_mappings);
159  TAILQ_REMOVE(&focus_mappings, mapping, focus_mappings);
160  free(mapping);
161  }
162  parsing_focus = false;
163  }
164  return 1;
165 }
166 
167 static int json_key(void *ctx, const unsigned char *val, size_t len) {
168  LOG("key: %.*s\n", (int)len, val);
169  FREE(last_key);
170  last_key = scalloc((len + 1) * sizeof(char));
171  memcpy(last_key, val, len);
172  if (strcasecmp(last_key, "swallows") == 0)
173  parsing_swallows = true;
174 
175  if (strcasecmp(last_key, "rect") == 0)
176  parsing_rect = true;
177 
178  if (strcasecmp(last_key, "deco_rect") == 0)
179  parsing_deco_rect = true;
180 
181  if (strcasecmp(last_key, "window_rect") == 0)
182  parsing_window_rect = true;
183 
184  if (strcasecmp(last_key, "geometry") == 0)
185  parsing_geometry = true;
186 
187  if (strcasecmp(last_key, "focus") == 0)
188  parsing_focus = true;
189 
190  return 1;
191 }
192 
193 static int json_string(void *ctx, const unsigned char *val, size_t len) {
194  LOG("string: %.*s for key %s\n", (int)len, val, last_key);
195  if (parsing_swallows) {
196  char *sval;
197  sasprintf(&sval, "%.*s", len, val);
198  if (strcasecmp(last_key, "class") == 0) {
199  current_swallow->class = regex_new(sval);
200  } else if (strcasecmp(last_key, "instance") == 0) {
201  current_swallow->instance = regex_new(sval);
202  } else if (strcasecmp(last_key, "window_role") == 0) {
203  current_swallow->window_role = regex_new(sval);
204  } else if (strcasecmp(last_key, "title") == 0) {
205  current_swallow->title = regex_new(sval);
206  } else {
207  ELOG("swallow key %s unknown\n", last_key);
208  }
209  free(sval);
210  } else {
211  if (strcasecmp(last_key, "name") == 0) {
212  json_node->name = scalloc((len + 1) * sizeof(char));
213  memcpy(json_node->name, val, len);
214  } else if (strcasecmp(last_key, "sticky_group") == 0) {
215  json_node->sticky_group = scalloc((len + 1) * sizeof(char));
216  memcpy(json_node->sticky_group, val, len);
217  LOG("sticky_group of this container is %s\n", json_node->sticky_group);
218  } else if (strcasecmp(last_key, "orientation") == 0) {
219  /* Upgrade path from older versions of i3 (doing an inplace restart
220  * to a newer version):
221  * "orientation" is dumped before "layout". Therefore, we store
222  * whether the orientation was horizontal or vertical in the
223  * last_split_layout. When we then encounter layout == "default",
224  * we will use the last_split_layout as layout instead. */
225  char *buf = NULL;
226  sasprintf(&buf, "%.*s", (int)len, val);
227  if (strcasecmp(buf, "none") == 0 ||
228  strcasecmp(buf, "horizontal") == 0)
229  json_node->last_split_layout = L_SPLITH;
230  else if (strcasecmp(buf, "vertical") == 0)
231  json_node->last_split_layout = L_SPLITV;
232  else
233  LOG("Unhandled orientation: %s\n", buf);
234  free(buf);
235  } else if (strcasecmp(last_key, "border") == 0) {
236  char *buf = NULL;
237  sasprintf(&buf, "%.*s", (int)len, val);
238  if (strcasecmp(buf, "none") == 0)
239  json_node->border_style = BS_NONE;
240  else if (strcasecmp(buf, "1pixel") == 0) {
241  json_node->border_style = BS_PIXEL;
242  json_node->current_border_width = 1;
243  } else if (strcasecmp(buf, "pixel") == 0)
244  json_node->border_style = BS_PIXEL;
245  else if (strcasecmp(buf, "normal") == 0)
246  json_node->border_style = BS_NORMAL;
247  else
248  LOG("Unhandled \"border\": %s\n", buf);
249  free(buf);
250  } else if (strcasecmp(last_key, "type") == 0) {
251  char *buf = NULL;
252  sasprintf(&buf, "%.*s", (int)len, val);
253  if (strcasecmp(buf, "root") == 0)
254  json_node->type = CT_ROOT;
255  else if (strcasecmp(buf, "output") == 0)
256  json_node->type = CT_OUTPUT;
257  else if (strcasecmp(buf, "con") == 0)
258  json_node->type = CT_CON;
259  else if (strcasecmp(buf, "floating_con") == 0)
260  json_node->type = CT_FLOATING_CON;
261  else if (strcasecmp(buf, "workspace") == 0)
262  json_node->type = CT_WORKSPACE;
263  else if (strcasecmp(buf, "dockarea") == 0)
264  json_node->type = CT_DOCKAREA;
265  else
266  LOG("Unhandled \"type\": %s\n", buf);
267  free(buf);
268  } else if (strcasecmp(last_key, "layout") == 0) {
269  char *buf = NULL;
270  sasprintf(&buf, "%.*s", (int)len, val);
271  if (strcasecmp(buf, "default") == 0)
272  /* This set above when we read "orientation". */
273  json_node->layout = json_node->last_split_layout;
274  else if (strcasecmp(buf, "stacked") == 0)
275  json_node->layout = L_STACKED;
276  else if (strcasecmp(buf, "tabbed") == 0)
277  json_node->layout = L_TABBED;
278  else if (strcasecmp(buf, "dockarea") == 0)
279  json_node->layout = L_DOCKAREA;
280  else if (strcasecmp(buf, "output") == 0)
281  json_node->layout = L_OUTPUT;
282  else if (strcasecmp(buf, "splith") == 0)
283  json_node->layout = L_SPLITH;
284  else if (strcasecmp(buf, "splitv") == 0)
285  json_node->layout = L_SPLITV;
286  else
287  LOG("Unhandled \"layout\": %s\n", buf);
288  free(buf);
289  } else if (strcasecmp(last_key, "workspace_layout") == 0) {
290  char *buf = NULL;
291  sasprintf(&buf, "%.*s", (int)len, val);
292  if (strcasecmp(buf, "default") == 0)
293  json_node->workspace_layout = L_DEFAULT;
294  else if (strcasecmp(buf, "stacked") == 0)
295  json_node->workspace_layout = L_STACKED;
296  else if (strcasecmp(buf, "tabbed") == 0)
297  json_node->workspace_layout = L_TABBED;
298  else
299  LOG("Unhandled \"workspace_layout\": %s\n", buf);
300  free(buf);
301  } else if (strcasecmp(last_key, "last_split_layout") == 0) {
302  char *buf = NULL;
303  sasprintf(&buf, "%.*s", (int)len, val);
304  if (strcasecmp(buf, "splith") == 0)
305  json_node->last_split_layout = L_SPLITH;
306  else if (strcasecmp(buf, "splitv") == 0)
307  json_node->last_split_layout = L_SPLITV;
308  else
309  LOG("Unhandled \"last_splitlayout\": %s\n", buf);
310  free(buf);
311  } else if (strcasecmp(last_key, "mark") == 0) {
312  char *buf = NULL;
313  sasprintf(&buf, "%.*s", (int)len, val);
314  json_node->mark = buf;
315  } else if (strcasecmp(last_key, "floating") == 0) {
316  char *buf = NULL;
317  sasprintf(&buf, "%.*s", (int)len, val);
318  if (strcasecmp(buf, "auto_off") == 0)
319  json_node->floating = FLOATING_AUTO_OFF;
320  else if (strcasecmp(buf, "auto_on") == 0)
321  json_node->floating = FLOATING_AUTO_ON;
322  else if (strcasecmp(buf, "user_off") == 0)
323  json_node->floating = FLOATING_USER_OFF;
324  else if (strcasecmp(buf, "user_on") == 0)
325  json_node->floating = FLOATING_USER_ON;
326  free(buf);
327  } else if (strcasecmp(last_key, "scratchpad_state") == 0) {
328  char *buf = NULL;
329  sasprintf(&buf, "%.*s", (int)len, val);
330  if (strcasecmp(buf, "none") == 0)
331  json_node->scratchpad_state = SCRATCHPAD_NONE;
332  else if (strcasecmp(buf, "fresh") == 0)
333  json_node->scratchpad_state = SCRATCHPAD_FRESH;
334  else if (strcasecmp(buf, "changed") == 0)
335  json_node->scratchpad_state = SCRATCHPAD_CHANGED;
336  free(buf);
337  }
338  }
339  return 1;
340 }
341 
342 static int json_int(void *ctx, long long val) {
343  LOG("int %lld for key %s\n", val, last_key);
344  /* For backwards compatibility with i3 < 4.8 */
345  if (strcasecmp(last_key, "type") == 0)
346  json_node->type = val;
347 
348  if (strcasecmp(last_key, "fullscreen_mode") == 0)
349  json_node->fullscreen_mode = val;
350 
351  if (strcasecmp(last_key, "num") == 0)
352  json_node->num = val;
353 
354  if (strcasecmp(last_key, "current_border_width") == 0)
355  json_node->current_border_width = val;
356 
357  if (strcasecmp(last_key, "depth") == 0)
358  json_node->depth = val;
359 
360  if (!parsing_swallows && strcasecmp(last_key, "id") == 0)
361  json_node->old_id = val;
362 
363  if (parsing_focus) {
364  struct focus_mapping *focus_mapping = scalloc(sizeof(struct focus_mapping));
365  focus_mapping->old_id = val;
366  TAILQ_INSERT_TAIL(&focus_mappings, focus_mapping, focus_mappings);
367  }
368 
370  Rect *r;
371  if (parsing_rect)
372  r = &(json_node->rect);
373  else if (parsing_window_rect)
374  r = &(json_node->window_rect);
375  else
376  r = &(json_node->geometry);
377  if (strcasecmp(last_key, "x") == 0)
378  r->x = val;
379  else if (strcasecmp(last_key, "y") == 0)
380  r->y = val;
381  else if (strcasecmp(last_key, "width") == 0)
382  r->width = val;
383  else if (strcasecmp(last_key, "height") == 0)
384  r->height = val;
385  else
386  ELOG("WARNING: unknown key %s in rect\n", last_key);
387  DLOG("rect now: (%d, %d, %d, %d)\n",
388  r->x, r->y, r->width, r->height);
389  }
390  if (parsing_swallows) {
391  if (strcasecmp(last_key, "id") == 0) {
392  current_swallow->id = val;
393  }
394  if (strcasecmp(last_key, "dock") == 0) {
395  current_swallow->dock = val;
396  }
397  if (strcasecmp(last_key, "insert_where") == 0) {
398  current_swallow->insert_where = val;
399  }
400  }
401 
402  return 1;
403 }
404 
405 static int json_bool(void *ctx, int val) {
406  LOG("bool %d for key %s\n", val, last_key);
407  if (strcasecmp(last_key, "focused") == 0 && val) {
408  to_focus = json_node;
409  }
410 
411  if (parsing_swallows) {
412  if (strcasecmp(last_key, "restart_mode") == 0)
413  current_swallow->restart_mode = val;
414  }
415 
416  return 1;
417 }
418 
419 static int json_double(void *ctx, double val) {
420  LOG("double %f for key %s\n", val, last_key);
421  if (strcasecmp(last_key, "percent") == 0) {
422  json_node->percent = val;
423  }
424  return 1;
425 }
426 
428 static int content_level;
429 
431  content_level++;
432  return 1;
433 }
434 
436  content_level--;
437  return 1;
438 }
439 
440 static int json_determine_content_string(void *ctx, const unsigned char *val, size_t len) {
441  if (strcasecmp(last_key, "type") != 0 || content_level > 1)
442  return 1;
443 
444  DLOG("string = %.*s, last_key = %s\n", (int)len, val, last_key);
445  if (strncasecmp((const char *)val, "workspace", len) == 0)
446  content_result = JSON_CONTENT_WORKSPACE;
447  return 0;
448 }
449 
450 /* Parses the given JSON file until it encounters the first “type” property to
451  * determine whether the file contains workspaces or regular containers, which
452  * is important to know when deciding where (and how) to append the contents.
453  * */
454 json_content_t json_determine_content(const char *filename) {
455  FILE *f;
456  if ((f = fopen(filename, "r")) == NULL) {
457  ELOG("Cannot open file \"%s\"\n", filename);
458  return JSON_CONTENT_UNKNOWN;
459  }
460  struct stat stbuf;
461  if (fstat(fileno(f), &stbuf) != 0) {
462  ELOG("Cannot fstat() \"%s\"\n", filename);
463  fclose(f);
464  return JSON_CONTENT_UNKNOWN;
465  }
466  char *buf = smalloc(stbuf.st_size);
467  int n = fread(buf, 1, stbuf.st_size, f);
468  if (n != stbuf.st_size) {
469  ELOG("File \"%s\" could not be read entirely, not loading.\n", filename);
470  fclose(f);
471  return JSON_CONTENT_UNKNOWN;
472  }
473  DLOG("read %d bytes\n", n);
474  // We default to JSON_CONTENT_CON because it is legal to not include
475  // “"type": "con"” in the JSON files for better readability.
476  content_result = JSON_CONTENT_CON;
477  content_level = 0;
478  yajl_gen g;
479  yajl_handle hand;
480  static yajl_callbacks callbacks = {
481  .yajl_string = json_determine_content_string,
482  .yajl_map_key = json_key,
483  .yajl_start_array = json_determine_content_deeper,
484  .yajl_start_map = json_determine_content_deeper,
485  .yajl_end_map = json_determine_content_shallower,
486  .yajl_end_array = json_determine_content_shallower,
487  };
488  g = yajl_gen_alloc(NULL);
489  hand = yajl_alloc(&callbacks, NULL, (void *)g);
490  /* Allowing comments allows for more user-friendly layout files. */
491  yajl_config(hand, yajl_allow_comments, true);
492  /* Allow multiple values, i.e. multiple nodes to attach */
493  yajl_config(hand, yajl_allow_multiple_values, true);
494  yajl_status stat;
495  setlocale(LC_NUMERIC, "C");
496  stat = yajl_parse(hand, (const unsigned char *)buf, n);
497  if (stat != yajl_status_ok && stat != yajl_status_client_canceled) {
498  unsigned char *str = yajl_get_error(hand, 1, (const unsigned char *)buf, n);
499  ELOG("JSON parsing error: %s\n", str);
500  yajl_free_error(hand, str);
501  }
502 
503  setlocale(LC_NUMERIC, "");
504  yajl_complete_parse(hand);
505 
506  fclose(f);
507 
508  return content_result;
509 }
510 
511 void tree_append_json(Con *con, const char *filename, char **errormsg) {
512  FILE *f;
513  if ((f = fopen(filename, "r")) == NULL) {
514  ELOG("Cannot open file \"%s\"\n", filename);
515  return;
516  }
517  struct stat stbuf;
518  if (fstat(fileno(f), &stbuf) != 0) {
519  ELOG("Cannot fstat() \"%s\"\n", filename);
520  fclose(f);
521  return;
522  }
523  char *buf = smalloc(stbuf.st_size);
524  int n = fread(buf, 1, stbuf.st_size, f);
525  if (n != stbuf.st_size) {
526  ELOG("File \"%s\" could not be read entirely, not loading.\n", filename);
527  fclose(f);
528  return;
529  }
530  DLOG("read %d bytes\n", n);
531  yajl_gen g;
532  yajl_handle hand;
533  static yajl_callbacks callbacks = {
534  .yajl_boolean = json_bool,
535  .yajl_integer = json_int,
536  .yajl_double = json_double,
537  .yajl_string = json_string,
538  .yajl_start_map = json_start_map,
539  .yajl_map_key = json_key,
540  .yajl_end_map = json_end_map,
541  .yajl_end_array = json_end_array,
542  };
543  g = yajl_gen_alloc(NULL);
544  hand = yajl_alloc(&callbacks, NULL, (void *)g);
545  /* Allowing comments allows for more user-friendly layout files. */
546  yajl_config(hand, yajl_allow_comments, true);
547  /* Allow multiple values, i.e. multiple nodes to attach */
548  yajl_config(hand, yajl_allow_multiple_values, true);
549  yajl_status stat;
550  json_node = con;
551  to_focus = NULL;
552  parsing_swallows = false;
553  parsing_rect = false;
554  parsing_deco_rect = false;
555  parsing_window_rect = false;
556  parsing_geometry = false;
557  parsing_focus = false;
558  setlocale(LC_NUMERIC, "C");
559  stat = yajl_parse(hand, (const unsigned char *)buf, n);
560  if (stat != yajl_status_ok) {
561  unsigned char *str = yajl_get_error(hand, 1, (const unsigned char *)buf, n);
562  ELOG("JSON parsing error: %s\n", str);
563  if (errormsg != NULL)
564  *errormsg = sstrdup((const char *)str);
565  yajl_free_error(hand, str);
566  }
567 
568  /* In case not all containers were restored, we need to fix the
569  * percentages, otherwise i3 will crash immediately when rendering the
570  * next time. */
571  con_fix_percent(con);
572 
573  setlocale(LC_NUMERIC, "");
574  yajl_complete_parse(hand);
575 
576  fclose(f);
577  if (to_focus)
578  con_focus(to_focus);
579 }
enum Con::@20 scratchpad_state
Definition: data.h:95
static Con * json_node
Definition: load_layout.c:23
struct Con * parent
Definition: data.h:529
long ws_name_to_number(const char *name)
Parses the workspace name as a number.
Definition: util.c:76
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
Definition: data.h:61
json_content_t json_determine_content(const char *filename)
Definition: load_layout.c:454
uint32_t y
Definition: data.h:132
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:402
void con_attach(Con *con, Con *parent, bool ignore_focus)
Attaches the given container to the given parent.
Definition: con.c:83
double percent
Definition: data.h:547
char * sticky_group
Definition: data.h:542
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
Definition: con.c:298
Stores a rectangle, for example the size of a window, the child window etc.
Definition: data.h:130
#define LOG(fmt,...)
Definition: libi3.h:76
static char * last_key
Definition: load_layout.c:22
static int content_level
Definition: load_layout.c:428
Definition: data.h:62
static int json_determine_content_shallower(void *ctx)
Definition: load_layout.c:435
struct Match * current_swallow
Definition: load_layout.c:31
struct Rect window_rect
Definition: data.h:532
struct Rect rect
Definition: data.h:531
char * mark
Definition: data.h:545
static int json_determine_content_deeper(void *ctx)
Definition: load_layout.c:430
static int json_bool(void *ctx, int val)
Definition: load_layout.c:405
int current_border_width
Definition: data.h:558
struct regex * window_role
Definition: data.h:410
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
Definition: queue.h:352
#define TAILQ_FIRST(head)
Definition: queue.h:336
static Con * to_focus
Definition: load_layout.c:24
static json_content_t content_result
Definition: load_layout.c:427
static int json_determine_content_string(void *ctx, const unsigned char *val, size_t len)
Definition: load_layout.c:440
static int json_double(void *ctx, double val)
Definition: load_layout.c:419
enum Con::@19 floating
floating? (= not in tiling layout) This cannot be simply a bool because we want to keep track of whet...
void tree_append_json(Con *con, const char *filename, char **errormsg)
Definition: load_layout.c:511
border_style_t border_style
Definition: data.h:596
static bool parsing_rect
Definition: load_layout.c:26
static bool parsing_focus
Definition: load_layout.c:30
static bool parsing_deco_rect
Definition: load_layout.c:27
enum Con::@18 type
Definition: data.h:93
#define DLOG(fmt,...)
Definition: libi3.h:86
struct regex * regex_new(const char *pattern)
Creates a new 'regex' struct containing the given pattern and a PCRE compiled regular expression...
Definition: regex.c:24
struct regex * instance
Definition: data.h:408
json_content_t
Definition: load_layout.h:13
int sasprintf(char **strp, const char *fmt,...)
Safe-wrapper around asprintf which exits if it returns -1 (meaning that there is no more memory avail...
Definition: data.h:94
int old_id
Definition: data.h:632
xcb_window_t id
Definition: data.h:423
static int json_key(void *ctx, const unsigned char *val, size_t len)
Definition: load_layout.c:167
uint16_t depth
Definition: data.h:635
static int json_end_array(void *ctx)
Definition: load_layout.c:133
uint32_t height
Definition: data.h:134
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:366
Con * focused
Definition: tree.c:15
struct Rect geometry
the geometry this window requested when getting mapped
Definition: data.h:535
int num
the workspace number, if this Con is of type CT_WORKSPACE and the workspace is not a named workspace ...
Definition: data.h:527
char * name
Definition: data.h:537
fullscreen_mode_t fullscreen_mode
Definition: data.h:580
Definition: data.h:99
void con_focus(Con *con)
Sets input focus to the given container.
Definition: con.c:193
#define TAILQ_EMPTY(head)
Definition: queue.h:344
static int json_int(void *ctx, long long val)
Definition: load_layout.c:342
bool con_is_split(Con *con)
Definition: con.c:246
enum Match::@13 dock
#define TAILQ_ENTRY(type)
Definition: queue.h:327
#define ELOG(fmt,...)
Definition: libi3.h:81
A "match" is a data structure which acts like a mask or expression to match certain windows or not...
Definition: data.h:404
static xcb_cursor_context_t * ctx
Definition: xcursor.c:19
#define GREP_FIRST(dest, head, condition)
Definition: util.h:39
layout_t layout
Definition: data.h:595
A 'Con' represents everything from the X11 root window down to a single X11 window.
Definition: data.h:496
uint32_t x
Definition: data.h:131
void * scalloc(size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
Definition: data.h:97
layout_t last_split_layout
Definition: data.h:595
struct regex * title
Definition: data.h:405
layout_t workspace_layout
Definition: data.h:595
enum Match::@15 insert_where
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:376
struct Con * croot
Definition: tree.c:14
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
bool restart_mode
Definition: data.h:447
Con * output_get_content(Con *output)
Returns the output container below the given output container.
Definition: output.c:18
static bool parsing_swallows
Definition: load_layout.c:25
void * smalloc(size_t size)
Safe-wrapper around malloc which exits if malloc returns NULL (meaning that there is no more memory a...
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:347
void con_fix_percent(Con *con)
Updates the percent attribute of the children of the given container.
Definition: con.c:523
static bool parsing_window_rect
Definition: load_layout.c:28
static bool parsing_geometry
Definition: load_layout.c:29
static int json_end_map(void *ctx)
Definition: load_layout.c:70
#define FREE(pointer)
Definition: util.h:48
static int json_string(void *ctx, const unsigned char *val, size_t len)
Definition: load_layout.c:193
Definition: data.h:60
void match_init(Match *match)
Definition: match.c:28
Con * con_new_skeleton(Con *parent, i3Window *window)
Create a new container (and attach it to the given parent, if not NULL).
Definition: con.c:38
struct regex * class
Definition: data.h:407
static TAILQ_HEAD(focus_mappings_head, focus_mapping)
Definition: load_layout.c:40
uint32_t width
Definition: data.h:133
Definition: data.h:98
void match_free(Match *match)
Frees the given match.
Definition: match.c:191
void x_con_init(Con *con, uint16_t depth)
Initializes the X11 part for the given container.
Definition: x.c:94