2 #define I3__FILE__ "workspace.c"
16 #include <yajl/yajl_gen.h>
34 DLOG(
"Auto orientation. Workspace size set to (%d,%d), setting layout to %d.\n",
48 Con *output, *workspace = NULL;
53 if (workspace == NULL) {
54 LOG(
"Creating new workspace \"%s\"\n", num);
60 if (strcmp(assignment->
name, num) != 0)
63 LOG(
"Found workspace assignment to output \"%s\"\n", assignment->
output);
68 LOG(
"got output %p with content %p\n", output, content);
71 workspace =
con_new(NULL, NULL);
73 sasprintf(&name,
"[i3 con] workspace %s", num);
76 workspace->
type = CT_WORKSPACE;
83 long parsed_num = strtol(num, &endptr, 10);
84 if (parsed_num == LONG_MIN ||
85 parsed_num == LONG_MAX ||
89 else workspace->
num = parsed_num;
90 LOG(
"num = %d\n", workspace->
num);
92 workspace->
parent = content;
97 ipc_send_event(
"workspace", I3_IPC_EVENT_WORKSPACE,
"{\"change\":\"init\"}");
101 else if (created != NULL) {
120 ws->
type = CT_WORKSPACE;
126 if (strlen(bind->
command) < strlen(
"workspace ") ||
127 strncasecmp(bind->
command,
"workspace", strlen(
"workspace")) != 0)
130 char *target = bind->
command + strlen(
"workspace ");
131 while((*target ==
' ' || *target ==
'\t') && target !=
'\0')
138 if (strncasecmp(target,
"next", strlen(
"next")) == 0 ||
139 strncasecmp(target,
"prev", strlen(
"prev")) == 0 ||
140 strncasecmp(target,
"next_on_output", strlen(
"next_on_output")) == 0 ||
141 strncasecmp(target,
"prev_on_output", strlen(
"prev_on_output")) == 0 ||
142 strncasecmp(target,
"number", strlen(
"number")) == 0 ||
143 strncasecmp(target,
"back_and_forth", strlen(
"back_and_forth")) == 0 ||
144 strncasecmp(target,
"current", strlen(
"current")) == 0)
149 ws->
name = strdup(target);
150 if (ws->
name[strlen(ws->
name)-1] ==
'"')
151 ws->
name[strlen(ws->
name)-1] =
'\0';
152 DLOG(
"trying name *%s*\n", ws->
name);
157 bool assigned =
false;
160 if (strcmp(assignment->
name, ws->
name) != 0 ||
161 strcmp(assignment->
output, output->
name) == 0)
175 exists = (current != NULL);
180 long parsed_num = strtol(ws->
name, &endptr, 10);
181 if (parsed_num == LONG_MIN ||
182 parsed_num == LONG_MAX ||
186 else ws->
num = parsed_num;
187 LOG(
"Used number %d for workspace with name %s\n", ws->
num, ws->
name);
195 DLOG(
"Getting next unused workspace by number\n");
206 exists = (current != NULL);
208 DLOG(
"result for ws %s / %d: exists = %d\n", ws->
name, c, exists);
238 LOG(
"workspace visible? fs = %p, ws = %p\n", fs, ws);
250 if (current != exclude &&
252 current->
window != NULL &&
261 TAILQ_FOREACH(current, &(con->floating_head), floating_windows) {
262 if (current != exclude &&
264 current->
window != NULL &&
294 LOG(
"Ah, this one is sticky: %s / %p\n", current->
name, current);
300 LOG(
"No window found for this sticky group\n");
313 LOG(
"re-assigned window from src %p to dest %p\n", src, current);
316 TAILQ_FOREACH(current, &(con->floating_head), floating_windows)
329 DLOG(
"Resetting urgency flag of con %p by timer\n", con);
344 setlocale(LC_NUMERIC,
"C");
363 const unsigned char *payload;
365 y(get_buf, &payload, &length);
367 ipc_send_event(
"workspace", I3_IPC_EVENT_WORKSPACE, (
const char *)payload);
369 setlocale(LC_NUMERIC,
"");
373 Con *current, *old = NULL;
391 if (workspace == current) {
392 DLOG(
"Not switching, already there.\n");
412 DLOG(
"switching to %p / %s\n", workspace, workspace->
name);
431 DLOG(
"Deferring reset of urgency flag of con %p on newly shown workspace %p\n",
440 DLOG(
"Resetting urgency timer of con %p on workspace %p\n",
449 DLOG(
"old = %p / %s\n", old, (old ? old->
name :
"(null)"));
458 LOG(
"Closing old workspace (%p / %s), it is empty\n", old, old->
name);
460 ipc_send_event(
"workspace", I3_IPC_EVENT_WORKSPACE,
"{\"change\":\"empty\"}");
469 if (old_output != new_output) {
504 if (current->
num == -1) {
514 if (child->type != CT_WORKSPACE)
516 if (child->num == -1)
521 if (current->
num < child->num && (!next || child->
num < next->
num))
529 bool found_current =
false;
535 if (child->type != CT_WORKSPACE)
537 if (child == current) {
539 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
541 goto workspace_next_end;
554 if (child->type != CT_WORKSPACE)
556 if (!next || (child->num != -1 && child->num < next->
num))
574 if (current->
num == -1) {
576 prev =
TAILQ_PREV(current, nodes_head, nodes);
577 if (prev && prev->
num != -1)
586 if (child->type != CT_WORKSPACE || child->num == -1)
591 if (current->
num > child->num && (!prev || child->
num > prev->
num))
599 bool found_current =
false;
605 if (child->type != CT_WORKSPACE)
607 if (child == current) {
608 found_current =
true;
609 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
611 goto workspace_prev_end;
624 if (child->type != CT_WORKSPACE)
626 if (!prev || child->
num > prev->
num)
646 if (current->
num == -1) {
652 if (child->type != CT_WORKSPACE)
654 if (child->num == -1)
659 if (current->
num < child->num && (!next || child->
num < next->
num))
666 bool found_current =
false;
668 if (child->type != CT_WORKSPACE)
670 if (child == current) {
672 }
else if (child->num == -1 && (current->
num != -1 || found_current)) {
674 goto workspace_next_on_output_end;
682 if (child->type != CT_WORKSPACE)
684 if (!next || (child->num != -1 && child->num < next->
num))
688 workspace_next_on_output_end:
700 DLOG(
"output = %s\n", output->
name);
702 if (current->
num == -1) {
704 prev =
TAILQ_PREV(current, nodes_head, nodes);
705 if (prev && prev->
num != -1)
710 if (child->type != CT_WORKSPACE || child->num == -1)
715 if (current->
num > child->num && (!prev || child->
num > prev->
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_prev_on_output_end;
738 if (child->type != CT_WORKSPACE)
740 if (!prev || child->
num > prev->
num)
745 workspace_prev_on_output_end:
755 DLOG(
"No previous workspace name set. Not switching.");
768 DLOG(
"no previous workspace name set.");
784 TAILQ_FOREACH(child, &(con->floating_head), floating_windows)
797 bool old_flag = ws->
urgent;
799 DLOG(
"Workspace urgency flag changed from %d to %d\n", old_flag, ws->
urgent);
801 if (old_flag != ws->
urgent)
802 ipc_send_event(
"workspace", I3_IPC_EVENT_WORKSPACE,
"{\"change\":\"urgent\"}");
821 DLOG(
"Moving cons\n");
833 DLOG(
"Attaching new split (%p) to ws (%p)\n", split, ws);
854 DLOG(
"Attaching a window to workspace %p / %s\n", ws, ws->
name);
857 DLOG(
"Default layout, just attaching it to the workspace itself.\n");
861 DLOG(
"Non-default layout, creating a new split container\n");
870 DLOG(
"Attaching new split %p to workspace %p\n",
new, ws);
884 ELOG(
"Workspace %p / %s has no children to encapsulate\n", ws, ws->
name);
892 DLOG(
"Moving children of workspace %p / %s into container %p\n",
char * name
Name of the output.
#define GREP_FIRST(dest, head, condition)
A 'Con' represents everything from the X11 root window down to a single X11 window.
void workspace_show(Con *workspace)
Switches to the given workspace.
Stores which workspace (by name) goes to which output.
bool workspace_is_visible(Con *ws)
Returns true if the workspace is currently visible.
#define NODES_FOREACH(head)
static void _workspace_show(Con *workspace)
void ewmh_update_current_desktop(void)
Updates _NET_CURRENT_DESKTOP with the current desktop number.
static bool get_urgency_flag(Con *con)
#define NODES_FOREACH_REVERSE(head)
void con_attach(Con *con, Con *parent, bool ignore_focus)
Attaches the given container to the given parent.
#define TAILQ_EMPTY(head)
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
Con * workspace_next_on_output(void)
Returns the next workspace on the same output.
#define TAILQ_PREV(elm, headname, field)
bool con_is_internal(Con *con)
Returns true if the container is internal, such as __i3_scratch.
Con * workspace_encapsulate(Con *ws)
Creates a new container and re-parents all of children from the given workspace into it...
void * scalloc(size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
void con_fix_percent(Con *con)
Updates the percent attribute of the children of the given container.
Con * workspace_prev(void)
Returns the previous workspace.
float workspace_urgency_timer
By default, urgency is cleared immediately when switching to another workspace leads to focusing the ...
static void _workspace_apply_default_orientation(Con *ws)
void workspace_back_and_forth(void)
Focuses the previously focused workspace.
Holds a keybinding, consisting of a keycode combined with modifiers and the command which is executed...
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...
int default_orientation
Default orientation for new containers.
void x_set_warp_to(Rect *rect)
Set warp_to coordinates.
char * command
Command, like in command mode.
struct ws_assignments_head ws_assignments
void x_move_win(Con *src, Con *dest)
Moves a child window from Container src to Container dest.
void workspace_show_by_name(const char *num)
Looks up the workspace by name and switches to it.
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...
void workspace_update_urgent_flag(Con *ws)
Goes through all clients on the given workspace and updates the workspace’s urgent flag accordingly...
Con * con_descend_focused(Con *con)
Returns the focused con inside this client, descending the tree as far as possible.
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...
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool force_set_focus)
Closes the given container including all children.
Con * workspace_back_and_forth_get(void)
Returns the previously focused workspace con, or NULL if unavailable.
Con * workspace_next(void)
Returns the next workspace.
#define TAILQ_NEXT(elm, field)
void con_focus(Con *con)
Sets input focus to the given container.
Con * workspace_prev_on_output(void)
Returns the previous workspace on the same output.
static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents)
#define TAILQ_FIRST(head)
An Output is a physical output on your graphics driver.
#define TAILQ_FOREACH(var, head, field)
Con * _get_sticky(Con *con, const char *sticky_group, Con *exclude)
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...
struct ev_loop * main_loop
struct ev_timer * urgency_timer
Con * con_new(Con *parent, i3Window *window)
int num
the workspace number, if this Con is of type CT_WORKSPACE and the workspace is not a named workspace ...
void con_detach(Con *con)
Detaches the given container from its current parent.
layout_t workspace_layout
Con * output_get_content(Con *output)
Returns the output container below the given output container.
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...
Con * con_get_output(Con *con)
Gets the output container (first container with CT_OUTPUT in hierarchy) this node is on...
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
struct bindings_head * bindings
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 ...
static void ipc_send_workspace_focus_event(Con *current, Con *old)
static char * previous_workspace_name
Con * create_workspace_on_output(Output *output, Con *content)
static void workspace_reassign_sticky(Con *con)
Con * con_get_fullscreen_con(Con *con, int fullscreen_mode)
Returns the first fullscreen node below this node.
void x_reparent_child(Con *con, Con *old)
Reparents the child window of the given container (necessary for sticky containers).
void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart)
enum Con::@19 fullscreen_mode
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 ...