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);
146 if (strcmp(assignment->
name, num) == 0) {
162 workspace =
con_new(NULL, NULL);
172 workspace->
num = parsed_num;
173 workspace->
type = CT_WORKSPACE;
203 if (strlen(bind->
command) < strlen(
"workspace ") ||
204 strncasecmp(bind->
command,
"workspace", strlen(
"workspace")) != 0)
207 const char *target = bind->
command + strlen(
"workspace ");
208 while (*target ==
' ' || *target ==
'\t')
215 if (strncasecmp(target,
"next", strlen(
"next")) == 0 ||
216 strncasecmp(target,
"prev", strlen(
"prev")) == 0 ||
217 strncasecmp(target,
"next_on_output", strlen(
"next_on_output")) == 0 ||
218 strncasecmp(target,
"prev_on_output", strlen(
"prev_on_output")) == 0 ||
219 strncasecmp(target,
"back_and_forth", strlen(
"back_and_forth")) == 0 ||
220 strncasecmp(target,
"current", strlen(
"current")) == 0)
222 if (strncasecmp(target,
"--no-auto-back-and-forth", strlen(
"--no-auto-back-and-forth")) == 0) {
223 target += strlen(
"--no-auto-back-and-forth");
224 while (*target ==
' ' || *target ==
'\t')
227 if (strncasecmp(target,
"number", strlen(
"number")) == 0) {
228 target += strlen(
"number");
229 while (*target ==
' ' || *target ==
'\t')
233 if (target_name == NULL)
235 if (strncasecmp(target_name,
"__", strlen(
"__")) == 0) {
236 LOG(
"Cannot create workspace \"%s\". Names starting with __ are i3-internal.\n", target);
240 DLOG(
"Saving workspace name \"%s\"\n", target_name);
260 ws->
type = CT_WORKSPACE;
269 if (assigned && assigned !=
output->con) {
279 LOG(
"Used number %d for workspace with name %s\n", ws->
num, ws->
name);
287 DLOG(
"Getting next unused workspace by number\n");
293 DLOG(
"result for ws %d: exists = %d\n", c, exists);
301 if (strcmp(assignment->
name, ws->
name) == 0) {
333 LOG(
"workspace visible? fs = %p, ws = %p\n", fs, ws);
345 if (current != exclude &&
347 current->
window != NULL &&
356 TAILQ_FOREACH (current, &(con->floating_head), floating_windows) {
357 if (current != exclude &&
359 current->
window != NULL &&
389 LOG(
"Ah, this one is sticky: %s / %p\n", current->
name, current);
395 LOG(
"No window found for this sticky group\n");
408 LOG(
"re-assigned window from src %p to dest %p\n", src, current);
411 TAILQ_FOREACH (current, &(con->floating_head), floating_windows) {
429 DLOG(
"Resetting urgency flag of con %p by timer\n", con);
443 Con *current, *old = NULL;
461 if (workspace == current) {
462 DLOG(
"Not switching, already there.\n");
487 DLOG(
"switching to %p / %s\n", workspace, workspace->
name);
507 DLOG(
"Deferring reset of urgency flag of con %p on newly shown workspace %p\n",
516 DLOG(
"Resetting urgency timer of con %p on workspace %p\n",
525 DLOG(
"old = %p / %s\n", old, (old ? old->
name :
"(null)"));
534 LOG(
"Closing old workspace (%p / %s), it is empty\n", old, old->
name);
538 const unsigned char *payload;
540 y(get_buf, &payload, &length);
541 ipc_send_event(
"workspace", I3_IPC_EVENT_WORKSPACE, (
const char *)payload);
546 if (old == old_focus) {
559 if (old_output != new_output) {
584 Con *next = NULL, *first = NULL, *first_opposite = NULL;
587 if (current->
num == -1) {
589 if ((next =
TAILQ_NEXT(current, nodes)) != NULL)
591 bool found_current =
false;
597 if (child->type != CT_WORKSPACE)
601 if (!first_opposite || (child->num != -1 && child->num < first_opposite->num))
602 first_opposite = child;
603 if (child == current) {
604 found_current =
true;
605 }
else if (child->num == -1 && found_current) {
618 if (child->type != CT_WORKSPACE)
620 if (!first || (child->num != -1 && child->num < first->num))
622 if (!first_opposite && child->num == -1)
623 first_opposite = child;
624 if (child->num == -1)
629 if (current->
num < child->num && (!next || child->
num < next->
num))
636 next = first_opposite ? first_opposite : first;
647 Con *prev = NULL, *first_opposite = NULL, *last = NULL;
650 if (current->
num == -1) {
652 prev =
TAILQ_PREV(current, nodes_head, nodes);
653 if (prev && prev->
num != -1)
656 bool found_current =
false;
662 if (child->type != CT_WORKSPACE)
666 if (!first_opposite || (child->num != -1 && child->num > first_opposite->num))
667 first_opposite = child;
668 if (child == current) {
669 found_current =
true;
670 }
else if (child->num == -1 && found_current) {
684 if (child->type != CT_WORKSPACE)
686 if (!last || (child->num != -1 && last->num < child->num))
688 if (!first_opposite && child->num == -1)
689 first_opposite = child;
690 if (child->num == -1)
695 if (current->
num > child->num && (!prev || child->
num > prev->
num))
702 prev = first_opposite ? first_opposite : last;
716 if (current->
num == -1) {
722 if (child->type != CT_WORKSPACE)
724 if (child->num == -1)
729 if (current->
num < child->num && (!next || child->
num < next->
num))
736 bool found_current =
false;
738 if (child->type != CT_WORKSPACE)
740 if (child == current) {
741 found_current =
true;
742 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
744 goto workspace_next_on_output_end;
752 if (child->type != CT_WORKSPACE)
754 if (!next || (child->num != -1 && child->num < next->
num))
758 workspace_next_on_output_end:
772 if (current->
num == -1) {
774 prev =
TAILQ_PREV(current, nodes_head, nodes);
775 if (prev && prev->
num != -1)
780 if (child->type != CT_WORKSPACE || child->num == -1)
785 if (current->
num > child->num && (!prev || child->
num > prev->
num))
792 bool found_current =
false;
794 if (child->type != CT_WORKSPACE)
796 if (child == current) {
797 found_current =
true;
798 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
800 goto workspace_prev_on_output_end;
808 if (child->type != CT_WORKSPACE)
810 if (!prev || child->
num > prev->
num)
815 workspace_prev_on_output_end:
825 DLOG(
"No previous workspace name set. Not switching.\n");
838 DLOG(
"No previous workspace name set.\n");
853 TAILQ_FOREACH (child, &(con->floating_head), floating_windows) {
868 bool old_flag = ws->
urgent;
870 DLOG(
"Workspace urgency flag changed from %d to %d\n", old_flag, ws->
urgent);
872 if (old_flag != ws->
urgent)
892 DLOG(
"Moving cons\n");
907 DLOG(
"Attaching new split (%p) to ws (%p)\n", split, ws);
925 DLOG(
"Attaching a window to workspace %p / %s\n", ws, ws->
name);
928 DLOG(
"Default layout, just attaching it to the workspace itself.\n");
932 DLOG(
"Non-default layout, creating a new split container\n");
941 DLOG(
"Attaching new split %p to workspace %p\n",
new, ws);
958 ELOG(
"Workspace %p / %s has no children to encapsulate\n", ws, ws->
name);
968 DLOG(
"Moving children of workspace %p / %s into container %p\n",
993 DLOG(
"got output %p with content %p\n",
output, content);
995 if (ws->
parent == content) {
996 DLOG(
"Nothing to do, workspace already there\n");
1000 Con *previously_visible_ws =
TAILQ_FIRST(&(content->focus_head));
1001 if (previously_visible_ws) {
1002 DLOG(
"Previously visible workspace = %p / %s\n", previously_visible_ws, previously_visible_ws->
name);
1004 DLOG(
"No previously visible workspace on output.\n");
1009 DLOG(
"Creating a new workspace to replace \"%s\" (last on its output).\n", ws->
name);
1012 bool used_assignment =
false;
1028 DLOG(
"Creating workspace from assignment %s.\n", assignment->
name);
1030 used_assignment =
true;
1037 if (!used_assignment) {
1041 DLOG(
"Detaching\n");
1046 if (workspace_was_visible) {
1050 DLOG(
"workspace was visible, focusing %p / %s now\n", focus_ws, focus_ws->
name);
1057 TAILQ_FOREACH (floating_con, &(ws->floating_head), floating_windows) {
1062 if (workspace_was_visible) {
1069 if (!previously_visible_ws) {
1079 if (ws != previously_visible_ws) {
1086 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).
void con_set_urgency(Con *con, bool urgent)
Set urgency flag to the container, all the parent containers and the workspace.
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
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 ** get_focus_order(Con *con)
Iterate over the container's focus stack and return an array with the containers inside it,...
Con * con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode)
Returns the first fullscreen node below this node.
Con * con_descend_focused(Con *con)
Returns the focused con inside this client, descending the tree as far as possible.
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.
Con * con_new(Con *parent, i3Window *window)
A wrapper for con_new_skeleton, to retain the old con_new behaviour.
void con_attach(Con *con, Con *parent, bool ignore_focus)
Attaches the given container to the given parent.
Con * con_get_output(Con *con)
Gets the output container (first container with CT_OUTPUT in hierarchy) this node is on.
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.
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...
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 * output_primary_name(Output *output)
Retrieves the primary name of an output.
void output_push_sticky_windows(Con *old_focus)
Iterates over all outputs and pushes sticky windows to the currently visible workspace on that output...
Con * output_get_content(Con *output)
Returns the output container below the given output container.
Output * get_output_for_con(Con *con)
Returns the output for the given con.
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_encapsulate(Con *ws)
Creates a new container and re-parents all of children from the given workspace into it.
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...
static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents)
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 * create_workspace_on_output(Output *output, Con *content)
Returns a pointer to a new workspace in the given output.
Con * workspace_get(const char *num)
Returns a pointer to the workspace with the given number (starting at 0), creating the workspace if n...
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.
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.
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_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_prev(void)
Returns the previous workspace.
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.
Con * workspace_prev_on_output(void)
Returns the previous workspace on the same output.
static char ** binding_workspace_names
void extract_workspace_names_from_bindings(void)
Extracts workspace names from keybindings (e.g.
static Con * _get_sticky(Con *con, const char *sticky_group, Con *exclude)
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 * workspace_next(void)
Returns the next 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 * 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.
char * sstrdup(const char *str)
Safe-wrapper around strdup 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...
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...
#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