i3
commands.c
Go to the documentation of this file.
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
6  *
7  * commands.c: all command functions (see commands_parser.c)
8  *
9  */
10 #include "all.h"
11 
12 #include <stdint.h>
13 #include <float.h>
14 #include <stdarg.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 
18 #include "shmlog.h"
19 
20 // Macros to make the YAJL API a bit easier to use.
21 #define y(x, ...) (cmd_output->json_gen != NULL ? yajl_gen_##x(cmd_output->json_gen, ##__VA_ARGS__) : 0)
22 #define ystr(str) (cmd_output->json_gen != NULL ? yajl_gen_string(cmd_output->json_gen, (unsigned char *)str, strlen(str)) : 0)
23 #define ysuccess(success) \
24  do { \
25  if (cmd_output->json_gen != NULL) { \
26  y(map_open); \
27  ystr("success"); \
28  y(bool, success); \
29  y(map_close); \
30  } \
31  } while (0)
32 #define yerror(format, ...) \
33  do { \
34  if (cmd_output->json_gen != NULL) { \
35  char *message; \
36  sasprintf(&message, format, ##__VA_ARGS__); \
37  y(map_open); \
38  ystr("success"); \
39  y(bool, false); \
40  ystr("error"); \
41  ystr(message); \
42  y(map_close); \
43  free(message); \
44  } \
45  } while (0)
46 
49 #define HANDLE_INVALID_MATCH \
50  do { \
51  if (current_match->error != NULL) { \
52  yerror("Invalid match: %s", current_match->error); \
53  return; \
54  } \
55  } while (0)
56 
62 #define HANDLE_EMPTY_MATCH \
63  do { \
64  HANDLE_INVALID_MATCH; \
65  \
66  if (match_is_empty(current_match)) { \
67  while (!TAILQ_EMPTY(&owindows)) { \
68  owindow *ow = TAILQ_FIRST(&owindows); \
69  TAILQ_REMOVE(&owindows, ow, owindows); \
70  free(ow); \
71  } \
72  owindow *ow = smalloc(sizeof(owindow)); \
73  ow->con = focused; \
74  TAILQ_INIT(&owindows); \
75  TAILQ_INSERT_TAIL(&owindows, ow, owindows); \
76  } \
77  } while (0)
78 
79 /*
80  * Checks whether we switched to a new workspace and returns false in that case,
81  * signaling that further workspace switching should be done by the calling function
82  * If not, calls workspace_back_and_forth() if workspace_auto_back_and_forth is set
83  * and return true, signaling that no further workspace switching should occur in the calling function.
84  *
85  */
86 static bool maybe_back_and_forth(struct CommandResultIR *cmd_output, const char *name) {
88 
89  /* If we switched to a different workspace, do nothing */
90  if (strcmp(ws->name, name) != 0)
91  return false;
92 
93  DLOG("This workspace is already focused.\n");
96  cmd_output->needs_tree_render = true;
97  }
98  return true;
99 }
100 
101 /*
102  * Return the passed workspace unless it is the current one and auto back and
103  * forth is enabled, in which case the back_and_forth workspace is returned.
104  */
106  Con *current, *baf;
107 
109  return workspace;
110 
111  current = con_get_workspace(focused);
112 
113  if (current == workspace) {
115  if (baf != NULL) {
116  DLOG("Substituting workspace with back_and_forth, as it is focused.\n");
117  return baf;
118  }
119  }
120 
121  return workspace;
122 }
123 
124 /*******************************************************************************
125  * Criteria functions.
126  ******************************************************************************/
127 
128 /*
129  * Helper data structure for an operation window (window on which the operation
130  * will be performed). Used to build the TAILQ owindows.
131  *
132  */
133 typedef struct owindow {
135 
138 } owindow;
139 
140 typedef TAILQ_HEAD(owindows_head, owindow) owindows_head;
141 
142 static owindows_head owindows;
143 
144 /*
145  * Initializes the specified 'Match' data structure and the initial state of
146  * commands.c for matching target windows of a command.
147  *
148  */
150  Con *con;
151  owindow *ow;
152 
153  DLOG("Initializing criteria, current_match = %p\n", current_match);
156  while (!TAILQ_EMPTY(&owindows)) {
157  ow = TAILQ_FIRST(&owindows);
159  free(ow);
160  }
162  /* copy all_cons */
164  ow = smalloc(sizeof(owindow));
165  ow->con = con;
167  }
168 }
169 
170 /*
171  * A match specification just finished (the closing square bracket was found),
172  * so we filter the list of owindows.
173  *
174  */
176  owindow *next, *current;
177 
178  DLOG("match specification finished, matching...\n");
179  /* copy the old list head to iterate through it and start with a fresh
180  * list which will contain only matching windows */
181  struct owindows_head old = owindows;
183  for (next = TAILQ_FIRST(&old); next != TAILQ_END(&old);) {
184  /* make a copy of the next pointer and advance the pointer to the
185  * next element as we are going to invalidate the element’s
186  * next/prev pointers by calling TAILQ_INSERT_TAIL later */
187  current = next;
188  next = TAILQ_NEXT(next, owindows);
189 
190  DLOG("checking if con %p / %s matches\n", current->con, current->con->name);
191 
192  /* We use this flag to prevent matching on window-less containers if
193  * only window-specific criteria were specified. */
194  bool accept_match = false;
195 
196  if (current_match->con_id != NULL) {
197  accept_match = true;
198 
199  if (current_match->con_id == current->con) {
200  DLOG("con_id matched.\n");
201  } else {
202  DLOG("con_id does not match.\n");
203  FREE(current);
204  continue;
205  }
206  }
207 
208  if (current_match->mark != NULL && !TAILQ_EMPTY(&(current->con->marks_head))) {
209  accept_match = true;
210  bool matched_by_mark = false;
211 
212  mark_t *mark;
213  TAILQ_FOREACH(mark, &(current->con->marks_head), marks) {
214  if (!regex_matches(current_match->mark, mark->name))
215  continue;
216 
217  DLOG("match by mark\n");
218  matched_by_mark = true;
219  break;
220  }
221 
222  if (!matched_by_mark) {
223  DLOG("mark does not match.\n");
224  FREE(current);
225  continue;
226  }
227  }
228 
229  if (current->con->window != NULL) {
230  if (match_matches_window(current_match, current->con->window)) {
231  DLOG("matches window!\n");
232  accept_match = true;
233  } else {
234  DLOG("doesn't match\n");
235  FREE(current);
236  continue;
237  }
238  }
239 
240  if (accept_match) {
241  TAILQ_INSERT_TAIL(&owindows, current, owindows);
242  } else {
243  FREE(current);
244  continue;
245  }
246  }
247 
248  TAILQ_FOREACH(current, &owindows, owindows) {
249  DLOG("matching: %p / %s\n", current->con, current->con->name);
250  }
251 }
252 
253 /*
254  * Interprets a ctype=cvalue pair and adds it to the current match
255  * specification.
256  *
257  */
258 void cmd_criteria_add(I3_CMD, const char *ctype, const char *cvalue) {
259  match_parse_property(current_match, ctype, cvalue);
260 }
261 
262 static void move_matches_to_workspace(Con *ws) {
263  owindow *current;
264  TAILQ_FOREACH(current, &owindows, owindows) {
265  DLOG("matching: %p / %s\n", current->con, current->con->name);
266  con_move_to_workspace(current->con, ws, true, false, false);
267  }
268 }
269 
270 #define CHECK_MOVE_CON_TO_WORKSPACE \
271  do { \
272  HANDLE_EMPTY_MATCH; \
273  if (TAILQ_EMPTY(&owindows)) { \
274  yerror("Nothing to move: specified criteria don't match any window"); \
275  return; \
276  } else { \
277  bool found = false; \
278  owindow *current = TAILQ_FIRST(&owindows); \
279  while (current) { \
280  owindow *next = TAILQ_NEXT(current, owindows); \
281  \
282  if (current->con->type == CT_WORKSPACE && !con_has_children(current->con)) { \
283  TAILQ_REMOVE(&owindows, current, owindows); \
284  } else { \
285  found = true; \
286  } \
287  \
288  current = next; \
289  } \
290  if (!found) { \
291  yerror("Nothing to move: workspace empty"); \
292  return; \
293  } \
294  } \
295  } while (0)
296 
297 /*
298  * Implementation of 'move [window|container] [to] workspace
299  * next|prev|next_on_output|prev_on_output|current'.
300  *
301  */
302 void cmd_move_con_to_workspace(I3_CMD, const char *which) {
303  DLOG("which=%s\n", which);
304 
306 
307  /* get the workspace */
308  Con *ws;
309  if (strcmp(which, "next") == 0)
310  ws = workspace_next();
311  else if (strcmp(which, "prev") == 0)
312  ws = workspace_prev();
313  else if (strcmp(which, "next_on_output") == 0)
315  else if (strcmp(which, "prev_on_output") == 0)
317  else if (strcmp(which, "current") == 0)
319  else {
320  yerror("BUG: called with which=%s", which);
321  return;
322  }
323 
325 
326  cmd_output->needs_tree_render = true;
327  // XXX: default reply for now, make this a better reply
328  ysuccess(true);
329 }
330 
331 /*
332  * Implementation of 'move [window|container] [to] workspace back_and_forth'.
333  *
334  */
337  if (ws == NULL) {
338  yerror("No workspace was previously active.");
339  return;
340  }
341 
343 
345 
346  cmd_output->needs_tree_render = true;
347  // XXX: default reply for now, make this a better reply
348  ysuccess(true);
349 }
350 
351 /*
352  * Implementation of 'move [--no-auto-back-and-forth] [window|container] [to] workspace <name>'.
353  *
354  */
355 void cmd_move_con_to_workspace_name(I3_CMD, const char *name, const char *no_auto_back_and_forth) {
356  if (strncasecmp(name, "__", strlen("__")) == 0) {
357  yerror("You cannot move containers to i3-internal workspaces (\"%s\").", name);
358  return;
359  }
360 
362 
363  LOG("should move window to workspace %s\n", name);
364  /* get the workspace */
365  Con *ws = workspace_get(name, NULL);
366 
367  if (no_auto_back_and_forth == NULL) {
369  }
370 
372 
373  cmd_output->needs_tree_render = true;
374  // XXX: default reply for now, make this a better reply
375  ysuccess(true);
376 }
377 
378 /*
379  * Implementation of 'move [--no-auto-back-and-forth] [window|container] [to] workspace number <name>'.
380  *
381  */
382 void cmd_move_con_to_workspace_number(I3_CMD, const char *which, const char *no_auto_back_and_forth) {
384 
385  LOG("should move window to workspace %s\n", which);
386 
387  long parsed_num = ws_name_to_number(which);
388  if (parsed_num == -1) {
389  LOG("Could not parse initial part of \"%s\" as a number.\n", which);
390  yerror("Could not parse number \"%s\"", which);
391  return;
392  }
393 
394  Con *ws = get_existing_workspace_by_num(parsed_num);
395  if (!ws) {
396  ws = workspace_get(which, NULL);
397  }
398 
399  if (no_auto_back_and_forth == NULL) {
401  }
402 
404 
405  cmd_output->needs_tree_render = true;
406  // XXX: default reply for now, make this a better reply
407  ysuccess(true);
408 }
409 
410 /*
411  * Convert a string direction ("left", "right", etc.) to a direction_t. Assumes
412  * valid direction string.
413  */
414 static direction_t parse_direction(const char *str) {
415  if (strcmp(str, "left") == 0) {
416  return D_LEFT;
417  } else if (strcmp(str, "right") == 0) {
418  return D_RIGHT;
419  } else if (strcmp(str, "up") == 0) {
420  return D_UP;
421  } else if (strcmp(str, "down") == 0) {
422  return D_DOWN;
423  } else {
424  ELOG("Invalid direction. This is a parser bug.\n");
425  assert(false);
426  }
427 }
428 
429 static void cmd_resize_floating(I3_CMD, const char *direction_str, Con *floating_con, int px) {
430  Rect old_rect = floating_con->rect;
431  Con *focused_con = con_descend_focused(floating_con);
432 
433  direction_t direction;
434  if (strcmp(direction_str, "height") == 0) {
435  direction = D_DOWN;
436  } else if (strcmp(direction_str, "width") == 0) {
437  direction = D_RIGHT;
438  } else {
439  direction = parse_direction(direction_str);
440  }
441  orientation_t orientation = orientation_from_direction(direction);
442 
443  /* ensure that resize will take place even if pixel increment is smaller than
444  * height increment or width increment.
445  * fixes #1011 */
446  const i3Window *window = focused_con->window;
447  if (window != NULL) {
448  if (orientation == VERT) {
449  if (px < 0) {
450  px = (-px < window->height_increment) ? -window->height_increment : px;
451  } else {
452  px = (px < window->height_increment) ? window->height_increment : px;
453  }
454  } else {
455  if (px < 0) {
456  px = (-px < window->width_increment) ? -window->width_increment : px;
457  } else {
458  px = (px < window->width_increment) ? window->width_increment : px;
459  }
460  }
461  }
462 
463  if (orientation == VERT) {
464  floating_con->rect.height += px;
465  } else {
466  floating_con->rect.width += px;
467  }
468  floating_check_size(floating_con, orientation == VERT);
469 
470  /* Did we actually resize anything or did the size constraints prevent us?
471  * If we could not resize, exit now to not move the window. */
472  if (rect_equals(old_rect, floating_con->rect)) {
473  return;
474  }
475 
476  if (direction == D_UP) {
477  floating_con->rect.y -= (floating_con->rect.height - old_rect.height);
478  } else if (direction == D_LEFT) {
479  floating_con->rect.x -= (floating_con->rect.width - old_rect.width);
480  }
481 
482  /* If this is a scratchpad window, don't auto center it from now on. */
483  if (floating_con->scratchpad_state == SCRATCHPAD_FRESH) {
484  floating_con->scratchpad_state = SCRATCHPAD_CHANGED;
485  }
486 }
487 
488 static bool cmd_resize_tiling_direction(I3_CMD, Con *current, const char *direction, int px, int ppt) {
489  Con *second = NULL;
490  Con *first = current;
491  direction_t search_direction = parse_direction(direction);
492 
493  bool res = resize_find_tiling_participants(&first, &second, search_direction, false);
494  if (!res) {
495  yerror("No second container found in this direction.");
496  return false;
497  }
498 
499  if (ppt) {
500  /* For backwards compatibility, 'X px or Y ppt' means that ppt is
501  * preferred. */
502  px = 0;
503  }
504  return resize_neighboring_cons(first, second, px, ppt);
505 }
506 
507 static bool cmd_resize_tiling_width_height(I3_CMD, Con *current, const char *direction, int px, double ppt) {
508  LOG("width/height resize\n");
509 
510  /* get the appropriate current container (skip stacked/tabbed cons) */
511  Con *dummy = NULL;
512  direction_t search_direction = (strcmp(direction, "width") == 0 ? D_LEFT : D_DOWN);
513  bool search_result = resize_find_tiling_participants(&current, &dummy, search_direction, true);
514  if (search_result == false) {
515  yerror("Failed to find appropriate tiling containers for resize operation");
516  return false;
517  }
518 
519  /* get the default percentage */
520  int children = con_num_children(current->parent);
521  LOG("ins. %d children\n", children);
522  double percentage = 1.0 / children;
523  LOG("default percentage = %f\n", percentage);
524 
525  /* Ensure all the other children have a percentage set. */
526  Con *child;
527  TAILQ_FOREACH(child, &(current->parent->nodes_head), nodes) {
528  LOG("child->percent = %f (child %p)\n", child->percent, child);
529  if (child->percent == 0.0)
530  child->percent = percentage;
531  }
532 
533  double new_current_percent;
534  double subtract_percent;
535  if (ppt != 0.0) {
536  new_current_percent = current->percent + ppt;
537  } else {
538  /* Convert px change to change in percentages */
539  ppt = (double)px / (double)con_rect_size_in_orientation(current->parent);
540  new_current_percent = current->percent + ppt;
541  }
542  subtract_percent = ppt / (children - 1);
543  if (ppt < 0.0 && new_current_percent < percent_for_1px(current)) {
544  yerror("Not resizing, container would end with less than 1px");
545  return false;
546  }
547 
548  LOG("new_current_percent = %f\n", new_current_percent);
549  LOG("subtract_percent = %f\n", subtract_percent);
550  /* Ensure that the new percentages are positive. */
551  if (subtract_percent >= 0.0) {
552  TAILQ_FOREACH(child, &(current->parent->nodes_head), nodes) {
553  if (child == current) {
554  continue;
555  }
556  if (child->percent - subtract_percent < percent_for_1px(child)) {
557  yerror("Not resizing, already at minimum size (child %p would end up with a size of %.f", child, child->percent - subtract_percent);
558  return false;
559  }
560  }
561  }
562 
563  current->percent = new_current_percent;
564  LOG("current->percent after = %f\n", current->percent);
565 
566  TAILQ_FOREACH(child, &(current->parent->nodes_head), nodes) {
567  if (child == current)
568  continue;
569  child->percent -= subtract_percent;
570  LOG("child->percent after (%p) = %f\n", child, child->percent);
571  }
572 
573  return true;
574 }
575 
576 /*
577  * Implementation of 'resize grow|shrink <direction> [<px> px] [or <ppt> ppt]'.
578  *
579  */
580 void cmd_resize(I3_CMD, const char *way, const char *direction, long resize_px, long resize_ppt) {
581  DLOG("resizing in way %s, direction %s, px %ld or ppt %ld\n", way, direction, resize_px, resize_ppt);
582  if (strcmp(way, "shrink") == 0) {
583  resize_px *= -1;
584  resize_ppt *= -1;
585  }
586 
588 
589  owindow *current;
590  TAILQ_FOREACH(current, &owindows, owindows) {
591  /* Don't handle dock windows (issue #1201) */
592  if (current->con->window && current->con->window->dock) {
593  DLOG("This is a dock window. Not resizing (con = %p)\n)", current->con);
594  continue;
595  }
596 
597  Con *floating_con;
598  if ((floating_con = con_inside_floating(current->con))) {
599  cmd_resize_floating(current_match, cmd_output, direction, floating_con, resize_px);
600  } else {
601  if (strcmp(direction, "width") == 0 ||
602  strcmp(direction, "height") == 0) {
603  const double ppt = (double)resize_ppt / 100.0;
605  current->con, direction,
606  resize_px, ppt)) {
607  yerror("Cannot resize.");
608  return;
609  }
610  } else {
612  current->con, direction,
613  resize_px, resize_ppt)) {
614  yerror("Cannot resize.");
615  return;
616  }
617  }
618  }
619  }
620 
621  cmd_output->needs_tree_render = true;
622  // XXX: default reply for now, make this a better reply
623  ysuccess(true);
624 }
625 
626 static bool resize_set_tiling(I3_CMD, Con *target, orientation_t resize_orientation, bool is_ppt, long target_size) {
627  direction_t search_direction;
628  char *mode;
629  if (resize_orientation == HORIZ) {
630  search_direction = D_LEFT;
631  mode = "width";
632  } else {
633  search_direction = D_DOWN;
634  mode = "height";
635  }
636 
637  /* Get the appropriate current container (skip stacked/tabbed cons) */
638  Con *dummy;
639  resize_find_tiling_participants(&target, &dummy, search_direction, true);
640 
641  /* Calculate new size for the target container */
642  double ppt = 0.0;
643  int px = 0;
644  if (is_ppt) {
645  ppt = (double)target_size / 100.0 - target->percent;
646  } else {
647  px = target_size - (resize_orientation == HORIZ ? target->rect.width : target->rect.height);
648  }
649 
650  /* Perform resizing and report failure if not possible */
652  target, mode, px, ppt);
653 }
654 
655 /*
656  * Implementation of 'resize set <width> [px | ppt] <height> [px | ppt]'.
657  *
658  */
659 void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, const char *mode_height) {
660  DLOG("resizing to %ld %s x %ld %s\n", cwidth, mode_width, cheight, mode_height);
661  if (cwidth < 0 || cheight < 0) {
662  yerror("Dimensions cannot be negative.");
663  return;
664  }
665 
667 
668  owindow *current;
669  bool success = true;
670  TAILQ_FOREACH(current, &owindows, owindows) {
671  Con *floating_con;
672  if ((floating_con = con_inside_floating(current->con))) {
673  Con *output = con_get_output(floating_con);
674  if (cwidth == 0) {
675  cwidth = floating_con->rect.width;
676  } else if (mode_width && strcmp(mode_width, "ppt") == 0) {
677  cwidth = output->rect.width * ((double)cwidth / 100.0);
678  }
679  if (cheight == 0) {
680  cheight = floating_con->rect.height;
681  } else if (mode_height && strcmp(mode_height, "ppt") == 0) {
682  cheight = output->rect.height * ((double)cheight / 100.0);
683  }
684  floating_resize(floating_con, cwidth, cheight);
685  } else {
686  if (current->con->window && current->con->window->dock) {
687  DLOG("This is a dock window. Not resizing (con = %p)\n)", current->con);
688  continue;
689  }
690 
691  if (cwidth > 0) {
692  bool is_ppt = mode_width && strcmp(mode_width, "ppt") == 0;
693  success &= resize_set_tiling(current_match, cmd_output, current->con,
694  HORIZ, is_ppt, cwidth);
695  }
696  if (cheight > 0) {
697  bool is_ppt = mode_height && strcmp(mode_height, "ppt") == 0;
698  success &= resize_set_tiling(current_match, cmd_output, current->con,
699  VERT, is_ppt, cheight);
700  }
701  }
702  }
703 
704  cmd_output->needs_tree_render = true;
705  ysuccess(success);
706 }
707 
708 static int border_width_from_style(border_style_t border_style, long border_width, Con *con) {
709  return 3;
710 }
711 
712 /*
713  * Implementation of 'border normal|pixel [<n>]', 'border none|1pixel|toggle'.
714  *
715  */
716 void cmd_border(I3_CMD, const char *border_style_str, long border_width) {
717  DLOG("border style should be changed to %s with border width %ld\n", border_style_str, border_width);
718  owindow *current;
719 
721 
722  TAILQ_FOREACH(current, &owindows, owindows) {
723  DLOG("matching: %p / %s\n", current->con, current->con->name);
724 
725  border_style_t border_style;
726  if (strcmp(border_style_str, "toggle") == 0) {
727  border_style = (current->con->border_style + 1) % 3;
728  } else if (strcmp(border_style_str, "normal") == 0) {
729  border_style = BS_NORMAL;
730  } else if (strcmp(border_style_str, "pixel") == 0) {
731  border_style = BS_PIXEL;
732  } else if (strcmp(border_style_str, "none") == 0) {
733  border_style = BS_NONE;
734  } else {
735  yerror("BUG: called with border_style=%s", border_style_str);
736  return;
737  }
738 
739  const int con_border_width = border_width_from_style(border_style, border_width, current->con);
740  con_set_border_style(current->con, border_style, con_border_width);
741  }
742 
743  cmd_output->needs_tree_render = true;
744  ysuccess(true);
745 }
746 
747 /*
748  * Implementation of 'nop <comment>'.
749  *
750  */
751 void cmd_nop(I3_CMD, const char *comment) {
752  LOG("-------------------------------------------------\n");
753  LOG(" NOP: %s\n", comment);
754  LOG("-------------------------------------------------\n");
755  ysuccess(true);
756 }
757 
758 /*
759  * Implementation of 'append_layout <path>'.
760  *
761  */
762 void cmd_append_layout(I3_CMD, const char *cpath) {
763  LOG("Appending layout \"%s\"\n", cpath);
764 
765  /* Make sure we allow paths like '~/.i3/layout.json' */
766  char *path = resolve_tilde(cpath);
767 
768  char *buf = NULL;
769  ssize_t len;
770  if ((len = slurp(path, &buf)) < 0) {
771  yerror("Could not slurp \"%s\".", path);
772  /* slurp already logged an error. */
773  goto out;
774  }
775 
776  if (!json_validate(buf, len)) {
777  ELOG("Could not parse \"%s\" as JSON, not loading.\n", path);
778  yerror("Could not parse \"%s\" as JSON.", path);
779  goto out;
780  }
781 
782  json_content_t content = json_determine_content(buf, len);
783  LOG("JSON content = %d\n", content);
784  if (content == JSON_CONTENT_UNKNOWN) {
785  ELOG("Could not determine the contents of \"%s\", not loading.\n", path);
786  yerror("Could not determine the contents of \"%s\".", path);
787  goto out;
788  }
789 
790  Con *parent = focused;
791  if (content == JSON_CONTENT_WORKSPACE) {
792  parent = output_get_content(con_get_output(parent));
793  } else {
794  /* We need to append the layout to a split container, since a leaf
795  * container must not have any children (by definition).
796  * Note that we explicitly check for workspaces, since they are okay for
797  * this purpose, but con_accepts_window() returns false for workspaces. */
798  while (parent->type != CT_WORKSPACE && !con_accepts_window(parent))
799  parent = parent->parent;
800  }
801  DLOG("Appending to parent=%p instead of focused=%p\n", parent, focused);
802  char *errormsg = NULL;
803  tree_append_json(parent, buf, len, &errormsg);
804  if (errormsg != NULL) {
805  yerror(errormsg);
806  free(errormsg);
807  /* Note that we continue executing since tree_append_json() has
808  * side-effects — user-provided layouts can be partly valid, partly
809  * invalid, leading to half of the placeholder containers being
810  * created. */
811  } else {
812  ysuccess(true);
813  }
814 
815  // XXX: This is a bit of a kludge. Theoretically, render_con(parent,
816  // false); should be enough, but when sending 'workspace 4; append_layout
817  // /tmp/foo.json', the needs_tree_render == true of the workspace command
818  // is not executed yet and will be batched with append_layout’s
819  // needs_tree_render after the parser finished. We should check if that is
820  // necessary at all.
821  render_con(croot);
822 
824 
825  if (content == JSON_CONTENT_WORKSPACE)
826  ipc_send_workspace_event("restored", parent, NULL);
827 
828  cmd_output->needs_tree_render = true;
829 out:
830  free(path);
831  free(buf);
832 }
833 
834 /*
835  * Implementation of 'workspace next|prev|next_on_output|prev_on_output'.
836  *
837  */
838 void cmd_workspace(I3_CMD, const char *which) {
839  Con *ws;
840 
841  DLOG("which=%s\n", which);
842 
844  yerror("Cannot switch workspace while in global fullscreen");
845  return;
846  }
847 
848  if (strcmp(which, "next") == 0)
849  ws = workspace_next();
850  else if (strcmp(which, "prev") == 0)
851  ws = workspace_prev();
852  else if (strcmp(which, "next_on_output") == 0)
854  else if (strcmp(which, "prev_on_output") == 0)
856  else {
857  yerror("BUG: called with which=%s", which);
858  return;
859  }
860 
861  workspace_show(ws);
862 
863  cmd_output->needs_tree_render = true;
864  // XXX: default reply for now, make this a better reply
865  ysuccess(true);
866 }
867 
868 /*
869  * Implementation of 'workspace [--no-auto-back-and-forth] number <name>'
870  *
871  */
872 void cmd_workspace_number(I3_CMD, const char *which, const char *_no_auto_back_and_forth) {
873  const bool no_auto_back_and_forth = (_no_auto_back_and_forth != NULL);
874 
876  yerror("Cannot switch workspace while in global fullscreen");
877  return;
878  }
879 
880  long parsed_num = ws_name_to_number(which);
881  if (parsed_num == -1) {
882  yerror("Could not parse initial part of \"%s\" as a number.", which);
883  return;
884  }
885 
886  Con *workspace = get_existing_workspace_by_num(parsed_num);
887  if (!workspace) {
888  LOG("There is no workspace with number %ld, creating a new one.\n", parsed_num);
889  ysuccess(true);
890  workspace_show_by_name(which);
891  cmd_output->needs_tree_render = true;
892  return;
893  }
894  if (!no_auto_back_and_forth && maybe_back_and_forth(cmd_output, workspace->name)) {
895  ysuccess(true);
896  return;
897  }
898  workspace_show(workspace);
899 
900  cmd_output->needs_tree_render = true;
901  // XXX: default reply for now, make this a better reply
902  ysuccess(true);
903 }
904 
905 /*
906  * Implementation of 'workspace back_and_forth'.
907  *
908  */
911  yerror("Cannot switch workspace while in global fullscreen");
912  return;
913  }
914 
916 
917  cmd_output->needs_tree_render = true;
918  // XXX: default reply for now, make this a better reply
919  ysuccess(true);
920 }
921 
922 /*
923  * Implementation of 'workspace [--no-auto-back-and-forth] <name>'
924  *
925  */
926 void cmd_workspace_name(I3_CMD, const char *name, const char *_no_auto_back_and_forth) {
927  const bool no_auto_back_and_forth = (_no_auto_back_and_forth != NULL);
928 
929  if (strncasecmp(name, "__", strlen("__")) == 0) {
930  yerror("You cannot switch to the i3-internal workspaces (\"%s\").", name);
931  return;
932  }
933 
935  yerror("Cannot switch workspace while in global fullscreen");
936  return;
937  }
938 
939  DLOG("should switch to workspace %s\n", name);
940  if (!no_auto_back_and_forth && maybe_back_and_forth(cmd_output, name)) {
941  ysuccess(true);
942  return;
943  }
945 
946  cmd_output->needs_tree_render = true;
947  // XXX: default reply for now, make this a better reply
948  ysuccess(true);
949 }
950 
951 /*
952  * Implementation of 'mark [--add|--replace] [--toggle] <mark>'
953  *
954  */
955 void cmd_mark(I3_CMD, const char *mark, const char *mode, const char *toggle) {
957 
958  owindow *current = TAILQ_FIRST(&owindows);
959  if (current == NULL) {
960  yerror("Given criteria don't match a window");
961  return;
962  }
963 
964  /* Marks must be unique, i.e., no two windows must have the same mark. */
965  if (current != TAILQ_LAST(&owindows, owindows_head)) {
966  yerror("A mark must not be put onto more than one window");
967  return;
968  }
969 
970  DLOG("matching: %p / %s\n", current->con, current->con->name);
971 
972  mark_mode_t mark_mode = (mode == NULL || strcmp(mode, "--replace") == 0) ? MM_REPLACE : MM_ADD;
973  if (toggle != NULL) {
974  con_mark_toggle(current->con, mark, mark_mode);
975  } else {
976  con_mark(current->con, mark, mark_mode);
977  }
978 
979  cmd_output->needs_tree_render = true;
980  // XXX: default reply for now, make this a better reply
981  ysuccess(true);
982 }
983 
984 /*
985  * Implementation of 'unmark [mark]'
986  *
987  */
988 void cmd_unmark(I3_CMD, const char *mark) {
990  con_unmark(NULL, mark);
991  } else {
992  owindow *current;
993  TAILQ_FOREACH(current, &owindows, owindows) {
994  con_unmark(current->con, mark);
995  }
996  }
997 
998  cmd_output->needs_tree_render = true;
999  // XXX: default reply for now, make this a better reply
1000  ysuccess(true);
1001 }
1002 
1003 /*
1004  * Implementation of 'mode <string>'.
1005  *
1006  */
1007 void cmd_mode(I3_CMD, const char *mode) {
1008  DLOG("mode=%s\n", mode);
1009  switch_mode(mode);
1010 
1011  // XXX: default reply for now, make this a better reply
1012  ysuccess(true);
1013 }
1014 
1015 /*
1016  * Implementation of 'move [window|container] [to] output <str>'.
1017  *
1018  */
1019 void cmd_move_con_to_output(I3_CMD, const char *name) {
1020  DLOG("Should move window to output \"%s\".\n", name);
1022 
1023  owindow *current;
1024  bool had_error = false;
1025  TAILQ_FOREACH(current, &owindows, owindows) {
1026  DLOG("matching: %p / %s\n", current->con, current->con->name);
1027 
1028  had_error |= !con_move_to_output_name(current->con, name, true);
1029  }
1030 
1031  cmd_output->needs_tree_render = true;
1032  ysuccess(!had_error);
1033 }
1034 
1035 /*
1036  * Implementation of 'move [container|window] [to] mark <str>'.
1037  *
1038  */
1039 void cmd_move_con_to_mark(I3_CMD, const char *mark) {
1040  DLOG("moving window to mark \"%s\"\n", mark);
1041 
1043 
1044  bool result = true;
1045  owindow *current;
1046  TAILQ_FOREACH(current, &owindows, owindows) {
1047  DLOG("moving matched window %p / %s to mark \"%s\"\n", current->con, current->con->name, mark);
1048  result &= con_move_to_mark(current->con, mark);
1049  }
1050 
1051  cmd_output->needs_tree_render = true;
1052  ysuccess(result);
1053 }
1054 
1055 /*
1056  * Implementation of 'floating enable|disable|toggle'
1057  *
1058  */
1059 void cmd_floating(I3_CMD, const char *floating_mode) {
1060  owindow *current;
1061 
1062  DLOG("floating_mode=%s\n", floating_mode);
1063 
1065 
1066  TAILQ_FOREACH(current, &owindows, owindows) {
1067  DLOG("matching: %p / %s\n", current->con, current->con->name);
1068  if (strcmp(floating_mode, "toggle") == 0) {
1069  DLOG("should toggle mode\n");
1070  toggle_floating_mode(current->con, false);
1071  } else {
1072  DLOG("should switch mode to %s\n", floating_mode);
1073  if (strcmp(floating_mode, "enable") == 0) {
1074  floating_enable(current->con, false);
1075  } else {
1076  floating_disable(current->con);
1077  }
1078  }
1079  }
1080 
1081  cmd_output->needs_tree_render = true;
1082  // XXX: default reply for now, make this a better reply
1083  ysuccess(true);
1084 }
1085 
1086 /*
1087  * Implementation of 'move workspace to [output] <str>'.
1088  *
1089  */
1090 void cmd_move_workspace_to_output(I3_CMD, const char *name) {
1091  DLOG("should move workspace to output %s\n", name);
1092 
1094 
1095  owindow *current;
1096  TAILQ_FOREACH(current, &owindows, owindows) {
1097  Con *ws = con_get_workspace(current->con);
1098  if (con_is_internal(ws)) {
1099  continue;
1100  }
1101 
1102  Output *current_output = get_output_for_con(ws);
1103  Output *target_output = get_output_from_string(current_output, name);
1104  if (!target_output) {
1105  yerror("Could not get output from string \"%s\"", name);
1106  return;
1107  }
1108 
1109  workspace_move_to_output(ws, target_output);
1110  }
1111 
1112  cmd_output->needs_tree_render = true;
1113  ysuccess(true);
1114 }
1115 
1116 /*
1117  * Implementation of 'split v|h|t|vertical|horizontal|toggle'.
1118  *
1119  */
1120 void cmd_split(I3_CMD, const char *direction) {
1122 
1123  owindow *current;
1124  LOG("splitting in direction %c\n", direction[0]);
1125  TAILQ_FOREACH(current, &owindows, owindows) {
1126  if (con_is_docked(current->con)) {
1127  ELOG("Cannot split a docked container, skipping.\n");
1128  continue;
1129  }
1130 
1131  DLOG("matching: %p / %s\n", current->con, current->con->name);
1132  if (direction[0] == 't') {
1133  layout_t current_layout;
1134  if (current->con->type == CT_WORKSPACE) {
1135  current_layout = current->con->layout;
1136  } else {
1137  current_layout = current->con->parent->layout;
1138  }
1139  /* toggling split orientation */
1140  if (current_layout == L_SPLITH) {
1141  tree_split(current->con, VERT);
1142  } else {
1143  tree_split(current->con, HORIZ);
1144  }
1145  } else {
1146  tree_split(current->con, (direction[0] == 'v' ? VERT : HORIZ));
1147  }
1148  }
1149 
1150  cmd_output->needs_tree_render = true;
1151  // XXX: default reply for now, make this a better reply
1152  ysuccess(true);
1153 }
1154 
1155 /*
1156  * Implementation of 'kill [window|client]'.
1157  *
1158  */
1159 void cmd_kill(I3_CMD, const char *kill_mode_str) {
1160  if (kill_mode_str == NULL)
1161  kill_mode_str = "window";
1162 
1163  DLOG("kill_mode=%s\n", kill_mode_str);
1164 
1165  int kill_mode;
1166  if (strcmp(kill_mode_str, "window") == 0)
1167  kill_mode = KILL_WINDOW;
1168  else if (strcmp(kill_mode_str, "client") == 0)
1169  kill_mode = KILL_CLIENT;
1170  else {
1171  yerror("BUG: called with kill_mode=%s", kill_mode_str);
1172  return;
1173  }
1174 
1176 
1177  owindow *current;
1178  TAILQ_FOREACH(current, &owindows, owindows) {
1179  con_close(current->con, kill_mode);
1180  }
1181 
1182  cmd_output->needs_tree_render = true;
1183  // XXX: default reply for now, make this a better reply
1184  ysuccess(true);
1185 }
1186 
1187 /*
1188  * Implementation of 'exec [--no-startup-id] <command>'.
1189  *
1190  */
1191 void cmd_exec(I3_CMD, const char *nosn, const char *command) {
1192  bool no_startup_id = (nosn != NULL);
1193 
1195 
1196  int count = 0;
1197  owindow *current;
1198  TAILQ_FOREACH(current, &owindows, owindows) {
1199  count++;
1200  }
1201 
1202  if (count > 1) {
1203  LOG("WARNING: Your criteria for the exec command match %d containers, "
1204  "so the command will execute this many times.\n",
1205  count);
1206  }
1207 
1208  TAILQ_FOREACH(current, &owindows, owindows) {
1209  DLOG("should execute %s, no_startup_id = %d\n", command, no_startup_id);
1210  start_application(command, no_startup_id);
1211  }
1212 
1213  ysuccess(true);
1214 }
1215 
1216 #define CMD_FOCUS_WARN_CHILDREN \
1217  do { \
1218  int count = 0; \
1219  owindow *current; \
1220  TAILQ_FOREACH(current, &owindows, owindows) { \
1221  count++; \
1222  } \
1223  \
1224  if (count > 1) { \
1225  LOG("WARNING: Your criteria for the focus command matches %d containers, " \
1226  "while only exactly one container can be focused at a time.\n", \
1227  count); \
1228  } \
1229  } while (0)
1230 
1231 /*
1232  * Implementation of 'focus left|right|up|down|next|prev'.
1233  *
1234  */
1235 void cmd_focus_direction(I3_CMD, const char *direction_str) {
1238 
1239  direction_t direction;
1240  position_t position;
1241  bool auto_direction = true;
1242  if (strcmp(direction_str, "prev") == 0) {
1243  position = BEFORE;
1244  } else if (strcmp(direction_str, "next") == 0) {
1245  position = AFTER;
1246  } else {
1247  auto_direction = false;
1248  direction = parse_direction(direction_str);
1249  }
1250 
1251  owindow *current;
1252  TAILQ_FOREACH(current, &owindows, owindows) {
1253  Con *ws = con_get_workspace(current->con);
1254  if (!ws || con_is_internal(ws)) {
1255  continue;
1256  }
1257  if (auto_direction) {
1258  orientation_t o = con_orientation(current->con->parent);
1259  direction = direction_from_orientation_position(o, position);
1260  }
1261  tree_next(current->con, direction);
1262  }
1263 
1264  cmd_output->needs_tree_render = true;
1265  // XXX: default reply for now, make this a better reply
1266  ysuccess(true);
1267 }
1268 
1269 /*
1270  * Implementation of 'focus next|prev sibling'
1271  *
1272  */
1273 void cmd_focus_sibling(I3_CMD, const char *direction_str) {
1276 
1277  const position_t direction = (STARTS_WITH(direction_str, "prev")) ? BEFORE : AFTER;
1278  owindow *current;
1279  TAILQ_FOREACH(current, &owindows, owindows) {
1280  Con *ws = con_get_workspace(current->con);
1281  if (!ws || con_is_internal(ws)) {
1282  continue;
1283  }
1284  Con *next = get_tree_next_sibling(current->con, direction);
1285  if (next) {
1286  if (next->type == CT_WORKSPACE) {
1287  /* On the workspace level, we need to make sure that the
1288  * workspace change happens properly. However, workspace_show
1289  * descends focus so we also have to put focus on the workspace
1290  * itself to maintain consistency. See #3997. */
1291  workspace_show(next);
1292  con_focus(next);
1293  } else {
1294  con_activate(next);
1295  }
1296  }
1297  }
1298 
1299  cmd_output->needs_tree_render = true;
1300  // XXX: default reply for now, make this a better reply
1301  ysuccess(true);
1302 }
1303 
1304 /*
1305  * Implementation of 'focus tiling|floating|mode_toggle'.
1306  *
1307  */
1308 void cmd_focus_window_mode(I3_CMD, const char *window_mode) {
1309  DLOG("window_mode = %s\n", window_mode);
1310 
1311  bool to_floating = false;
1312  if (strcmp(window_mode, "mode_toggle") == 0) {
1313  to_floating = !con_inside_floating(focused);
1314  } else if (strcmp(window_mode, "floating") == 0) {
1315  to_floating = true;
1316  } else if (strcmp(window_mode, "tiling") == 0) {
1317  to_floating = false;
1318  }
1319 
1320  Con *ws = con_get_workspace(focused);
1321  Con *current;
1322  bool success = false;
1323  TAILQ_FOREACH(current, &(ws->focus_head), focused) {
1324  if ((to_floating && current->type != CT_FLOATING_CON) ||
1325  (!to_floating && current->type == CT_FLOATING_CON))
1326  continue;
1327 
1329  success = true;
1330  break;
1331  }
1332 
1333  if (success) {
1334  cmd_output->needs_tree_render = true;
1335  ysuccess(true);
1336  } else {
1337  yerror("Failed to find a %s container in workspace.", to_floating ? "floating" : "tiling");
1338  }
1339 }
1340 
1341 /*
1342  * Implementation of 'focus parent|child'.
1343  *
1344  */
1345 void cmd_focus_level(I3_CMD, const char *level) {
1346  DLOG("level = %s\n", level);
1347  bool success = false;
1348 
1349  /* Focusing the parent can only be allowed if the newly
1350  * focused container won't escape the fullscreen container. */
1351  if (strcmp(level, "parent") == 0) {
1352  if (focused && focused->parent) {
1354  success = level_up();
1355  else
1356  ELOG("'focus parent': Currently in fullscreen, not going up\n");
1357  }
1358  }
1359 
1360  /* Focusing a child should always be allowed. */
1361  else
1362  success = level_down();
1363 
1364  cmd_output->needs_tree_render = success;
1365  // XXX: default reply for now, make this a better reply
1366  ysuccess(success);
1367 }
1368 
1369 /*
1370  * Implementation of 'focus'.
1371  *
1372  */
1374  DLOG("current_match = %p\n", current_match);
1375 
1377  ELOG("You have to specify which window/container should be focused.\n");
1378  ELOG("Example: [class=\"urxvt\" title=\"irssi\"] focus\n");
1379 
1380  yerror("You have to specify which window/container should be focused");
1381  return;
1382  } else if (TAILQ_EMPTY(&owindows)) {
1383  yerror("No window matches given criteria");
1384  return;
1385  }
1386 
1388 
1389  Con *__i3_scratch = workspace_get("__i3_scratch", NULL);
1390  owindow *current;
1391  TAILQ_FOREACH(current, &owindows, owindows) {
1392  Con *ws = con_get_workspace(current->con);
1393  /* If no workspace could be found, this was a dock window.
1394  * Just skip it, you cannot focus dock windows. */
1395  if (!ws)
1396  continue;
1397 
1398  /* In case this is a scratchpad window, call scratchpad_show(). */
1399  if (ws == __i3_scratch) {
1400  scratchpad_show(current->con);
1401  /* While for the normal focus case we can change focus multiple
1402  * times and only a single window ends up focused, we could show
1403  * multiple scratchpad windows. So, rather break here. */
1404  break;
1405  }
1406 
1407  LOG("focusing %p / %s\n", current->con, current->con->name);
1408  con_activate_unblock(current->con);
1409  }
1410 
1411  cmd_output->needs_tree_render = true;
1412  ysuccess(true);
1413 }
1414 
1415 /*
1416  * Implementation of 'fullscreen enable|toggle [global]' and
1417  * 'fullscreen disable'
1418  *
1419  */
1420 void cmd_fullscreen(I3_CMD, const char *action, const char *fullscreen_mode) {
1421  fullscreen_mode_t mode = strcmp(fullscreen_mode, "global") == 0 ? CF_GLOBAL : CF_OUTPUT;
1422  DLOG("%s fullscreen, mode = %s\n", action, fullscreen_mode);
1423  owindow *current;
1424 
1426 
1427  TAILQ_FOREACH(current, &owindows, owindows) {
1428  DLOG("matching: %p / %s\n", current->con, current->con->name);
1429  if (strcmp(action, "toggle") == 0) {
1430  con_toggle_fullscreen(current->con, mode);
1431  } else if (strcmp(action, "enable") == 0) {
1432  con_enable_fullscreen(current->con, mode);
1433  } else if (strcmp(action, "disable") == 0) {
1434  con_disable_fullscreen(current->con);
1435  }
1436  }
1437 
1438  cmd_output->needs_tree_render = true;
1439  // XXX: default reply for now, make this a better reply
1440  ysuccess(true);
1441 }
1442 
1443 /*
1444  * Implementation of 'sticky enable|disable|toggle'.
1445  *
1446  */
1447 void cmd_sticky(I3_CMD, const char *action) {
1448  DLOG("%s sticky on window\n", action);
1450 
1451  owindow *current;
1452  TAILQ_FOREACH(current, &owindows, owindows) {
1453  if (current->con->window == NULL) {
1454  ELOG("only containers holding a window can be made sticky, skipping con = %p\n", current->con);
1455  continue;
1456  }
1457  DLOG("setting sticky for container = %p / %s\n", current->con, current->con->name);
1458 
1459  bool sticky = false;
1460  if (strcmp(action, "enable") == 0)
1461  sticky = true;
1462  else if (strcmp(action, "disable") == 0)
1463  sticky = false;
1464  else if (strcmp(action, "toggle") == 0)
1465  sticky = !current->con->sticky;
1466 
1467  current->con->sticky = sticky;
1468  ewmh_update_sticky(current->con->window->id, sticky);
1469  }
1470 
1471  /* A window we made sticky might not be on a visible workspace right now, so we need to make
1472  * sure it gets pushed to the front now. */
1474 
1476 
1477  cmd_output->needs_tree_render = true;
1478  ysuccess(true);
1479 }
1480 
1481 /*
1482  * Implementation of 'move <direction> [<pixels> [px]]'.
1483  *
1484  */
1485 void cmd_move_direction(I3_CMD, const char *direction_str, long move_px) {
1486  owindow *current;
1488 
1489  Con *initially_focused = focused;
1490  direction_t direction = parse_direction(direction_str);
1491 
1492  TAILQ_FOREACH(current, &owindows, owindows) {
1493  DLOG("moving in direction %s, px %ld\n", direction_str, move_px);
1494  if (con_is_floating(current->con)) {
1495  DLOG("floating move with %ld pixels\n", move_px);
1496  Rect newrect = current->con->parent->rect;
1497 
1498  switch (direction) {
1499  case D_LEFT:
1500  newrect.x -= move_px;
1501  break;
1502  case D_RIGHT:
1503  newrect.x += move_px;
1504  break;
1505  case D_UP:
1506  newrect.y -= move_px;
1507  break;
1508  case D_DOWN:
1509  newrect.y += move_px;
1510  break;
1511  }
1512 
1513  cmd_output->needs_tree_render = floating_reposition(current->con->parent, newrect);
1514  } else {
1515  tree_move(current->con, direction);
1516  cmd_output->needs_tree_render = true;
1517  }
1518  }
1519 
1520  /* The move command should not disturb focus. con_exists is called because
1521  * tree_move calls tree_flatten. */
1522  if (focused != initially_focused && con_exists(initially_focused)) {
1523  con_activate(initially_focused);
1524  }
1525 
1526  // XXX: default reply for now, make this a better reply
1527  ysuccess(true);
1528 }
1529 
1530 /*
1531  * Implementation of 'layout default|stacked|stacking|tabbed|splitv|splith'.
1532  *
1533  */
1534 void cmd_layout(I3_CMD, const char *layout_str) {
1536 
1537  layout_t layout;
1538  if (!layout_from_name(layout_str, &layout)) {
1539  yerror("Unknown layout \"%s\", this is a mismatch between code and parser spec.", layout_str);
1540  return;
1541  }
1542 
1543  DLOG("changing layout to %s (%d)\n", layout_str, layout);
1544 
1545  owindow *current;
1546  TAILQ_FOREACH(current, &owindows, owindows) {
1547  if (con_is_docked(current->con)) {
1548  ELOG("cannot change layout of a docked container, skipping it.\n");
1549  continue;
1550  }
1551 
1552  DLOG("matching: %p / %s\n", current->con, current->con->name);
1553  con_set_layout(current->con, layout);
1554  }
1555 
1556  cmd_output->needs_tree_render = true;
1557  // XXX: default reply for now, make this a better reply
1558  ysuccess(true);
1559 }
1560 
1561 /*
1562  * Implementation of 'layout toggle [all|split]'.
1563  *
1564  */
1565 void cmd_layout_toggle(I3_CMD, const char *toggle_mode) {
1566  owindow *current;
1567 
1568  if (toggle_mode == NULL)
1569  toggle_mode = "default";
1570 
1571  DLOG("toggling layout (mode = %s)\n", toggle_mode);
1572 
1573  /* check if the match is empty, not if the result is empty */
1575  con_toggle_layout(focused, toggle_mode);
1576  else {
1577  TAILQ_FOREACH(current, &owindows, owindows) {
1578  DLOG("matching: %p / %s\n", current->con, current->con->name);
1579  con_toggle_layout(current->con, toggle_mode);
1580  }
1581  }
1582 
1583  cmd_output->needs_tree_render = true;
1584  // XXX: default reply for now, make this a better reply
1585  ysuccess(true);
1586 }
1587 
1588 /*
1589  * Implementation of 'exit'.
1590  *
1591  */
1593  LOG("Exiting due to user command.\n");
1594  exit(EXIT_SUCCESS);
1595 
1596  /* unreached */
1597 }
1598 
1599 /*
1600  * Implementation of 'reload'.
1601  *
1602  */
1604  LOG("reloading\n");
1608  x_set_i3_atoms();
1609  /* Send an IPC event just in case the ws names have changed */
1610  ipc_send_workspace_event("reload", NULL, NULL);
1611  /* Send an update event for the barconfig just in case it has changed */
1612  update_barconfig();
1613 
1614  // XXX: default reply for now, make this a better reply
1615  ysuccess(true);
1616 }
1617 
1618 /*
1619  * Implementation of 'restart'.
1620  *
1621  */
1623  LOG("restarting i3\n");
1624  int exempt_fd = -1;
1625  if (cmd_output->client != NULL) {
1626  exempt_fd = cmd_output->client->fd;
1627  LOG("Carrying file descriptor %d across restart\n", exempt_fd);
1628  int flags;
1629  if ((flags = fcntl(exempt_fd, F_GETFD)) < 0 ||
1630  fcntl(exempt_fd, F_SETFD, flags & ~FD_CLOEXEC) < 0) {
1631  ELOG("Could not disable FD_CLOEXEC on fd %d\n", exempt_fd);
1632  }
1633  char *fdstr = NULL;
1634  sasprintf(&fdstr, "%d", exempt_fd);
1635  setenv("_I3_RESTART_FD", fdstr, 1);
1636  }
1638  unlink(config.ipc_socket_path);
1639  /* We need to call this manually since atexit handlers don’t get called
1640  * when exec()ing */
1642  i3_restart(false);
1643  /* unreached */
1644  assert(false);
1645 }
1646 
1647 /*
1648  * Implementation of 'open'.
1649  *
1650  */
1652  LOG("opening new container\n");
1653  Con *con = tree_open_con(NULL, NULL);
1654  con->layout = L_SPLITH;
1655  con_activate(con);
1656 
1657  y(map_open);
1658  ystr("success");
1659  y(bool, true);
1660  ystr("id");
1661  y(integer, (uintptr_t)con);
1662  y(map_close);
1663 
1664  cmd_output->needs_tree_render = true;
1665 }
1666 
1667 /*
1668  * Implementation of 'focus output <output>'.
1669  *
1670  */
1671 void cmd_focus_output(I3_CMD, const char *name) {
1673 
1674  if (TAILQ_EMPTY(&owindows)) {
1675  ysuccess(true);
1676  return;
1677  }
1678 
1679  Output *current_output = get_output_for_con(TAILQ_FIRST(&owindows)->con);
1680  Output *output = get_output_from_string(current_output, name);
1681 
1682  if (!output) {
1683  yerror("Output %s not found.", name);
1684  return;
1685  }
1686 
1687  /* get visible workspace on output */
1688  Con *ws = NULL;
1689  GREP_FIRST(ws, output_get_content(output->con), workspace_is_visible(child));
1690  if (!ws) {
1691  yerror("BUG: No workspace found on output.");
1692  return;
1693  }
1694 
1695  workspace_show(ws);
1696 
1697  cmd_output->needs_tree_render = true;
1698  ysuccess(true);
1699 }
1700 
1701 /*
1702  * Implementation of 'move [window|container] [to] [absolute] position <px> [px] <px> [px]
1703  *
1704  */
1705 void cmd_move_window_to_position(I3_CMD, long x, long y) {
1706  bool has_error = false;
1707 
1708  owindow *current;
1710 
1711  TAILQ_FOREACH(current, &owindows, owindows) {
1712  if (!con_is_floating(current->con)) {
1713  ELOG("Cannot change position. The window/container is not floating\n");
1714 
1715  if (!has_error) {
1716  yerror("Cannot change position of a window/container because it is not floating.");
1717  has_error = true;
1718  }
1719 
1720  continue;
1721  }
1722 
1723  Rect newrect = current->con->parent->rect;
1724 
1725  DLOG("moving to position %ld %ld\n", x, y);
1726  newrect.x = x;
1727  newrect.y = y;
1728 
1729  if (!floating_reposition(current->con->parent, newrect)) {
1730  yerror("Cannot move window/container out of bounds.");
1731  has_error = true;
1732  }
1733  }
1734 
1735  if (!has_error)
1736  ysuccess(true);
1737 }
1738 
1739 /*
1740  * Implementation of 'move [window|container] [to] [absolute] position center
1741  *
1742  */
1743 void cmd_move_window_to_center(I3_CMD, const char *method) {
1744  bool has_error = false;
1746 
1747  owindow *current;
1748  TAILQ_FOREACH(current, &owindows, owindows) {
1749  Con *floating_con = con_inside_floating(current->con);
1750  if (floating_con == NULL) {
1751  ELOG("con %p / %s is not floating, cannot move it to the center.\n",
1752  current->con, current->con->name);
1753 
1754  if (!has_error) {
1755  yerror("Cannot change position of a window/container because it is not floating.");
1756  has_error = true;
1757  }
1758 
1759  continue;
1760  }
1761 
1762  if (strcmp(method, "absolute") == 0) {
1763  DLOG("moving to absolute center\n");
1764  floating_center(floating_con, croot->rect);
1765 
1766  floating_maybe_reassign_ws(floating_con);
1767  cmd_output->needs_tree_render = true;
1768  }
1769 
1770  if (strcmp(method, "position") == 0) {
1771  DLOG("moving to center\n");
1772  floating_center(floating_con, con_get_workspace(floating_con)->rect);
1773 
1774  cmd_output->needs_tree_render = true;
1775  }
1776  }
1777 
1778  // XXX: default reply for now, make this a better reply
1779  if (!has_error)
1780  ysuccess(true);
1781 }
1782 
1783 /*
1784  * Implementation of 'move [window|container] [to] position mouse'
1785  *
1786  */
1789 
1790  owindow *current;
1791  TAILQ_FOREACH(current, &owindows, owindows) {
1792  Con *floating_con = con_inside_floating(current->con);
1793  if (floating_con == NULL) {
1794  DLOG("con %p / %s is not floating, cannot move it to the mouse position.\n",
1795  current->con, current->con->name);
1796  continue;
1797  }
1798 
1799  DLOG("moving floating container %p / %s to cursor position\n", floating_con, floating_con->name);
1800  floating_move_to_pointer(floating_con);
1801  }
1802 
1803  cmd_output->needs_tree_render = true;
1804  ysuccess(true);
1805 }
1806 
1807 /*
1808  * Implementation of 'move scratchpad'.
1809  *
1810  */
1812  DLOG("should move window to scratchpad\n");
1813  owindow *current;
1814 
1816 
1817  TAILQ_FOREACH(current, &owindows, owindows) {
1818  DLOG("matching: %p / %s\n", current->con, current->con->name);
1819  scratchpad_move(current->con);
1820  }
1821 
1822  cmd_output->needs_tree_render = true;
1823  // XXX: default reply for now, make this a better reply
1824  ysuccess(true);
1825 }
1826 
1827 /*
1828  * Implementation of 'scratchpad show'.
1829  *
1830  */
1832  DLOG("should show scratchpad window\n");
1833  owindow *current;
1834  bool result = false;
1835 
1837  result = scratchpad_show(NULL);
1838  } else {
1839  TAILQ_FOREACH(current, &owindows, owindows) {
1840  DLOG("matching: %p / %s\n", current->con, current->con->name);
1841  result |= scratchpad_show(current->con);
1842  }
1843  }
1844 
1845  cmd_output->needs_tree_render = true;
1846 
1847  ysuccess(result);
1848 }
1849 
1850 /*
1851  * Implementation of 'swap [container] [with] id|con_id|mark <arg>'.
1852  *
1853  */
1854 void cmd_swap(I3_CMD, const char *mode, const char *arg) {
1856 
1857  owindow *match = TAILQ_FIRST(&owindows);
1858  if (match == NULL) {
1859  yerror("No match found for swapping.");
1860  return;
1861  }
1862  if (match->con == NULL) {
1863  yerror("Match %p has no container.", match);
1864  return;
1865  }
1866 
1867  Con *con;
1868  if (strcmp(mode, "id") == 0) {
1869  long target;
1870  if (!parse_long(arg, &target, 0)) {
1871  yerror("Failed to parse %s into a window id.", arg);
1872  return;
1873  }
1874 
1875  con = con_by_window_id(target);
1876  } else if (strcmp(mode, "con_id") == 0) {
1877  long target;
1878  if (!parse_long(arg, &target, 0)) {
1879  yerror("Failed to parse %s into a container id.", arg);
1880  return;
1881  }
1882 
1883  con = con_by_con_id(target);
1884  } else if (strcmp(mode, "mark") == 0) {
1885  con = con_by_mark(arg);
1886  } else {
1887  yerror("Unhandled swap mode \"%s\". This is a bug.", mode);
1888  return;
1889  }
1890 
1891  if (con == NULL) {
1892  yerror("Could not find container for %s = %s", mode, arg);
1893  return;
1894  }
1895 
1896  if (match != TAILQ_LAST(&owindows, owindows_head)) {
1897  LOG("More than one container matched the swap command, only using the first one.");
1898  }
1899 
1900  DLOG("Swapping %p with %p.\n", match->con, con);
1901  bool result = con_swap(match->con, con);
1902 
1903  cmd_output->needs_tree_render = true;
1904  // XXX: default reply for now, make this a better reply
1905  ysuccess(result);
1906 }
1907 
1908 /*
1909  * Implementation of 'title_format <format>'
1910  *
1911  */
1912 void cmd_title_format(I3_CMD, const char *format) {
1913  DLOG("setting title_format to \"%s\"\n", format);
1915 
1916  owindow *current;
1917  TAILQ_FOREACH(current, &owindows, owindows) {
1918  DLOG("setting title_format for %p / %s\n", current->con, current->con->name);
1919  FREE(current->con->title_format);
1920 
1921  /* If we only display the title without anything else, we can skip the parsing step,
1922  * so we remove the title format altogether. */
1923  if (strcasecmp(format, "%title") != 0) {
1924  current->con->title_format = sstrdup(format);
1925 
1926  if (current->con->window != NULL) {
1927  i3String *formatted_title = con_parse_title_format(current->con);
1928  ewmh_update_visible_name(current->con->window->id, i3string_as_utf8(formatted_title));
1929  I3STRING_FREE(formatted_title);
1930  }
1931  } else {
1932  if (current->con->window != NULL) {
1933  /* We can remove _NET_WM_VISIBLE_NAME since we don't display a custom title. */
1934  ewmh_update_visible_name(current->con->window->id, NULL);
1935  }
1936  }
1937 
1938  if (current->con->window != NULL) {
1939  /* Make sure the window title is redrawn immediately. */
1940  current->con->window->name_x_changed = true;
1941  } else {
1942  /* For windowless containers we also need to force the redrawing. */
1943  FREE(current->con->deco_render_params);
1944  }
1945  }
1946 
1947  cmd_output->needs_tree_render = true;
1948  ysuccess(true);
1949 }
1950 
1951 /*
1952  * Implementation of 'rename workspace [<name>] to <name>'
1953  *
1954  */
1955 void cmd_rename_workspace(I3_CMD, const char *old_name, const char *new_name) {
1956  if (strncasecmp(new_name, "__", strlen("__")) == 0) {
1957  yerror("Cannot rename workspace to \"%s\": names starting with __ are i3-internal.", new_name);
1958  return;
1959  }
1960  if (old_name) {
1961  LOG("Renaming workspace \"%s\" to \"%s\"\n", old_name, new_name);
1962  } else {
1963  LOG("Renaming current workspace to \"%s\"\n", new_name);
1964  }
1965 
1966  Con *workspace;
1967  if (old_name) {
1968  workspace = get_existing_workspace_by_name(old_name);
1969  } else {
1970  workspace = con_get_workspace(focused);
1971  old_name = workspace->name;
1972  }
1973 
1974  if (!workspace) {
1975  yerror("Old workspace \"%s\" not found", old_name);
1976  return;
1977  }
1978 
1979  Con *check_dest = get_existing_workspace_by_name(new_name);
1980 
1981  /* If check_dest == workspace, the user might be changing the case of the
1982  * workspace, or it might just be a no-op. */
1983  if (check_dest != NULL && check_dest != workspace) {
1984  yerror("New workspace \"%s\" already exists", new_name);
1985  return;
1986  }
1987 
1988  /* Change the name and try to parse it as a number. */
1989  /* old_name might refer to workspace->name, so copy it before free()ing */
1990  char *old_name_copy = sstrdup(old_name);
1991  FREE(workspace->name);
1992  workspace->name = sstrdup(new_name);
1993 
1994  workspace->num = ws_name_to_number(new_name);
1995  LOG("num = %d\n", workspace->num);
1996 
1997  /* By re-attaching, the sort order will be correct afterwards. */
1998  Con *previously_focused = focused;
1999  Con *previously_focused_content = focused->type == CT_WORKSPACE ? focused->parent : NULL;
2000  Con *parent = workspace->parent;
2001  con_detach(workspace);
2002  con_attach(workspace, parent, false);
2003  ipc_send_workspace_event("rename", workspace, NULL);
2004 
2005  /* Move the workspace to the correct output if it has an assignment */
2006  struct Workspace_Assignment *assignment = NULL;
2008  if (assignment->output == NULL)
2009  continue;
2010  if (strcmp(assignment->name, workspace->name) != 0 && (!name_is_digits(assignment->name) || ws_name_to_number(assignment->name) != workspace->num)) {
2011  continue;
2012  }
2013 
2014  Output *target_output = get_output_by_name(assignment->output, true);
2015  if (!target_output) {
2016  LOG("Could not get output named \"%s\"\n", assignment->output);
2017  continue;
2018  }
2019  if (!output_triggers_assignment(target_output, assignment)) {
2020  continue;
2021  }
2022  workspace_move_to_output(workspace, target_output);
2023 
2024  break;
2025  }
2026 
2027  bool can_restore_focus = previously_focused != NULL;
2028  /* NB: If previously_focused is a workspace we can't work directly with it
2029  * since it might have been cleaned up by workspace_show() already,
2030  * depending on the focus order/number of other workspaces on the output.
2031  * Instead, we loop through the available workspaces and only focus
2032  * previously_focused if we still find it. */
2033  if (previously_focused_content) {
2034  Con *workspace = NULL;
2035  GREP_FIRST(workspace, previously_focused_content, child == previously_focused);
2036  can_restore_focus &= (workspace != NULL);
2037  }
2038 
2039  if (can_restore_focus) {
2040  /* Restore the previous focus since con_attach messes with the focus. */
2041  workspace_show(con_get_workspace(previously_focused));
2042  con_focus(previously_focused);
2043  }
2044 
2045  /* Let back-and-forth work after renaming the previous workspace.
2046  * See #3694. */
2047  if (previous_workspace_name && !strcmp(previous_workspace_name, old_name_copy)) {
2049  previous_workspace_name = sstrdup(new_name);
2050  }
2051 
2052  cmd_output->needs_tree_render = true;
2053  ysuccess(true);
2054 
2056 
2057  startup_sequence_rename_workspace(old_name_copy, new_name);
2058  free(old_name_copy);
2059 }
2060 
2061 /*
2062  * Implementation of 'bar mode dock|hide|invisible|toggle [<bar_id>]'
2063  *
2064  */
2065 static bool cmd_bar_mode(const char *bar_mode, const char *bar_id) {
2066  int mode = M_DOCK;
2067  bool toggle = false;
2068  if (strcmp(bar_mode, "dock") == 0)
2069  mode = M_DOCK;
2070  else if (strcmp(bar_mode, "hide") == 0)
2071  mode = M_HIDE;
2072  else if (strcmp(bar_mode, "invisible") == 0)
2073  mode = M_INVISIBLE;
2074  else if (strcmp(bar_mode, "toggle") == 0)
2075  toggle = true;
2076  else {
2077  ELOG("Unknown bar mode \"%s\", this is a mismatch between code and parser spec.\n", bar_mode);
2078  return false;
2079  }
2080 
2081  bool changed_sth = false;
2082  Barconfig *current = NULL;
2083  TAILQ_FOREACH(current, &barconfigs, configs) {
2084  if (bar_id && strcmp(current->id, bar_id) != 0)
2085  continue;
2086 
2087  if (toggle)
2088  mode = (current->mode + 1) % 2;
2089 
2090  DLOG("Changing bar mode of bar_id '%s' to '%s (%d)'\n", current->id, bar_mode, mode);
2091  current->mode = mode;
2092  changed_sth = true;
2093 
2094  if (bar_id)
2095  break;
2096  }
2097 
2098  if (bar_id && !changed_sth) {
2099  DLOG("Changing bar mode of bar_id %s failed, bar_id not found.\n", bar_id);
2100  return false;
2101  }
2102 
2103  return true;
2104 }
2105 
2106 /*
2107  * Implementation of 'bar hidden_state hide|show|toggle [<bar_id>]'
2108  *
2109  */
2110 static bool cmd_bar_hidden_state(const char *bar_hidden_state, const char *bar_id) {
2111  int hidden_state = S_SHOW;
2112  bool toggle = false;
2113  if (strcmp(bar_hidden_state, "hide") == 0)
2114  hidden_state = S_HIDE;
2115  else if (strcmp(bar_hidden_state, "show") == 0)
2116  hidden_state = S_SHOW;
2117  else if (strcmp(bar_hidden_state, "toggle") == 0)
2118  toggle = true;
2119  else {
2120  ELOG("Unknown bar state \"%s\", this is a mismatch between code and parser spec.\n", bar_hidden_state);
2121  return false;
2122  }
2123 
2124  bool changed_sth = false;
2125  Barconfig *current = NULL;
2126  TAILQ_FOREACH(current, &barconfigs, configs) {
2127  if (bar_id && strcmp(current->id, bar_id) != 0)
2128  continue;
2129 
2130  if (toggle)
2131  hidden_state = (current->hidden_state + 1) % 2;
2132 
2133  DLOG("Changing bar hidden_state of bar_id '%s' to '%s (%d)'\n", current->id, bar_hidden_state, hidden_state);
2134  current->hidden_state = hidden_state;
2135  changed_sth = true;
2136 
2137  if (bar_id)
2138  break;
2139  }
2140 
2141  if (bar_id && !changed_sth) {
2142  DLOG("Changing bar hidden_state of bar_id %s failed, bar_id not found.\n", bar_id);
2143  return false;
2144  }
2145 
2146  return true;
2147 }
2148 
2149 /*
2150  * Implementation of 'bar (hidden_state hide|show|toggle)|(mode dock|hide|invisible|toggle) [<bar_id>]'
2151  *
2152  */
2153 void cmd_bar(I3_CMD, const char *bar_type, const char *bar_value, const char *bar_id) {
2154  bool ret;
2155  if (strcmp(bar_type, "mode") == 0)
2156  ret = cmd_bar_mode(bar_value, bar_id);
2157  else if (strcmp(bar_type, "hidden_state") == 0)
2158  ret = cmd_bar_hidden_state(bar_value, bar_id);
2159  else {
2160  ELOG("Unknown bar option type \"%s\", this is a mismatch between code and parser spec.\n", bar_type);
2161  ret = false;
2162  }
2163 
2164  ysuccess(ret);
2165  if (!ret)
2166  return;
2167 
2168  update_barconfig();
2169 }
2170 
2171 /*
2172  * Implementation of 'shmlog <size>|toggle|on|off'
2173  *
2174  */
2175 void cmd_shmlog(I3_CMD, const char *argument) {
2176  if (!strcmp(argument, "toggle"))
2177  /* Toggle shm log, if size is not 0. If it is 0, set it to default. */
2179  else if (!strcmp(argument, "on"))
2181  else if (!strcmp(argument, "off"))
2182  shmlog_size = 0;
2183  else {
2184  long new_size = 0;
2185  if (!parse_long(argument, &new_size, 0)) {
2186  yerror("Failed to parse %s into a shmlog size.", argument);
2187  return;
2188  }
2189  /* If shm logging now, restart logging with the new size. */
2190  if (shmlog_size > 0) {
2191  shmlog_size = 0;
2192  LOG("Restarting shm logging...\n");
2193  init_logging();
2194  }
2195  shmlog_size = (int)new_size;
2196  }
2197  LOG("%s shm logging\n", shmlog_size > 0 ? "Enabling" : "Disabling");
2198  init_logging();
2200  ysuccess(true);
2201 }
2202 
2203 /*
2204  * Implementation of 'debuglog toggle|on|off'
2205  *
2206  */
2207 void cmd_debuglog(I3_CMD, const char *argument) {
2208  bool logging = get_debug_logging();
2209  if (!strcmp(argument, "toggle")) {
2210  LOG("%s debug logging\n", logging ? "Disabling" : "Enabling");
2211  set_debug_logging(!logging);
2212  } else if (!strcmp(argument, "on") && !logging) {
2213  LOG("Enabling debug logging\n");
2214  set_debug_logging(true);
2215  } else if (!strcmp(argument, "off") && logging) {
2216  LOG("Disabling debug logging\n");
2217  set_debug_logging(false);
2218  }
2219  // XXX: default reply for now, make this a better reply
2220  ysuccess(true);
2221 }
struct _i3String i3String
Opaque data structure for storing strings.
Definition: libi3.h:48
uint32_t height
Definition: data.h:179
bool name_x_changed
Flag to force re-rendering the decoration upon changes.
Definition: data.h:459
Stores a rectangle, for example the size of a window, the child window etc.
Definition: data.h:175
marks_head
Definition: data.h:699
void cmd_reload(I3_CMD)
Implementation of 'reload'.
Definition: commands.c:1603
bool con_move_to_mark(Con *con, const char *mark)
Moves the given container to the given mark.
Definition: con.c:1329
void con_detach(Con *con)
Detaches the given container from its current parent.
Definition: con.c:206
Con * workspace_get(const char *num, bool *created)
Returns a pointer to the workspace with the given number (starting at 0), creating the workspace if n...
Definition: workspace.c:125
void tree_append_json(Con *con, const char *buf, const size_t len, char **errormsg)
Definition: load_layout.c:623
Definition: data.h:100
void workspace_show_by_name(const char *num)
Looks up the workspace by name and switches to it.
Definition: workspace.c:553
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:347
void cmd_kill(I3_CMD, const char *kill_mode_str)
Implementation of 'kill [window|client]'.
Definition: commands.c:1159
bool json_validate(const char *buf, const size_t len)
Returns true if the provided JSON could be parsed by yajl.
Definition: load_layout.c:563
void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, const char *mode_height)
Implementation of 'resize set <width> [px | ppt] <height> [px | ppt]'.
Definition: commands.c:659
void cmd_mark(I3_CMD, const char *mark, const char *mode, const char *toggle)
Implementation of 'mark [–add|–replace] [–toggle] <mark>'.
Definition: commands.c:955
#define LOG(fmt,...)
Definition: libi3.h:94
focus_head
Definition: data.h:725
Holds an intermediate represenation of the result of a call to any command.
bool con_swap(Con *first, Con *second)
Swaps the two containers.
Definition: con.c:2306
void cmd_title_format(I3_CMD, const char *format)
Implementation of 'title_format <format>'.
Definition: commands.c:1912
bool con_exists(Con *con)
Returns true if the given container (still) exists.
Definition: con.c:676
void cmd_open(I3_CMD)
Implementation of 'open'.
Definition: commands.c:1651
void cmd_move_window_to_position(I3_CMD, long x, long y)
Implementation of 'move [window|container] [to] [absolute] position <px> [px] <px> [px].
Definition: commands.c:1705
void cmd_workspace_name(I3_CMD, const char *name, const char *_no_auto_back_and_forth)
Implementation of 'workspace [–no-auto-back-and-forth] <name>'.
Definition: commands.c:926
void set_debug_logging(const bool _debug_logging)
Set debug logging.
Definition: log.c:214
Con * get_existing_workspace_by_name(const char *name)
Returns the workspace with the given name or NULL if such a workspace does not exist.
Definition: workspace.c:30
Con * con
Pointer to the Con which represents this output.
Definition: data.h:414
void update_barconfig(void)
Sends the current bar configuration as an event to all barconfig_update listeners.
Definition: config.c:35
void cmd_rename_workspace(I3_CMD, const char *old_name, const char *new_name)
Implementation of 'rename workspace <name> to <name>'.
Definition: commands.c:1955
Definition: data.h:64
struct barconfig_head barconfigs
Definition: config.c:19
#define yerror(format,...)
Definition: commands.c:32
void cmd_criteria_add(I3_CMD, const char *ctype, const char *cvalue)
Interprets a ctype=cvalue pair and adds it to the current match specification.
Definition: commands.c:258
struct Window * window
Definition: data.h:709
void x_set_i3_atoms(void)
Sets up i3 specific atoms (I3_SOCKET_PATH and I3_CONFIG_PATH)
Definition: x.c:1429
void ipc_shutdown(shutdown_reason_t reason, int exempt_fd)
Calls shutdown() on each socket and closes it.
Definition: ipc.c:206
void purge_zerobyte_logfile(void)
Deletes the unused log files.
Definition: log.c:355
void cmd_move_con_to_output(I3_CMD, const char *name)
Implementation of 'move [window|container] [to] output <str>'.
Definition: commands.c:1019
direction_t direction_from_orientation_position(orientation_t orientation, position_t position)
Convert orientation and position to the corresponding direction.
Definition: util.c:498
char * title_format
The format with which the window's name should be displayed.
Definition: data.h:690
A 'Window' is a type which contains an xcb_window_t and all the related information (hints like _NET_...
Definition: data.h:428
Definition: data.h:65
bool layout_from_name(const char *layout_str, layout_t *out)
Set 'out' to the layout_t value for the given layout.
Definition: util.c:79
#define y(x,...)
Definition: commands.c:21
position_t
Definition: data.h:62
#define TAILQ_INIT(head)
Definition: queue.h:360
uint32_t width
Definition: data.h:178
layout_t
Container layouts.
Definition: data.h:93
Con * con_by_con_id(long target)
Returns the container with the given container ID or NULL if no such container exists.
Definition: con.c:660
struct Con * croot
Definition: tree.c:12
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...
void switch_mode(const char *new_mode)
Switches the key bindings to the given mode, if the mode exists.
Definition: bindings.c:618
void con_focus(Con *con)
Sets input focus to the given container.
Definition: con.c:222
void cmd_criteria_match_windows(I3_CMD)
A match specification just finished (the closing square bracket was found), so we filter the list of ...
Definition: commands.c:175
bool match_matches_window(Match *match, i3Window *window)
Check if a match data structure matches the given window.
Definition: match.c:87
void floating_center(Con *con, Rect rect)
Centers a floating con above the specified rect.
Definition: floating.c:533
void restore_open_placeholder_windows(Con *parent)
Open placeholder windows for all children of parent.
static bool cmd_bar_hidden_state(const char *bar_hidden_state, const char *bar_id)
Definition: commands.c:2110
void match_free(Match *match)
Frees the given match.
Definition: match.c:241
void startup_sequence_rename_workspace(const char *old_name, const char *new_name)
Renames workspaces that are mentioned in the startup sequences.
Definition: startup.c:265
void workspace_move_to_output(Con *ws, Output *output)
Move the given workspace to the specified output.
Definition: workspace.c:968
A 'Con' represents everything from the X11 root window down to a single X11 window.
Definition: data.h:641
bool load_configuration(const char *override_configpath, config_load_t load_type)
(Re-)loads the configuration file (sets useful defaults before).
Definition: config.c:174
static bool resize_set_tiling(I3_CMD, Con *target, orientation_t resize_orientation, bool is_ppt, long target_size)
Definition: commands.c:626
Output * get_output_from_string(Output *current_output, const char *output_str)
Returns an 'output' corresponding to one of left/right/down/up or a specific output name.
Definition: output.c:31
Con * output_get_content(Con *output)
Returns the output container below the given output container.
Definition: output.c:16
void cmd_resize(I3_CMD, const char *way, const char *direction, long resize_px, long resize_ppt)
Implementation of 'resize grow|shrink <direction> [<px> px] [or <ppt> ppt]'.
Definition: commands.c:580
#define ELOG(fmt,...)
Definition: libi3.h:99
void con_unmark(Con *con, const char *name)
Removes marks from containers.
Definition: con.c:773
nodes_head
Definition: data.h:722
#define I3_CMD
The beginning of the prototype for every cmd_ function.
Definition: commands.h:17
bool floating_reposition(Con *con, Rect newrect)
Repositions the CT_FLOATING_CON to have the coordinates specified by newrect, but only if the coordin...
Definition: floating.c:744
Definition: data.h:66
uint32_t y
Definition: data.h:177
void cmd_fullscreen(I3_CMD, const char *action, const char *fullscreen_mode)
Implementation of 'fullscreen [enable|disable|toggle] [global]'.
Definition: commands.c:1420
struct Rect rect
Definition: data.h:677
#define ysuccess(success)
Definition: commands.c:23
#define GREP_FIRST(dest, head, condition)
Definition: util.h:38
Con * con_inside_floating(Con *con)
Checks if the given container is either floating or inside some floating container.
Definition: con.c:599
Con * get_existing_workspace_by_num(int num)
Returns the workspace with the given number or NULL if such a workspace does not exist.
Definition: workspace.c:44
void cmd_move_window_to_mouse(I3_CMD)
Implementation of 'move [window|container] [to] position mouse'.
Definition: commands.c:1787
Con * con_by_window_id(xcb_window_t window)
Returns the container with the given client window ID or NULL if no such container exists.
Definition: con.c:647
char * resolve_tilde(const char *path)
This function resolves ~ in pathnames.
#define CHECK_MOVE_CON_TO_WORKSPACE
Definition: commands.c:270
orientation_t orientation_from_direction(direction_t direction)
Convert a direction to its corresponding orientation.
Definition: util.c:482
pid_t command_error_nagbar_pid
Definition: bindings.c:17
void cmd_layout_toggle(I3_CMD, const char *toggle_mode)
Implementation of 'layout toggle [all|split]'.
Definition: commands.c:1565
void render_con(Con *con)
"Renders" the given container (and its children), meaning that all rects are updated correctly.
Definition: render.c:40
long ws_name_to_number(const char *name)
Parses the workspace name as a number.
Definition: util.c:106
void con_mark(Con *con, const char *mark, mark_mode_t mode)
Assigns a mark to the container.
Definition: con.c:743
const int default_shmlog_size
Definition: main.c:71
void cmd_criteria_init(I3_CMD)
Initializes the specified 'Match' data structure and the initial state of commands....
void cmd_unmark(I3_CMD, const char *mark)
Implementation of 'unmark [mark]'.
Definition: commands.c:988
void cmd_bar(I3_CMD, const char *bar_type, const char *bar_value, const char *bar_id)
Implementation of 'bar (hidden_state hide|show|toggle)|(mode dock|hide|invisible|toggle) [<bar_id>]'.
Definition: commands.c:2153
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
void cmd_restart(I3_CMD)
Implementation of 'restart'.
Definition: commands.c:1622
void cmd_workspace_back_and_forth(I3_CMD)
Implementation of 'workspace back_and_forth'.
Definition: commands.c:909
Definition: data.h:55
bool level_up(void)
Moves focus one level up.
Definition: tree.c:386
void cmd_layout(I3_CMD, const char *layout_str)
Implementation of 'layout default|stacked|stacking|tabbed|splitv|splith'.
Definition: commands.c:1534
void cmd_move_workspace_to_output(I3_CMD, const char *name)
Implementation of 'move workspace to [output] <str>'.
Definition: commands.c:1090
void cmd_sticky(I3_CMD, const char *action)
Implementation of 'sticky enable|disable|toggle'.
Definition: commands.c:1447
int height_increment
Definition: data.h:498
enum Con::@20 type
char * previous_workspace_name
Stores a copy of the name of the last used workspace for the workspace back-and-forth switching.
Definition: workspace.c:19
struct ws_assignments_head ws_assignments
Definition: main.c:87
ssize_t slurp(const char *path, char **buf)
Slurp reads path in its entirety into buf, returning the length of the file or -1 if the file could n...
Definition: util.c:453
typedef TAILQ_HEAD(owindows_head, owindow)
Definition: commands.c:140
struct pending_marks * marks
bool scratchpad_show(Con *con)
Either shows the top-most scratchpad window (con == NULL) or shows the specified con (if it is scratc...
Definition: scratchpad.c:85
void con_mark_toggle(Con *con, const char *mark, mark_mode_t mode)
Toggles the mark on a container.
Definition: con.c:728
char * name
Definition: data.h:687
void con_toggle_fullscreen(Con *con, int fullscreen_mode)
Toggles fullscreen mode for the given container.
Definition: con.c:1033
void cmd_swap(I3_CMD, const char *mode, const char *arg)
Implementation of 'swap [container] [with] id|con_id|mark <arg>'.
Definition: commands.c:1854
bool sticky
Definition: data.h:735
void cmd_scratchpad_show(I3_CMD)
Implementation of 'scratchpad show'.
Definition: commands.c:1831
layout_t layout
Definition: data.h:751
void cmd_border(I3_CMD, const char *border_style_str, long border_width)
Implementation of 'border normal|pixel [<n>]', 'border none|1pixel|toggle'.
Definition: commands.c:716
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
Definition: con.c:453
Con * con_get_output(Con *con)
Gets the output container (first container with CT_OUTPUT in hierarchy) this node is on.
Definition: con.c:439
void cmd_focus_direction(I3_CMD, const char *direction_str)
Implementation of 'focus left|right|up|down'.
Definition: commands.c:1235
Con * workspace_prev_on_output(void)
Returns the previous workspace on the same output.
Definition: workspace.c:747
void cmd_nop(I3_CMD, const char *comment)
Implementation of 'nop <comment>'.
Definition: commands.c:751
fullscreen_mode_t
Fullscreen modes.
Definition: data.h:626
int con_num_children(Con *con)
Returns the number of children of this container.
Definition: con.c:922
void cmd_move_direction(I3_CMD, const char *direction_str, long move_px)
Implementation of 'move <direction> [<pixels> [px]]'.
Definition: commands.c:1485
bool con_is_floating(Con *con)
Returns true if the node is floating.
Definition: con.c:575
#define TAILQ_EMPTY(head)
Definition: queue.h:344
void cmd_focus_output(I3_CMD, const char *name)
Implementation of 'focus output <output>'.
Definition: commands.c:1671
static bool maybe_back_and_forth(struct CommandResultIR *cmd_output, const char *name)
Definition: commands.c:86
bool level_down(void)
Moves focus one level down.
Definition: tree.c:409
orientation_t con_orientation(Con *con)
Returns the orientation of the given container (for stacked containers, vertical orientation is used ...
Definition: con.c:1443
Con * workspace_next_on_output(void)
Returns the next workspace on the same output.
Definition: workspace.c:692
Definition: data.h:58
bool con_is_docked(Con *con)
Returns true if the container is a docked container.
Definition: con.c:584
bool rect_equals(Rect a, Rect b)
Definition: util.c:56
void cmd_move_scratchpad(I3_CMD)
Implementation of 'move scratchpad'.
Definition: commands.c:1811
struct Con * focused
Definition: tree.c:13
void scratchpad_move(Con *con)
Moves the specified window to the __i3_scratch workspace, making it floating and setting the appropri...
Definition: scratchpad.c:19
#define TAILQ_LAST(head, headname)
Definition: queue.h:339
Con * con
Definition: commands.c:134
bool parse_long(const char *str, long *out, int base)
Converts a string into a long using strtol().
Definition: util.c:435
void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool dont_warp, bool ignore_focus)
Moves the given container to the currently focused container on the given workspace.
Definition: con.c:1392
double percent
Definition: data.h:703
enum Barconfig::@10 hidden_state
bool con_accepts_window(Con *con)
Returns true if this node accepts a window (if the node swallows windows, it might already have swall...
Definition: con.c:420
void con_activate_unblock(Con *con)
Activates the container like in con_activate but removes fullscreen restrictions and properly warps t...
Definition: con.c:273
static void cmd_resize_floating(I3_CMD, const char *direction_str, Con *floating_con, int px)
Definition: commands.c:429
char * name
Definition: data.h:631
void output_push_sticky_windows(Con *old_focus)
Iterates over all outputs and pushes sticky windows to the currently visible workspace on that output...
Definition: output.c:75
int shmlog_size
Definition: log.c:49
#define FREE(pointer)
Definition: util.h:47
void match_init(Match *match)
Initializes the Match data structure.
Definition: match.c:26
bool con_is_internal(Con *con)
Returns true if the container is internal, such as __i3_scratch.
Definition: con.c:567
#define TAILQ_NEXT(elm, field)
Definition: queue.h:338
void floating_disable(Con *con)
Disables floating mode for the given container by re-attaching the container to its old parent.
Definition: floating.c:424
void cmd_move_con_to_workspace(I3_CMD, const char *which)
Implementation of 'move [window|container] [to] workspace next|prev|next_on_output|prev_on_output'.
Definition: commands.c:302
json_content_t
Definition: load_layout.h:15
Definition: data.h:56
bool con_fullscreen_permits_focusing(Con *con)
Returns true if changing the focus to con would be allowed considering the fullscreen focus constrain...
Definition: con.c:2069
void tree_move(Con *con, direction_t direction)
Moves the given container in the given direction.
Definition: move.c:249
void floating_resize(Con *floating_con, uint32_t x, uint32_t y)
Sets size of the CT_FLOATING_CON to specified dimensions.
Definition: floating.c:771
void floating_check_size(Con *floating_con, bool prefer_height)
Called when a floating window is created or resized.
Definition: floating.c:73
void cmd_move_window_to_center(I3_CMD, const char *method)
Implementation of 'move [window|container] [to] [absolute] position center.
Definition: commands.c:1743
bool workspace_auto_back_and_forth
Automatic workspace back and forth switching.
bool get_debug_logging(void)
Checks if debug logging is active.
Definition: log.c:206
void tree_next(Con *con, direction_t direction)
Changes focus in the given direction.
Definition: tree.c:585
void floating_move_to_pointer(Con *con)
Moves the given floating con to the current pointer position.
Definition: floating.c:542
Definition: data.h:88
Con * con_id
Definition: data.h:558
void cmd_workspace(I3_CMD, const char *which)
Implementation of 'workspace next|prev|next_on_output|prev_on_output'.
Definition: commands.c:838
void ewmh_update_wm_desktop(void)
Updates _NET_WM_DESKTOP for all windows.
Definition: ewmh.c:182
void start_application(const char *command, bool no_startup_id)
Starts the given application by passing it through a shell.
Definition: startup.c:133
void cmd_move_con_to_workspace_name(I3_CMD, const char *name, const char *no_auto_back_and_forth)
Implementation of 'move [–no-auto-back-and-forth] [window|container] [to] workspace <name>'.
Definition: commands.c:355
void con_set_layout(Con *con, layout_t layout)
This function changes the layout of a given container.
Definition: con.c:1768
const char * i3string_as_utf8(i3String *str)
Returns the UTF-8 encoded version of the i3String.
static direction_t parse_direction(const char *str)
Definition: commands.c:414
bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction, bool both_sides)
Definition: resize.c:70
char * id
Automatically generated ID for this bar config.
#define CMD_FOCUS_WARN_CHILDREN
Definition: commands.c:1216
void workspace_show(Con *workspace)
Switches to the given workspace.
Definition: workspace.c:421
void con_disable_fullscreen(Con *con)
Disables fullscreen mode for the given container, if necessary.
Definition: con.c:1133
void toggle_floating_mode(Con *con, bool automatic)
Calls floating_enable() for tiling containers and floating_disable() for floating containers.
Definition: floating.c:461
Con * con_descend_focused(Con *con)
Returns the focused con inside this client, descending the tree as far as possible.
Definition: con.c:1516
bool floating_maybe_reassign_ws(Con *con)
Checks if con’s coordinates are within its workspace and re-assigns it to the actual workspace if not...
Definition: floating.c:494
Stores which workspace (by name or number) goes to which output.
Definition: data.h:225
Output * get_output_by_name(const char *name, const bool require_active)
Returns the output with the given name or NULL.
Definition: randr.c:47
Con * con_by_mark(const char *mark)
Returns the container with the given mark or NULL if no such container exists.
Definition: con.c:698
void con_toggle_layout(Con *con, const char *toggle_mode)
This function toggles the layout of a given container.
Definition: con.c:1853
double percent_for_1px(Con *con)
Calculate the minimum percent needed for the given container to be at least 1 pixel.
Definition: resize.c:129
void init_logging(void)
Initializes logging by creating an error logfile in /tmp (or XDG_RUNTIME_DIR, see get_process_filenam...
Definition: log.c:85
void cmd_workspace_number(I3_CMD, const char *which, const char *_no_auto_back_and_forth)
Implementation of 'workspace [–no-auto-back-and-forth] number <number>'.
Definition: commands.c:872
char * ipc_socket_path
border_style_t border_style
Definition: data.h:752
void cmd_exec(I3_CMD, const char *nosn, const char *command)
Implementation of 'exec [–no-startup-id] <command>'.
Definition: commands.c:1191
#define TAILQ_ENTRY(type)
Definition: queue.h:327
void update_shmlog_atom(void)
Set up the SHMLOG_PATH atom.
Definition: x.c:1415
Definition: data.h:61
#define HANDLE_EMPTY_MATCH
When the command did not include match criteria (!), we use the currently focused container.
Definition: commands.c:62
direction_t
Definition: data.h:55
void con_enable_fullscreen(Con *con, fullscreen_mode_t fullscreen_mode)
Enables fullscreen mode for the given container, if necessary.
Definition: con.c:1087
#define TAILQ_END(head)
Definition: queue.h:337
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:376
int width_increment
Definition: data.h:497
An Output is a physical output on your graphics driver.
Definition: data.h:393
uint32_t con_rect_size_in_orientation(Con *con)
Returns given container's rect size depending on its orientation.
Definition: con.c:2426
Definition: data.h:62
Holds the status bar configuration (i3bar).
void con_set_border_style(Con *con, int border_style, int border_width)
Sets the given border style on con, correctly keeping the position/size of a floating window.
Definition: con.c:1726
void cmd_move_con_to_workspace_back_and_forth(I3_CMD)
Implementation of 'move [window|container] [to] workspace back_and_forth'.
Definition: commands.c:335
#define STARTS_WITH(string, needle)
Definition: util.h:25
void ewmh_update_desktop_properties(void)
Updates all the EWMH desktop properties.
Definition: ewmh.c:116
void con_close(Con *con, kill_window_t kill_window)
Closes the given container.
Definition: con.c:307
#define ystr(str)
Definition: commands.c:22
void cmd_focus(I3_CMD)
Implementation of 'focus'.
Definition: commands.c:1373
Con * con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode)
Returns the first fullscreen node below this node.
Definition: con.c:502
static Match current_match
bool match_is_empty(Match *match)
Check if a match is empty.
Definition: match.c:39
Definition: data.h:63
#define I3STRING_FREE(str)
Securely i3string_free by setting the pointer to NULL to prevent accidentally using freed memory.
Definition: libi3.h:236
Output * get_output_for_con(Con *con)
Returns the output for the given con.
Definition: output.c:55
struct deco_render_params * deco_render_params
Cache for the decoration rendering.
Definition: data.h:715
Definition: data.h:60
void cmd_floating(I3_CMD, const char *floating_mode)
Implementation of 'floating enable|disable|toggle'.
Definition: commands.c:1059
bool con_move_to_output_name(Con *con, const char *name, bool fix_coordinates)
Moves the given container to the currently focused container on the visible workspace on the output s...
Definition: con.c:1425
void tree_split(Con *con, orientation_t orientation)
Splits (horizontally or vertically) the given container by creating a new container which contains th...
Definition: tree.c:327
xcb_window_t id
Definition: data.h:429
Con * workspace_prev(void)
Returns the previous workspace.
Definition: workspace.c:626
bool workspace_is_visible(Con *ws)
Returns true if the workspace is currently visible.
Definition: workspace.c:308
void cmd_split(I3_CMD, const char *direction)
Implementation of 'split v|h|t|vertical|horizontal|toggle'.
Definition: commands.c:1120
struct all_cons_head all_cons
Definition: tree.c:15
static bool cmd_resize_tiling_direction(I3_CMD, Con *current, const char *direction, int px, int ppt)
Definition: commands.c:488
orientation_t
Definition: data.h:59
#define DLOG(fmt,...)
Definition: libi3.h:104
border_style_t
Definition: data.h:64
static bool cmd_bar_mode(const char *bar_mode, const char *bar_id)
Definition: commands.c:2065
bool output_triggers_assignment(Output *output, struct Workspace_Assignment *assignment)
Returns true if the first output assigned to a workspace with the given workspace assignment is the s...
Definition: workspace.c:114
Con * workspace_next(void)
Returns the next workspace.
Definition: workspace.c:563
void * smalloc(size_t size)
Safe-wrapper around malloc which exits if malloc returns NULL (meaning that there is no more memory a...
void con_attach(Con *con, Con *parent, bool ignore_focus)
Attaches the given container to the given parent.
Definition: con.c:198
void i3_restart(bool forget_layout)
Restart i3 in-place appends -a to argument list to disable autostart.
Definition: util.c:286
void cmd_debuglog(I3_CMD, const char *argument)
Implementation of 'debuglog toggle|on|off'.
Definition: commands.c:2207
void kill_nagbar(pid_t *nagbar_pid, bool wait_for_it)
Kills the i3-nagbar process, if *nagbar_pid != -1.
Definition: util.c:413
struct Con * parent
Definition: data.h:673
json_content_t json_determine_content(const char *buf, const size_t len)
Definition: load_layout.c:590
void con_activate(Con *con)
Sets input focus to the given container and raises it to the top.
Definition: con.c:263
Definition: data.h:630
Con * get_tree_next_sibling(Con *con, position_t direction)
Get the previous / next sibling.
Definition: tree.c:627
void ewmh_update_visible_name(xcb_window_t window, const char *name)
Updates _NET_WM_VISIBLE_NAME.
Definition: ewmh.c:214
Config config
Definition: config.c:17
void cmd_shmlog(I3_CMD, const char *argument)
Implementation of 'shmlog <size>|toggle|on|off'.
Definition: commands.c:2175
void cmd_mode(I3_CMD, const char *mode)
Implementation of 'mode <string>'.
Definition: commands.c:1007
Definition: data.h:57
void cmd_exit(I3_CMD)
Implementation of 'exit'.
Definition: commands.c:1592
#define TAILQ_FIRST(head)
Definition: queue.h:336
void floating_enable(Con *con, bool automatic)
Enables floating mode for the given container by detaching it from its parent, creating a new contain...
Definition: floating.c:224
void cmd_focus_window_mode(I3_CMD, const char *window_mode)
Implementation of 'focus tiling|floating|mode_toggle'.
Definition: commands.c:1308
mark_mode_t
Definition: data.h:87
static void move_matches_to_workspace(Con *ws)
Definition: commands.c:262
enum Window::@13 dock
Whether the window says it is a dock window.
void cmd_focus_sibling(I3_CMD, const char *direction_str)
Implementation of 'focus next|prev sibling'.
Definition: commands.c:1273
struct regex * mark
Definition: data.h:538
bool regex_matches(struct regex *regex, const char *input)
Checks if the given regular expression matches the given input and returns true if it does.
Definition: regex.c:73
void cmd_move_con_to_workspace_number(I3_CMD, const char *which, const char *no_auto_back_and_forth)
Implementation of 'move [–no-auto-back-and-forth] [window|container] [to] workspace number <number>'.
Definition: commands.c:382
uint32_t x
Definition: data.h:176
int num
the workspace number, if this Con is of type CT_WORKSPACE and the workspace is not a named workspace ...
Definition: data.h:671
void ipc_send_workspace_event(const char *change, Con *current, Con *old)
For the workspace events we send, along with the usual "change" field, also the workspace container i...
Definition: ipc.c:1598
pid_t config_error_nagbar_pid
Definition: config_parser.c:47
static int border_width_from_style(border_style_t border_style, long border_width, Con *con)
Definition: commands.c:708
void match_parse_property(Match *match, const char *ctype, const char *cvalue)
Interprets a ctype=cvalue pair and adds it to the given match specification.
Definition: match.c:256
Con * workspace_back_and_forth_get(void)
Returns the previously focused workspace con, or NULL if unavailable.
Definition: workspace.c:817
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:402
bool resize_neighboring_cons(Con *first, Con *second, int px, int ppt)
Resize the two given containers using the given amount of pixels or percentage points.
Definition: resize.c:144
void ewmh_update_sticky(xcb_window_t window, bool sticky)
Set or remove _NET_WM_STATE_STICKY on the window.
Definition: ewmh.c:277
enum Barconfig::@9 mode
Bar display mode (hide unless modifier is pressed or show in dock mode or always hide in invisible mo...
i3String * con_parse_title_format(Con *con)
Returns the window title considering the current title format.
Definition: con.c:2262
void cmd_append_layout(I3_CMD, const char *cpath)
Implementation of 'append_layout <path>'.
Definition: commands.c:762
void cmd_focus_level(I3_CMD, const char *level)
Implementation of 'focus parent|child'.
Definition: commands.c:1345
static bool cmd_resize_tiling_width_height(I3_CMD, Con *current, const char *direction, int px, double ppt)
Definition: commands.c:507
static Con * maybe_auto_back_and_forth_workspace(Con *workspace)
Definition: commands.c:105
void workspace_back_and_forth(void)
Focuses the previously focused workspace.
Definition: workspace.c:804
enum Con::@22 scratchpad_state
Con * tree_open_con(Con *con, i3Window *window)
Opens an empty container in the current container.
Definition: tree.c:149
void cmd_move_con_to_mark(I3_CMD, const char *mark)
Implementation of 'move [window|container] [to] mark <str>'.
Definition: commands.c:1039