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)
196 const char *target = bind->
command + strlen(
"workspace ");
197 while (*target ==
' ' || *target ==
'\t')
204 if (strncasecmp(target,
"next", strlen(
"next")) == 0 ||
205 strncasecmp(target,
"prev", strlen(
"prev")) == 0 ||
206 strncasecmp(target,
"next_on_output", strlen(
"next_on_output")) == 0 ||
207 strncasecmp(target,
"prev_on_output", strlen(
"prev_on_output")) == 0 ||
208 strncasecmp(target,
"back_and_forth", strlen(
"back_and_forth")) == 0 ||
209 strncasecmp(target,
"current", strlen(
"current")) == 0)
211 if (strncasecmp(target,
"--no-auto-back-and-forth", strlen(
"--no-auto-back-and-forth")) == 0) {
212 target += strlen(
"--no-auto-back-and-forth");
213 while (*target ==
' ' || *target ==
'\t')
216 if (strncasecmp(target,
"number", strlen(
"number")) == 0) {
217 target += strlen(
"number");
218 while (*target ==
' ' || *target ==
'\t')
222 if (target_name == NULL)
224 if (strncasecmp(target_name,
"__", strlen(
"__")) == 0) {
225 LOG(
"Cannot create workspace \"%s\". Names starting with __ are i3-internal.\n", target);
229 DLOG(
"Saving workspace name \"%s\"\n", target_name);
248 ws->
type = CT_WORKSPACE;
257 if (assigned && assigned !=
output->con) {
270 DLOG(
"Used number %d for workspace with name %s\n", ws->
num, ws->
name);
278 DLOG(
"Getting next unused workspace by number\n");
284 DLOG(
"result for ws %d: exists = %d\n", c, exists);
331 if (current != exclude &&
333 current->
window != NULL &&
342 TAILQ_FOREACH (current, &(con->floating_head), floating_windows) {
343 if (current != exclude &&
345 current->
window != NULL &&
375 LOG(
"Ah, this one is sticky: %s / %p\n", current->
name, current);
381 LOG(
"No window found for this sticky group\n");
394 LOG(
"re-assigned window from src %p to dest %p\n", src, current);
397 TAILQ_FOREACH (current, &(con->floating_head), floating_windows) {
415 DLOG(
"Resetting urgency flag of con %p by timer\n", con);
429 Con *current, *old = NULL;
447 if (workspace == current) {
448 DLOG(
"Not switching, already there.\n");
473 DLOG(
"switching to %p / %s\n", workspace, workspace->
name);
493 DLOG(
"Deferring reset of urgency flag of con %p on newly shown workspace %p\n",
502 DLOG(
"Resetting urgency timer of con %p on workspace %p\n",
511 DLOG(
"old = %p / %s\n", old, (old ? old->
name :
"(null)"));
520 LOG(
"Closing old workspace (%p / %s), it is empty\n", old, old->
name);
524 const unsigned char *payload;
526 y(get_buf, &payload, &length);
527 ipc_send_event(
"workspace", I3_IPC_EVENT_WORKSPACE, (
const char *)payload);
532 if (old == old_focus) {
545 if (old_output != new_output) {
570 Con *next = NULL, *first = NULL, *first_opposite = NULL;
573 if (current->
num == -1) {
575 if ((next =
TAILQ_NEXT(current, nodes)) != NULL)
577 bool found_current =
false;
583 if (child->type != CT_WORKSPACE)
587 if (!first_opposite || (child->num != -1 && child->num < first_opposite->num))
588 first_opposite = child;
589 if (child == current) {
590 found_current =
true;
591 }
else if (child->num == -1 && found_current) {
604 if (child->type != CT_WORKSPACE)
606 if (!first || (child->num != -1 && child->num < first->num))
608 if (!first_opposite && child->num == -1)
609 first_opposite = child;
610 if (child->num == -1)
615 if (current->
num < child->num && (!next || child->
num < next->
num))
622 next = first_opposite ? first_opposite : first;
633 Con *prev = NULL, *first_opposite = NULL, *last = NULL;
636 if (current->
num == -1) {
638 prev =
TAILQ_PREV(current, nodes_head, nodes);
639 if (prev && prev->
num != -1)
642 bool found_current =
false;
648 if (child->type != CT_WORKSPACE)
652 if (!first_opposite || (child->num != -1 && child->num > first_opposite->num))
653 first_opposite = child;
654 if (child == current) {
655 found_current =
true;
656 }
else if (child->num == -1 && found_current) {
670 if (child->type != CT_WORKSPACE)
672 if (!last || (child->num != -1 && last->num < child->num))
674 if (!first_opposite && child->num == -1)
675 first_opposite = child;
676 if (child->num == -1)
681 if (current->
num > child->num && (!prev || child->
num > prev->
num))
688 prev = first_opposite ? first_opposite : last;
702 if (current->
num == -1) {
708 if (child->type != CT_WORKSPACE)
710 if (child->num == -1)
715 if (current->
num < child->num && (!next || child->
num < next->
num))
722 bool found_current =
false;
724 if (child->type != CT_WORKSPACE)
726 if (child == current) {
727 found_current =
true;
728 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
730 goto workspace_next_on_output_end;
738 if (child->type != CT_WORKSPACE)
740 if (!next || (child->num != -1 && child->num < next->
num))
744workspace_next_on_output_end:
758 if (current->
num == -1) {
760 prev =
TAILQ_PREV(current, nodes_head, nodes);
761 if (prev && prev->
num != -1)
766 if (child->type != CT_WORKSPACE || child->num == -1)
771 if (current->
num > child->num && (!prev || child->
num > prev->
num))
778 bool found_current =
false;
780 if (child->type != CT_WORKSPACE)
782 if (child == current) {
783 found_current =
true;
784 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
786 goto workspace_prev_on_output_end;
794 if (child->type != CT_WORKSPACE)
796 if (!prev || child->
num > prev->
num)
801workspace_prev_on_output_end:
811 DLOG(
"No previous workspace name set. Not switching.\n");
824 DLOG(
"No previous workspace name set.\n");
839 TAILQ_FOREACH (child, &(con->floating_head), floating_windows) {
854 bool old_flag = ws->
urgent;
856 DLOG(
"Workspace urgency flag changed from %d to %d\n", old_flag, ws->
urgent);
858 if (old_flag != ws->
urgent)
878 DLOG(
"Moving cons\n");
893 DLOG(
"Attaching new split (%p) to ws (%p)\n", split, ws);
911 DLOG(
"Attaching a window to workspace %p / %s\n", ws, ws->
name);
914 DLOG(
"Default layout, just attaching it to the workspace itself.\n");
918 DLOG(
"Non-default layout, creating a new split container\n");
927 DLOG(
"Attaching new split %p to workspace %p\n",
new, ws);
944 ELOG(
"Workspace %p / %s has no children to encapsulate\n", ws, ws->
name);
954 DLOG(
"Moving children of workspace %p / %s into container %p\n",
979 DLOG(
"got output %p with content %p\n",
output, content);
981 if (ws->
parent == content) {
982 DLOG(
"Nothing to do, workspace already there\n");
987 if (previously_visible_ws) {
988 DLOG(
"Previously visible workspace = %p / %s\n", previously_visible_ws, previously_visible_ws->
name);
990 DLOG(
"No previously visible workspace on output.\n");
995 DLOG(
"Creating a new workspace to replace \"%s\" (last on its output).\n", ws->
name);
998 bool used_assignment =
false;
1006 const bool attached = (num == -1)
1014 DLOG(
"Creating workspace from assignment %s.\n", assignment->
name);
1016 used_assignment =
true;
1023 if (!used_assignment) {
1027 DLOG(
"Detaching\n");
1032 if (workspace_was_visible) {
1036 DLOG(
"workspace was visible, focusing %p / %s now\n", focus_ws, focus_ws->
name);
1043 TAILQ_FOREACH (floating_con, &(ws->floating_head), floating_windows) {
1048 if (workspace_was_visible) {
1055 if (!previously_visible_ws) {
1065 if (ws != previously_visible_ws) {
1072 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)
Returns the output for the given con.
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