31 Con *output, *workspace = NULL;
45 Con *output, *workspace = NULL;
66 DLOG(
"Auto orientation. Workspace size set to (%d,%d), setting layout to %d.\n",
88 if (assignment->
output == NULL) {
93 DLOG(
"Found workspace name=\"%s\" assignment to output \"%s\"\n",
96 if (assigned_by_name) {
98 return assigned_by_name->
con;
102 name_is_digits(assignment->
name) &&
104 DLOG(
"Found workspace number=%ld assignment to output \"%s\"\n",
105 parsed_num, assignment->
output);
107 if (assigned_by_num) {
122 return assigned && assigned ==
output->con;
137 LOG(
"Creating new workspace \"%s\"\n", num);
151 workspace =
con_new(NULL, NULL);
161 workspace->
num = parsed_num;
162 workspace->
type = CT_WORKSPACE;
192 if (strlen(bind->
command) < strlen(
"workspace ") ||
193 strncasecmp(bind->
command,
"workspace", strlen(
"workspace")) != 0) {
197 const char *target = bind->
command + strlen(
"workspace ");
198 while (*target ==
' ' || *target ==
'\t') {
206 if (strncasecmp(target,
"next", strlen(
"next")) == 0 ||
207 strncasecmp(target,
"prev", strlen(
"prev")) == 0 ||
208 strncasecmp(target,
"next_on_output", strlen(
"next_on_output")) == 0 ||
209 strncasecmp(target,
"prev_on_output", strlen(
"prev_on_output")) == 0 ||
210 strncasecmp(target,
"back_and_forth", strlen(
"back_and_forth")) == 0 ||
211 strncasecmp(target,
"current", strlen(
"current")) == 0) {
214 if (strncasecmp(target,
"--no-auto-back-and-forth", strlen(
"--no-auto-back-and-forth")) == 0) {
215 target += strlen(
"--no-auto-back-and-forth");
216 while (*target ==
' ' || *target ==
'\t') {
220 if (strncasecmp(target,
"number", strlen(
"number")) == 0) {
221 target += strlen(
"number");
222 while (*target ==
' ' || *target ==
'\t') {
227 if (target_name == NULL) {
230 if (strncasecmp(target_name,
"__", strlen(
"__")) == 0) {
231 LOG(
"Cannot create workspace \"%s\". Names starting with __ are i3-internal.\n", target);
235 DLOG(
"Saving workspace name \"%s\"\n", target_name);
254 ws->
type = CT_WORKSPACE;
263 if (assigned && assigned !=
output->con) {
276 DLOG(
"Used number %d for workspace with name %s\n", ws->
num, ws->
name);
284 DLOG(
"Getting next unused workspace by number\n");
290 DLOG(
"result for ws %d: exists = %d\n", c, exists);
337 if (current != exclude &&
339 current->
window != NULL &&
345 if (recurse != NULL) {
350 TAILQ_FOREACH (current, &(con->floating_head), floating_windows) {
351 if (current != exclude &&
353 current->
window != NULL &&
359 if (recurse != NULL) {
385 LOG(
"Ah, this one is sticky: %s / %p\n", current->
name, current);
391 LOG(
"No window found for this sticky group\n");
404 LOG(
"re-assigned window from src %p to dest %p\n", src, current);
407 TAILQ_FOREACH (current, &(con->floating_head), floating_windows) {
425 DLOG(
"Resetting urgency flag of con %p by timer\n", con);
439 Con *current, *old = NULL;
459 if (workspace == current) {
460 DLOG(
"Not switching, already there.\n");
485 DLOG(
"switching to %p / %s\n", workspace, workspace->
name);
493 if (next->
urgent && (
int)(
config.workspace_urgency_timer * 1000) > 0) {
504 if (
focused->urgency_timer == NULL) {
505 DLOG(
"Deferring reset of urgency flag of con %p on newly shown workspace %p\n",
510 config.workspace_urgency_timer,
config.workspace_urgency_timer);
514 DLOG(
"Resetting urgency timer of con %p on workspace %p\n",
524 DLOG(
"old = %p / %s\n", old, (old ? old->
name :
"(null)"));
533 LOG(
"Closing old workspace (%p / %s), it is empty\n", old, old->
name);
537 const unsigned char *payload;
539 y(get_buf, &payload, &length);
540 ipc_send_event(
"workspace", I3_IPC_EVENT_WORKSPACE, (
const char *)payload);
545 if (old == old_focus) {
558 if (old_output != new_output) {
583 Con *next = NULL, *first = NULL, *first_opposite = NULL;
586 if (current->
num == -1) {
588 if ((next =
TAILQ_NEXT(current, nodes)) != NULL) {
591 bool found_current =
false;
598 if (child->type != CT_WORKSPACE) {
604 if (!first_opposite || (child->num != -1 && child->num < first_opposite->num)) {
605 first_opposite = child;
607 if (child == current) {
608 found_current =
true;
609 }
else if (child->num == -1 && found_current) {
617 bool found_current =
false;
624 if (child->type != CT_WORKSPACE) {
627 if (!first || (child->num != -1 && child->num < first->num)) {
630 if (!first_opposite && child->num == -1) {
631 first_opposite = child;
633 if (child->num == -1) {
639 if (current->
num < child->num && (!next || child->
num < next->
num)) {
645 if (child == current) {
646 found_current =
true;
647 }
else if (found_current && current->
num == child->num) {
655 next = first_opposite ? first_opposite : first;
667 Con *prev = NULL, *first_opposite = NULL, *last = NULL;
670 if (current->
num == -1) {
672 prev =
TAILQ_PREV(current, nodes_head, nodes);
673 if (prev && prev->
num != -1) {
677 bool found_current =
false;
684 if (child->type != CT_WORKSPACE) {
690 if (!first_opposite || (child->num != -1 && child->num > first_opposite->num)) {
691 first_opposite = child;
693 if (child == current) {
694 found_current =
true;
695 }
else if (child->num == -1 && found_current) {
704 bool found_current =
false;
711 if (child->type != CT_WORKSPACE) {
714 if (!last || (child->num != -1 && last->num < child->num)) {
717 if (!first_opposite && child->num == -1) {
718 first_opposite = child;
720 if (child->num == -1) {
726 if (current->
num > child->num && (!prev || child->
num > prev->
num)) {
732 if (child == current) {
733 found_current =
true;
734 }
else if (found_current && current->
num == child->num) {
742 prev = first_opposite ? first_opposite : last;
757 if (current->
num == -1) {
762 bool found_current =
false;
764 if (child->type != CT_WORKSPACE) {
767 if (child->num == -1) {
773 if (current->
num < child->num && (!next || child->
num < next->
num)) {
779 if (child == current) {
780 found_current =
true;
781 }
else if (found_current && current->
num == child->num) {
789 bool found_current =
false;
791 if (child->type != CT_WORKSPACE) {
794 if (child == current) {
795 found_current =
true;
796 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
798 goto workspace_next_on_output_end;
806 if (child->type != CT_WORKSPACE) {
809 if (!next || (child->num != -1 && child->num < next->
num)) {
814workspace_next_on_output_end:
828 if (current->
num == -1) {
830 prev =
TAILQ_PREV(current, nodes_head, nodes);
831 if (prev && prev->
num != -1) {
836 bool found_current =
false;
838 if (child->type != CT_WORKSPACE || child->num == -1) {
844 if (current->
num > child->num && (!prev || child->
num > prev->
num)) {
850 if (child == current) {
851 found_current =
true;
852 }
else if (found_current && current->
num == child->num) {
860 bool found_current =
false;
862 if (child->type != CT_WORKSPACE) {
865 if (child == current) {
866 found_current =
true;
867 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
869 goto workspace_prev_on_output_end;
877 if (child->type != CT_WORKSPACE) {
880 if (!prev || child->
num > prev->
num) {
886workspace_prev_on_output_end:
896 DLOG(
"No previous workspace name set. Not switching.\n");
909 DLOG(
"No previous workspace name set.\n");
924 TAILQ_FOREACH (child, &(con->floating_head), floating_windows) {
939 bool old_flag = ws->
urgent;
941 DLOG(
"Workspace urgency flag changed from %d to %d\n", old_flag, ws->
urgent);
943 if (old_flag != ws->
urgent) {
964 DLOG(
"Moving cons\n");
979 DLOG(
"Attaching new split (%p) to ws (%p)\n", split, ws);
997 DLOG(
"Attaching a window to workspace %p / %s\n", ws, ws->
name);
1000 DLOG(
"Default layout, just attaching it to the workspace itself.\n");
1004 DLOG(
"Non-default layout, creating a new split container\n");
1013 DLOG(
"Attaching new split %p to workspace %p\n",
new, ws);
1030 ELOG(
"Workspace %p / %s has no children to encapsulate\n", ws, ws->
name);
1040 DLOG(
"Moving children of workspace %p / %s into container %p\n",
1065 DLOG(
"got output %p with content %p\n",
output, content);
1067 if (ws->
parent == content) {
1068 DLOG(
"Nothing to do, workspace already there\n");
1072 Con *previously_visible_ws =
TAILQ_FIRST(&(content->focus_head));
1073 if (previously_visible_ws) {
1074 DLOG(
"Previously visible workspace = %p / %s\n", previously_visible_ws, previously_visible_ws->
name);
1076 DLOG(
"No previously visible workspace on output.\n");
1081 DLOG(
"Creating a new workspace to replace \"%s\" (last on its output).\n", ws->
name);
1084 bool used_assignment =
false;
1092 const bool attached = (num == -1)
1100 DLOG(
"Creating workspace from assignment %s.\n", assignment->
name);
1102 used_assignment =
true;
1109 if (!used_assignment) {
1113 DLOG(
"Detaching\n");
1118 if (workspace_was_visible) {
1122 DLOG(
"workspace was visible, focusing %p / %s now\n", focus_ws, focus_ws->
name);
1129 TAILQ_FOREACH (floating_con, &(ws->floating_head), floating_windows) {
1134 if (workspace_was_visible) {
1141 if (!previously_visible_ws) {
1151 if (ws != previously_visible_ws) {
1158 CALL(previously_visible_ws, on_remove_child);
char * parse_string(const char **walk, bool as_word)
Parses a string (or word, if as_word is true).
Con * con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode)
Returns the first fullscreen node below this node.
void con_set_urgency(Con *con, bool urgent)
Set urgency flag to the container, all the parent containers and the workspace.
void con_update_parents_urgency(Con *con)
Make all parent containers urgent if con is urgent or clear the urgent flag of all parent containers ...
Con * con_new(Con *parent, i3Window *window)
A wrapper for con_new_skeleton, to retain the old con_new behaviour.
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
bool con_is_internal(Con *con)
Returns true if the container is internal, such as __i3_scratch.
void con_detach(Con *con)
Detaches the given container from its current parent.
void set_focus_order(Con *con, Con **focus_order)
Clear the container's focus stack and re-add it using the provided container array.
void con_fix_percent(Con *con)
Updates the percent attribute of the children of the given container.
void con_attach(Con *con, Con *parent, bool ignore_focus)
Attaches the given container to the given parent.
int con_num_children(Con *con)
Returns the number of children of this container.
void con_focus(Con *con)
Sets input focus to the given container.
Con * con_get_output(Con *con)
Gets the output container (first container with CT_OUTPUT in hierarchy) this node is on.
Con * con_descend_focused(Con *con)
Returns the focused con inside this client, descending the tree as far as possible.
Con ** get_focus_order(Con *con)
Iterate over the container's focus stack and return an array with the containers inside it,...
void ewmh_update_desktop_properties(void)
Updates all the EWMH desktop properties.
void ewmh_update_current_desktop(void)
Updates _NET_CURRENT_DESKTOP with the current desktop number.
void floating_fix_coordinates(Con *con, Rect *old_rect, Rect *new_rect)
Fixes the coordinates of the floating window whenever the window gets reassigned to a different outpu...
gaps_t gaps_for_workspace(Con *ws)
Returns the configured gaps for this workspace based on the workspace name, number,...
void output_push_sticky_windows(Con *old_focus)
Iterates over all outputs and pushes sticky windows to the currently visible workspace on that output...
char * output_primary_name(Output *output)
Retrieves the primary name of an output.
Output * get_output_for_con(Con *con)
Retrieves the output for a given container.
Con * output_get_content(Con *output)
Returns the output container below the given output container.
Output * get_output_by_name(const char *name, const bool require_active)
Returns the output with the given name or NULL.
bool tree_close_internal(Con *con, kill_window_t kill_window, bool dont_kill_parent)
Closes the given container including all children.
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
int ws_name_to_number(const char *name)
Parses the workspace name as a number.
static void _workspace_apply_default_orientation(Con *ws)
Con * workspace_back_and_forth_get(void)
Returns the previously focused workspace con, or NULL if unavailable.
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.
static Con * _get_sticky(Con *con, const char *sticky_group, Con *exclude)
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...
Con * create_workspace_on_output(Output *output, Con *content)
Returns a pointer to a new workspace in the given output.
static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents)
Con * workspace_next_on_output(void)
Returns the next workspace on the same output.
void workspace_update_urgent_flag(Con *ws)
Goes through all clients on the given workspace and updates the workspace’s urgent flag accordingly.
void workspace_show(Con *workspace)
Switches to the given workspace.
bool workspace_is_visible(Con *ws)
Returns true if the workspace is currently visible.
static void workspace_reassign_sticky(Con *con)
Con * workspace_prev_on_output(void)
Returns the previous workspace on the same output.
Con * workspace_attach_to(Con *ws)
Called when a new con (with a window, not an empty or split con) should be attached to the workspace ...
Con * workspace_get(const char *num)
Returns a pointer to the workspace with the given number (starting at 0), creating the workspace if n...
void workspace_back_and_forth(void)
Focuses the previously focused workspace.
void workspace_move_to_output(Con *ws, Output *output)
Move the given workspace to the specified output.
static char ** binding_workspace_names
Con * workspace_next(void)
Returns the next workspace.
void extract_workspace_names_from_bindings(void)
Extracts workspace names from keybindings (e.g.
void ws_force_orientation(Con *ws, orientation_t orientation)
'Forces' workspace orientation by moving all cons into a new split-con with the same orientation as t...
Con * get_existing_workspace_by_num(int num)
Returns the workspace with the given number or NULL if such a workspace does not exist.
Con * workspace_prev(void)
Returns the previous workspace.
void workspace_show_by_name(const char *num)
Looks up the workspace by name and switches to it.
static bool get_urgency_flag(Con *con)
char * previous_workspace_name
Stores a copy of the name of the last used workspace for the workspace back-and-forth switching.
Con * workspace_encapsulate(Con *ws)
Creates a new container and re-parents all of children from the given workspace into it.
Con * get_assigned_output(const char *name, long parsed_num)
Returns the first output that is assigned to a workspace specified by the given name or number.
void x_move_win(Con *src, Con *dest)
Moves a child window from Container src to Container dest.
void x_reparent_child(Con *con, Con *old)
Reparents the child window of the given container (necessary for sticky containers).
void x_set_warp_to(Rect *rect)
Set warp_to coordinates.
void x_set_name(Con *con, const char *name)
Sets the WM_NAME property (so, no UTF8, but used only for debugging anyways) of the given name.
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...
void ipc_send_event(const char *event, uint32_t message_type, const char *payload)
Sends the specified event to all IPC clients which are currently connected and subscribed to this kin...
yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old)
Generates a json workspace event.
void ipc_send_window_event(const char *property, Con *con)
For the window events we send, along the usual "change" field, also the window container,...
struct ev_loop * main_loop
struct ws_assignments_head ws_assignments
struct bindings_head * bindings
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
void * scalloc(size_t num, size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
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 * srealloc(void *ptr, size_t size)
Safe-wrapper around realloc which exits if realloc returns NULL (meaning that there is no more memory...
#define TAILQ_FOREACH(var, head, field)
#define TAILQ_PREV(elm, headname, field)
#define TAILQ_FIRST(head)
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
#define TAILQ_NEXT(elm, field)
#define TAILQ_EMPTY(head)
#define NODES_FOREACH(head)
#define CALL(obj, member,...)
#define GREP_FIRST(dest, head, condition)
#define NODES_FOREACH_REVERSE(head)
Stores which workspace (by name or number) goes to which output and its gaps config.
Holds a keybinding, consisting of a keycode combined with modifiers and the command which is executed...
char * command
Command, like in command mode.
Con * con
Pointer to the Con which represents this output.
A 'Con' represents everything from the X11 root window down to a single X11 window.
layout_t workspace_layout
enum Con::@346165121142372010274264023343041222364036203311 type
gaps_t gaps
Only applicable for containers of type CT_WORKSPACE.
int num
the workspace number, if this Con is of type CT_WORKSPACE and the workspace is not a named workspace ...
struct ev_timer * urgency_timer
fullscreen_mode_t fullscreen_mode