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 assignment to output \"%s\"\n", assignment->
output);
95 if (assigned_by_name) {
97 return assigned_by_name->
con;
101 name_is_digits(assignment->
name) &&
103 DLOG(
"Found workspace number assignment to output \"%s\"\n", assignment->
output);
105 if (assigned_by_num) {
120 return assigned && assigned ==
output->con;
132 if (workspace == NULL) {
133 LOG(
"Creating new workspace \"%s\"\n", num);
143 if (strcmp(assignment->
name, num) == 0) {
158 LOG(
"got output %p with content %p\n",
output, content);
161 workspace =
con_new(NULL, NULL);
166 workspace->
type = CT_WORKSPACE;
170 workspace->
num = parsed_num;
171 LOG(
"num = %d\n", workspace->
num);
174 workspace->
parent = content;
183 }
else if (created != NULL) {
208 if (strlen(bind->
command) < strlen(
"workspace ") ||
209 strncasecmp(bind->
command,
"workspace", strlen(
"workspace")) != 0)
212 const char *target = bind->
command + strlen(
"workspace ");
213 while (*target ==
' ' || *target ==
'\t')
220 if (strncasecmp(target,
"next", strlen(
"next")) == 0 ||
221 strncasecmp(target,
"prev", strlen(
"prev")) == 0 ||
222 strncasecmp(target,
"next_on_output", strlen(
"next_on_output")) == 0 ||
223 strncasecmp(target,
"prev_on_output", strlen(
"prev_on_output")) == 0 ||
224 strncasecmp(target,
"back_and_forth", strlen(
"back_and_forth")) == 0 ||
225 strncasecmp(target,
"current", strlen(
"current")) == 0)
227 if (strncasecmp(target,
"--no-auto-back-and-forth", strlen(
"--no-auto-back-and-forth")) == 0) {
228 target += strlen(
"--no-auto-back-and-forth");
229 while (*target ==
' ' || *target ==
'\t')
232 if (strncasecmp(target,
"number", strlen(
"number")) == 0) {
233 target += strlen(
"number");
234 while (*target ==
' ' || *target ==
'\t')
238 if (target_name == NULL)
240 if (strncasecmp(target_name,
"__", strlen(
"__")) == 0) {
241 LOG(
"Cannot create workspace \"%s\". Names starting with __ are i3-internal.\n", target);
245 DLOG(
"Saving workspace name \"%s\"\n", target_name);
265 ws->
type = CT_WORKSPACE;
274 if (assigned && assigned !=
output->con) {
284 LOG(
"Used number %d for workspace with name %s\n", ws->
num, ws->
name);
292 DLOG(
"Getting next unused workspace by number\n");
298 DLOG(
"result for ws %d: exists = %d\n", c, exists);
306 if (strcmp(assignment->
name, ws->
name) == 0) {
338 LOG(
"workspace visible? fs = %p, ws = %p\n", fs, ws);
350 if (current != exclude &&
352 current->
window != NULL &&
362 if (current != exclude &&
364 current->
window != NULL &&
394 LOG(
"Ah, this one is sticky: %s / %p\n", current->
name, current);
400 LOG(
"No window found for this sticky group\n");
413 LOG(
"re-assigned window from src %p to dest %p\n", src, current);
433 DLOG(
"Resetting urgency flag of con %p by timer\n", con);
447 Con *current, *old = NULL;
465 if (workspace == current) {
466 DLOG(
"Not switching, already there.\n");
491 DLOG(
"switching to %p / %s\n", workspace, workspace->
name);
511 DLOG(
"Deferring reset of urgency flag of con %p on newly shown workspace %p\n",
520 DLOG(
"Resetting urgency timer of con %p on workspace %p\n",
529 DLOG(
"old = %p / %s\n", old, (old ? old->
name :
"(null)"));
538 LOG(
"Closing old workspace (%p / %s), it is empty\n", old, old->
name);
542 const unsigned char *payload;
544 y(get_buf, &payload, &length);
545 ipc_send_event(
"workspace", I3_IPC_EVENT_WORKSPACE, (
const char *)payload);
550 if (old == old_focus) {
563 if (old_output != new_output) {
590 Con *next = NULL, *first = NULL, *first_opposite = NULL;
593 if (current->
num == -1) {
595 if ((next =
TAILQ_NEXT(current, nodes)) != NULL)
597 bool found_current =
false;
603 if (child->type != CT_WORKSPACE)
607 if (!first_opposite || (child->num != -1 && child->num < first_opposite->num))
608 first_opposite = child;
609 if (child == current) {
610 found_current =
true;
611 }
else if (child->num == -1 && found_current) {
624 if (child->type != CT_WORKSPACE)
626 if (!first || (child->num != -1 && child->num < first->num))
628 if (!first_opposite && child->num == -1)
629 first_opposite = child;
630 if (child->num == -1)
635 if (current->
num < child->num && (!next || child->
num < next->
num))
642 next = first_opposite ? first_opposite : first;
653 Con *prev = NULL, *first_opposite = NULL, *last = NULL;
656 if (current->
num == -1) {
658 prev =
TAILQ_PREV(current, nodes_head, nodes);
659 if (prev && prev->
num != -1)
662 bool found_current =
false;
668 if (child->type != CT_WORKSPACE)
672 if (!first_opposite || (child->num != -1 && child->num > first_opposite->num))
673 first_opposite = child;
674 if (child == current) {
675 found_current =
true;
676 }
else if (child->num == -1 && found_current) {
690 if (child->type != CT_WORKSPACE)
692 if (!last || (child->num != -1 && last->num < child->num))
694 if (!first_opposite && child->num == -1)
695 first_opposite = child;
696 if (child->num == -1)
701 if (current->
num > child->num && (!prev || child->
num > prev->
num))
708 prev = first_opposite ? first_opposite : last;
722 if (current->
num == -1) {
728 if (child->type != CT_WORKSPACE)
730 if (child->num == -1)
735 if (current->
num < child->num && (!next || child->
num < next->
num))
742 bool found_current =
false;
744 if (child->type != CT_WORKSPACE)
746 if (child == current) {
747 found_current =
true;
748 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
750 goto workspace_next_on_output_end;
758 if (child->type != CT_WORKSPACE)
760 if (!next || (child->num != -1 && child->num < next->
num))
764 workspace_next_on_output_end:
778 if (current->
num == -1) {
780 prev =
TAILQ_PREV(current, nodes_head, nodes);
781 if (prev && prev->
num != -1)
786 if (child->type != CT_WORKSPACE || child->num == -1)
791 if (current->
num > child->num && (!prev || child->
num > prev->
num))
798 bool found_current =
false;
800 if (child->type != CT_WORKSPACE)
802 if (child == current) {
803 found_current =
true;
804 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
806 goto workspace_prev_on_output_end;
814 if (child->type != CT_WORKSPACE)
816 if (!prev || child->
num > prev->
num)
821 workspace_prev_on_output_end:
831 DLOG(
"No previous workspace name set. Not switching.\n");
844 DLOG(
"No previous workspace name set.\n");
873 bool old_flag = ws->
urgent;
875 DLOG(
"Workspace urgency flag changed from %d to %d\n", old_flag, ws->
urgent);
877 if (old_flag != ws->
urgent)
897 DLOG(
"Moving cons\n");
912 DLOG(
"Attaching new split (%p) to ws (%p)\n", split, ws);
930 DLOG(
"Attaching a window to workspace %p / %s\n", ws, ws->
name);
933 DLOG(
"Default layout, just attaching it to the workspace itself.\n");
937 DLOG(
"Non-default layout, creating a new split container\n");
946 DLOG(
"Attaching new split %p to workspace %p\n",
new, ws);
963 ELOG(
"Workspace %p / %s has no children to encapsulate\n", ws, ws->
name);
973 DLOG(
"Moving children of workspace %p / %s into container %p\n",
998 DLOG(
"got output %p with content %p\n",
output, content);
1000 if (ws->
parent == content) {
1001 DLOG(
"Nothing to do, workspace already there\n");
1006 if (previously_visible_ws) {
1007 DLOG(
"Previously visible workspace = %p / %s\n", previously_visible_ws, previously_visible_ws->
name);
1009 DLOG(
"No previously visible workspace on output.\n");
1014 DLOG(
"Creating a new workspace to replace \"%s\" (last on its output).\n", ws->
name);
1017 bool used_assignment =
false;
1033 DLOG(
"Creating workspace from assignment %s.\n", assignment->
name);
1035 used_assignment =
true;
1042 if (!used_assignment) {
1046 DLOG(
"Detaching\n");
1051 if (workspace_was_visible) {
1055 DLOG(
"workspace was visible, focusing %p / %s now\n", focus_ws, focus_ws->
name);
1067 if (workspace_was_visible) {
1074 if (!previously_visible_ws) {
1084 if (ws != previously_visible_ws) {
1091 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...
long 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_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.
static Con * get_assigned_output(const char *name, long parsed_num)
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...
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