} \
} while (0)
-static owindows_head owindows;
/*
* Returns true if a is definitely greater than b (using the given epsilon)
static Output *get_output_from_string(Output *current_output, const char *output_str) {
Output *output;
- if (strcasecmp(output_str, "left") == 0) {
- output = get_output_next(D_LEFT, current_output, CLOSEST_OUTPUT);
- if (!output)
- output = get_output_most(D_RIGHT, current_output);
- } else if (strcasecmp(output_str, "right") == 0) {
- output = get_output_next(D_RIGHT, current_output, CLOSEST_OUTPUT);
- if (!output)
- output = get_output_most(D_LEFT, current_output);
- } else if (strcasecmp(output_str, "up") == 0) {
- output = get_output_next(D_UP, current_output, CLOSEST_OUTPUT);
- if (!output)
- output = get_output_most(D_DOWN, current_output);
- } else if (strcasecmp(output_str, "down") == 0) {
- output = get_output_next(D_DOWN, current_output, CLOSEST_OUTPUT);
- if (!output)
- output = get_output_most(D_UP, current_output);
- } else output = get_output_by_name(output_str);
+ if (strcasecmp(output_str, "left") == 0)
+ output = get_output_next_wrap(D_LEFT, current_output);
+ else if (strcasecmp(output_str, "right") == 0)
+ output = get_output_next_wrap(D_RIGHT, current_output);
+ else if (strcasecmp(output_str, "up") == 0)
+ output = get_output_next_wrap(D_UP, current_output);
+ else if (strcasecmp(output_str, "down") == 0)
+ output = get_output_next_wrap(D_DOWN, current_output);
+ else output = get_output_by_name(output_str);
return output;
}
* Criteria functions.
******************************************************************************/
+/*
+ * Helper data structure for an operation window (window on which the operation
+ * will be performed). Used to build the TAILQ owindows.
+ *
+ */
+typedef struct owindow {
+ Con *con;
+ TAILQ_ENTRY(owindow) owindows;
+} owindow;
+
+typedef TAILQ_HEAD(owindows_head, owindow) owindows_head;
+
+static owindows_head owindows;
+
/*
* Initializes the specified 'Match' data structure and the initial state of
* commands.c for matching target windows of a command.
* when criteria was specified but didn't match any window or
* when criteria wasn't specified and we don't have any window focused. */
if ((!match_is_empty(current_match) && TAILQ_EMPTY(&owindows)) ||
- (match_is_empty(current_match) && focused->type == CT_WORKSPACE)) {
+ (match_is_empty(current_match) && focused->type == CT_WORKSPACE &&
+ !con_has_children(focused))) {
ysuccess(false);
return;
}
ysuccess(false);
return;
}
-
- if (match_is_empty(current_match) && focused->type == CT_WORKSPACE) {
- ELOG("No window to move, you have focused a workspace.\n");
+ else if (match_is_empty(current_match) && focused->type == CT_WORKSPACE &&
+ !con_has_children(focused)) {
ysuccess(false);
return;
}
* when criteria was specified but didn't match any window or
* when criteria wasn't specified and we don't have any window focused. */
if ((!match_is_empty(current_match) && TAILQ_EMPTY(&owindows)) ||
- (match_is_empty(current_match) && focused->type == CT_WORKSPACE)) {
+ (match_is_empty(current_match) && focused->type == CT_WORKSPACE &&
+ !con_has_children(focused))) {
ysuccess(false);
return;
}
static void cmd_resize_floating(I3_CMD, char *way, char *direction, Con *floating_con, int px) {
LOG("floating resize\n");
+ Rect old_rect = floating_con->rect;
+
if (strcmp(direction, "up") == 0) {
- floating_con->rect.y -= px;
floating_con->rect.height += px;
} else if (strcmp(direction, "down") == 0 || strcmp(direction, "height") == 0) {
floating_con->rect.height += px;
} else if (strcmp(direction, "left") == 0) {
- floating_con->rect.x -= px;
floating_con->rect.width += px;
} else {
floating_con->rect.width += px;
}
+
+ floating_check_size(floating_con);
+
+ /* Did we actually resize anything or did the size constraints prevent us?
+ * If we could not resize, exit now to not move the window. */
+ if (memcmp(&old_rect, &(floating_con->rect), sizeof(Rect)) == 0)
+ return;
+
+ if (strcmp(direction, "up") == 0) {
+ floating_con->rect.y -= (floating_con->rect.height - old_rect.height);
+ } else if (strcmp(direction, "left") == 0) {
+ floating_con->rect.x -= (floating_con->rect.width - old_rect.width);
+ }
+
+ /* If this is a scratchpad window, don't auto center it from now on. */
+ if (floating_con->scratchpad_state == SCRATCHPAD_FRESH)
+ floating_con->scratchpad_state = SCRATCHPAD_CHANGED;
}
-static bool cmd_resize_tiling_direction(I3_CMD, char *way, char *direction, int ppt) {
+static bool cmd_resize_tiling_direction(I3_CMD, Con *current, char *way, char *direction, int ppt) {
LOG("tiling resize\n");
/* get the appropriate current container (skip stacked/tabbed cons) */
- Con *current = focused;
Con *other = NULL;
double percentage = 0;
while (current->parent->layout == L_STACKED ||
return true;
}
-static bool cmd_resize_tiling_width_height(I3_CMD, char *way, char *direction, int ppt) {
+static bool cmd_resize_tiling_width_height(I3_CMD, Con *current, char *way, char *direction, int ppt) {
LOG("width/height resize\n");
/* get the appropriate current container (skip stacked/tabbed cons) */
- Con *current = focused;
while (current->parent->layout == L_STACKED ||
current->parent->layout == L_TABBED)
current = current->parent;
ppt *= -1;
}
- Con *floating_con;
- if ((floating_con = con_inside_floating(focused))) {
- cmd_resize_floating(current_match, cmd_output, way, direction, floating_con, px);
- } else {
- if (strcmp(direction, "width") == 0 ||
- strcmp(direction, "height") == 0) {
- if (!cmd_resize_tiling_width_height(current_match, cmd_output, way, direction, ppt))
- return;
+ HANDLE_EMPTY_MATCH;
+
+ owindow *current;
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ Con *floating_con;
+ if ((floating_con = con_inside_floating(current->con))) {
+ cmd_resize_floating(current_match, cmd_output, way, direction, floating_con, px);
} else {
- if (!cmd_resize_tiling_direction(current_match, cmd_output, way, direction, ppt))
- return;
+ if (strcmp(direction, "width") == 0 ||
+ strcmp(direction, "height") == 0) {
+ if (!cmd_resize_tiling_width_height(current_match, cmd_output, current->con, way, direction, ppt))
+ return;
+ } else {
+ if (!cmd_resize_tiling_direction(current_match, cmd_output, current->con, way, direction, ppt))
+ return;
+ }
}
}
// TODO: clean this up with commands.spec as soon as we switched away from the lex/yacc command parser
if (strcasecmp(name, "up") == 0)
- output = get_output_next(D_UP, current_output, CLOSEST_OUTPUT);
+ output = get_output_next_wrap(D_UP, current_output);
else if (strcasecmp(name, "down") == 0)
- output = get_output_next(D_DOWN, current_output, CLOSEST_OUTPUT);
+ output = get_output_next_wrap(D_DOWN, current_output);
else if (strcasecmp(name, "left") == 0)
- output = get_output_next(D_LEFT, current_output, CLOSEST_OUTPUT);
+ output = get_output_next_wrap(D_LEFT, current_output);
else if (strcasecmp(name, "right") == 0)
- output = get_output_next(D_RIGHT, current_output, CLOSEST_OUTPUT);
+ output = get_output_next_wrap(D_RIGHT, current_output);
else
output = get_output_by_name(name);
/* notify the IPC listeners */
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}");
}
+ DLOG("Detaching\n");
/* detach from the old output and attach to the new output */
Con *old_content = ws->parent;
workspace_show(ws);
}
- /* Call the on_remove_child callback of the workspace which previously
- * was visible on the destination output. Since it is no longer
- * visible, it might need to get cleaned up. */
- CALL(previously_visible_ws, on_remove_child);
+ /* NB: We cannot simply work with previously_visible_ws since it might
+ * have been cleaned up by workspace_show() already, depending on the
+ * focus order/number of other workspaces on the output.
+ * Instead, we loop through the available workspaces and only work with
+ * previously_visible_ws if we still find it. */
+ TAILQ_FOREACH(ws, &(content->nodes_head), nodes) {
+ if (ws != previously_visible_ws)
+ continue;
+
+ /* Call the on_remove_child callback of the workspace which previously
+ * was visible on the destination output. Since it is no longer
+ * visible, it might need to get cleaned up. */
+ CALL(previously_visible_ws, on_remove_child);
+ break;
+ }
}
cmd_output->needs_tree_render = true;
}
/*
- * Implementaiton of 'kill [window|client]'.
+ * Implementation of 'kill [window|client]'.
*
*/
void cmd_kill(I3_CMD, char *kill_mode_str) {
*
*/
void cmd_focus_direction(I3_CMD, char *direction) {
- if (focused &&
- focused->type != CT_WORKSPACE &&
- focused->fullscreen_mode != CF_NONE) {
- LOG("Cannot change focus while in fullscreen mode.\n");
- ysuccess(false);
- return;
- }
-
DLOG("direction = *%s*\n", direction);
if (strcmp(direction, "left") == 0)
*
*/
void cmd_focus_window_mode(I3_CMD, char *window_mode) {
- if (focused &&
- focused->type != CT_WORKSPACE &&
- focused->fullscreen_mode != CF_NONE) {
- LOG("Cannot change focus while in fullscreen mode.\n");
- ysuccess(false);
- return;
- }
-
DLOG("window_mode = %s\n", window_mode);
Con *ws = con_get_workspace(focused);
return;
}
+ Con *__i3_scratch = workspace_get("__i3_scratch", NULL);
int count = 0;
owindow *current;
TAILQ_FOREACH(current, &owindows, owindows) {
return;
}
+ /* In case this is a scratchpad window, call scratchpad_show(). */
+ if (ws == __i3_scratch) {
+ scratchpad_show(current->con);
+ count++;
+ /* While for the normal focus case we can change focus multiple
+ * times and only a single window ends up focused, we could show
+ * multiple scratchpad windows. So, rather break here. */
+ break;
+ }
+
/* If the container is not on the current workspace,
* workspace_show() will switch to a different workspace and (if
* enabled) trigger a mouse pointer warp to the currently focused
}
/*
- * Implementaiton of 'exit'.
+ * Implementation of 'exit'.
*
*/
void cmd_exit(I3_CMD) {
}
/*
- * Implementaiton of 'reload'.
+ * Implementation of 'reload'.
*
*/
void cmd_reload(I3_CMD) {
LOG("reloading\n");
- kill_configerror_nagbar(false);
- kill_commanderror_nagbar(false);
+ kill_nagbar(&config_error_nagbar_pid, false);
+ kill_nagbar(&command_error_nagbar_pid, false);
load_configuration(conn, NULL, true);
x_set_i3_atoms();
/* Send an IPC event just in case the ws names have changed */
}
/*
- * Implementaiton of 'restart'.
+ * Implementation of 'restart'.
*
*/
void cmd_restart(I3_CMD) {
}
/*
- * Implementaiton of 'open'.
+ * Implementation of 'open'.
*
*/
void cmd_open(I3_CMD) {
}
/*
- * Implementation of 'rename workspace <name> to <name>'
+ * Implementation of 'rename workspace [<name>] to <name>'
*
*/
void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) {
- LOG("Renaming workspace \"%s\" to \"%s\"\n", old_name, new_name);
+ if (old_name) {
+ LOG("Renaming workspace \"%s\" to \"%s\"\n", old_name, new_name);
+ } else {
+ LOG("Renaming current workspace to \"%s\"\n", new_name);
+ }
Con *output, *workspace = NULL;
- TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
- GREP_FIRST(workspace, output_get_content(output),
- !strcasecmp(child->name, old_name));
+ if (old_name) {
+ TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
+ GREP_FIRST(workspace, output_get_content(output),
+ !strcasecmp(child->name, old_name));
+ } else {
+ workspace = con_get_workspace(focused);
+ }
if (!workspace) {
// TODO: we should include the old workspace name here and use yajl for