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);
505 DLOG(
"Deferring reset of urgency flag of con %p on newly shown workspace %p\n",
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)
int default_orientation
Default orientation for new containers.
float workspace_urgency_timer
By default, urgency is cleared immediately when switching to another workspace leads to focusing the ...
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.
An Output is a physical output on your graphics driver.
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
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