workspace->type = CT_WORKSPACE;
FREE(workspace->name);
workspace->name = sstrdup(num);
+ workspace->workspace_layout = config.default_layout;
/* We set ->num to the number if this workspace’s name begins with a
* positive number. Otherwise it’s a named ws and num will be -1. */
char *endptr = NULL;
workspace_reassign_sticky(current);
}
+/*
+ * Callback to reset the urgent flag of the given con to false. May be started by
+ * _workspace_show to avoid urgency hints being lost by switching to a workspace
+ * focusing the con.
+ *
+ */
+static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents) {
+ Con *con = w->data;
+
+ DLOG("Resetting urgency flag of con %p by timer\n", con);
+ con->urgent = false;
+ con_update_parents_urgency(con);
+ workspace_update_urgent_flag(con_get_workspace(con));
+ tree_render();
+
+ ev_timer_stop(main_loop, con->urgency_timer);
+ FREE(con->urgency_timer);
+}
static void _workspace_show(Con *workspace) {
Con *current, *old = NULL;
/* safe-guard against showing i3-internal workspaces like __i3_scratch */
- if (workspace->name[0] == '_' && workspace->name[1] == '_')
+ if (con_is_internal(workspace))
return;
/* disable fullscreen for the other workspaces and get the workspace we are
workspace_reassign_sticky(workspace);
- LOG("switching to %p\n", workspace);
+ DLOG("switching to %p / %s\n", workspace, workspace->name);
Con *next = con_descend_focused(workspace);
+ /* Memorize current output */
+ Con *old_output = con_get_output(focused);
+
+ /* Display urgency hint for a while if the newly visible workspace would
+ * focus and thereby immediately destroy it */
+ if (next->urgent && (int)(config.workspace_urgency_timer * 1000) > 0) {
+ /* focus for now… */
+ con_focus(next);
+
+ /* … but immediately reset urgency flags; they will be set to false by
+ * the timer callback in case the container is focused at the time of
+ * its expiration */
+ focused->urgent = true;
+ workspace->urgent = true;
+
+ if (focused->urgency_timer == NULL) {
+ DLOG("Deferring reset of urgency flag of con %p on newly shown workspace %p\n",
+ focused, workspace);
+ focused->urgency_timer = scalloc(sizeof(struct ev_timer));
+ /* use a repeating timer to allow for easy resets */
+ ev_timer_init(focused->urgency_timer, workspace_defer_update_urgent_hint_cb,
+ config.workspace_urgency_timer, config.workspace_urgency_timer);
+ focused->urgency_timer->data = focused;
+ ev_timer_start(main_loop, focused->urgency_timer);
+ } else {
+ DLOG("Resetting urgency timer of con %p on workspace %p\n",
+ focused, workspace);
+ ev_timer_again(main_loop, focused->urgency_timer);
+ }
+ } else
+ con_focus(next);
+
+ DLOG("old = %p / %s\n", old, (old ? old->name : "(null)"));
+ /* Close old workspace if necessary. This must be done *after* doing
+ * urgency handling, because tree_close() will do a con_focus() on the next
+ * client, which will clear the urgency flag too early. Also, there is no
+ * way for con_focus() to know about when to clear urgency immediately and
+ * when to defer it. */
if (old && TAILQ_EMPTY(&(old->nodes_head)) && TAILQ_EMPTY(&(old->floating_head))) {
/* check if this workspace is currently visible */
if (!workspace_is_visible(old)) {
}
}
- /* Memorize current output */
- Con *old_output = con_get_output(focused);
-
- con_focus(next);
workspace->fullscreen_mode = CF_OUTPUT;
LOG("focused now = %p / %s\n", focused, focused->name);
*/
void workspace_show_by_name(const char *num) {
Con *workspace;
- bool changed_num_workspaces;
- workspace = workspace_get(num, &changed_num_workspaces);
+ workspace = workspace_get(num, NULL);
_workspace_show(workspace);
}
/* If currently a numbered workspace, find next numbered workspace. */
TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
/* Skip outputs starting with __, they are internal. */
- if (output->name[0] == '_' && output->name[1] == '_')
+ if (con_is_internal(output))
continue;
NODES_FOREACH(output_get_content(output)) {
if (child->type != CT_WORKSPACE)
bool found_current = false;
TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
/* Skip outputs starting with __, they are internal. */
- if (output->name[0] == '_' && output->name[1] == '_')
+ if (con_is_internal(output))
continue;
NODES_FOREACH(output_get_content(output)) {
if (child->type != CT_WORKSPACE)
if (!next) {
TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
/* Skip outputs starting with __, they are internal. */
- if (output->name[0] == '_' && output->name[1] == '_')
+ if (con_is_internal(output))
continue;
NODES_FOREACH(output_get_content(output)) {
if (child->type != CT_WORKSPACE)
/* If numbered workspace, find previous numbered workspace. */
TAILQ_FOREACH_REVERSE(output, &(croot->nodes_head), nodes_head, nodes) {
/* Skip outputs starting with __, they are internal. */
- if (output->name[0] == '_' && output->name[1] == '_')
+ if (con_is_internal(output))
continue;
NODES_FOREACH_REVERSE(output_get_content(output)) {
if (child->type != CT_WORKSPACE || child->num == -1)
bool found_current = false;
TAILQ_FOREACH_REVERSE(output, &(croot->nodes_head), nodes_head, nodes) {
/* Skip outputs starting with __, they are internal. */
- if (output->name[0] == '_' && output->name[1] == '_')
+ if (con_is_internal(output))
continue;
NODES_FOREACH_REVERSE(output_get_content(output)) {
if (child->type != CT_WORKSPACE)
if (!prev) {
TAILQ_FOREACH_REVERSE(output, &(croot->nodes_head), nodes_head, nodes) {
/* Skip outputs starting with __, they are internal. */
- if (output->name[0] == '_' && output->name[1] == '_')
+ if (con_is_internal(output))
continue;
NODES_FOREACH_REVERSE(output_get_content(output)) {
if (child->type != CT_WORKSPACE)
workspace_show_by_name(previous_workspace_name);
}
+/*
+ * Returns the previously focused workspace con, or NULL if unavailable.
+ *
+ */
+Con *workspace_back_and_forth_get(void) {
+ if (!previous_workspace_name) {
+ DLOG("no previous workspace name set.");
+ return NULL;
+ }
+
+ Con *workspace;
+ workspace = workspace_get(previous_workspace_name, NULL);
+
+ return workspace;
+}
+
static bool get_urgency_flag(Con *con) {
Con *child;
TAILQ_FOREACH(child, &(con->nodes_head), nodes)
/* 1: create a new split container */
Con *split = con_new(NULL, NULL);
split->parent = ws;
+ split->split = true;
/* 2: copy layout from workspace */
split->layout = ws->layout;
/* 4: switch workspace layout */
ws->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV;
+ DLOG("split->layout = %d, ws->layout = %d\n", split->layout, ws->layout);
/* 5: attach the new split container to the workspace */
- DLOG("Attaching new split to ws\n");
+ DLOG("Attaching new split (%p) to ws (%p)\n", split, ws);
con_attach(split, ws, false);
/* 6: fix the percentages */
Con *workspace_attach_to(Con *ws) {
DLOG("Attaching a window to workspace %p / %s\n", ws, ws->name);
- if (config.default_layout == L_DEFAULT) {
+ if (ws->workspace_layout == L_DEFAULT) {
DLOG("Default layout, just attaching it to the workspace itself.\n");
return ws;
}
new->split = true;
/* 2: set the requested layout on the split con */
- new->layout = config.default_layout;
+ new->layout = ws->workspace_layout;
/* 4: attach the new split container to the workspace */
DLOG("Attaching new split %p to workspace %p\n", new, ws);
return new;
}
+
+/**
+ * Creates a new container and re-parents all of children from the given
+ * workspace into it.
+ *
+ * The container inherits the layout from the workspace.
+ */
+Con *workspace_encapsulate(Con *ws) {
+ if (TAILQ_EMPTY(&(ws->nodes_head))) {
+ ELOG("Workspace %p / %s has no children to encapsulate\n", ws, ws->name);
+ return NULL;
+ }
+
+ Con *new = con_new(NULL, NULL);
+ new->parent = ws;
+ new->layout = ws->layout;
+
+ DLOG("Moving children of workspace %p / %s into container %p\n",
+ ws, ws->name, new);
+
+ Con *child;
+ while (!TAILQ_EMPTY(&(ws->nodes_head))) {
+ child = TAILQ_FIRST(&(ws->nodes_head));
+ con_detach(child);
+ con_attach(child, new, true);
+ }
+
+ con_attach(new, ws, true);
+
+ return new;
+}