+#undef I3__FILE__
+#define I3__FILE__ "commands.c"
/*
* vim:ts=4:sw=4:expandtab
*
#include "all.h"
+// Macros to make the YAJL API a bit easier to use.
+#define y(x, ...) yajl_gen_ ## x (cmd_output->json_gen, ##__VA_ARGS__)
+#define ystr(str) yajl_gen_string(cmd_output->json_gen, (unsigned char*)str, strlen(str))
+#define ysuccess(success) do { \
+ y(map_open); \
+ ystr("success"); \
+ y(bool, success); \
+ y(map_close); \
+} while (0)
+
/** When the command did not include match criteria (!), we use the currently
- * focused command. Do not confuse this case with a command which included
+ * focused container. Do not confuse this case with a command which included
* criteria but which did not match any windows. This macro has to be called in
* every command.
*/
Output *output;
if (strcasecmp(output_str, "left") == 0) {
- output = get_output_next(D_LEFT, current_output);
+ 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);
+ 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);
+ 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);
+ 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);
return output;
}
+/*
+ * Checks whether we switched to a new workspace and returns false in that case,
+ * signaling that further workspace switching should be done by the calling function
+ * If not, calls workspace_back_and_forth() if workspace_auto_back_and_forth is set
+ * and return true, signaling that no further workspace switching should occur in the calling function.
+ *
+ */
+static bool maybe_back_and_forth(struct CommandResult *cmd_output, char *name) {
+ Con *ws = con_get_workspace(focused);
+
+ /* If we switched to a different workspace, do nothing */
+ if (strcmp(ws->name, name) != 0)
+ return false;
+
+ DLOG("This workspace is already focused.\n");
+ if (config.workspace_auto_back_and_forth) {
+ workspace_back_and_forth();
+ cmd_output->needs_tree_render = true;
+ }
+ return true;
+}
+
+/*
+ * Return the passed workspace unless it is the current one and auto back and
+ * forth is enabled, in which case the back_and_forth workspace is returned.
+ */
+static Con *maybe_auto_back_and_forth_workspace(Con *workspace) {
+ Con *current, *baf;
+
+ if (!config.workspace_auto_back_and_forth)
+ return workspace;
+
+ current = con_get_workspace(focused);
+
+ if (current == workspace) {
+ baf = workspace_back_and_forth_get();
+ if (baf != NULL) {
+ DLOG("Substituting workspace with back_and_forth, as it is focused.\n");
+ return baf;
+ }
+ }
+
+ return workspace;
+}
+
// This code is commented out because we might recycle it for popping up error
// messages on parser errors.
#if 0
/*
* Implementation of 'move [window|container] [to] workspace
- * next|prev|next_on_output|prev_on_output'.
+ * next|prev|next_on_output|prev_on_output|current'.
*
*/
void cmd_move_con_to_workspace(I3_CMD, char *which) {
DLOG("which=%s\n", which);
+ /* We have nothing to move:
+ * 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)) {
+ ysuccess(false);
+ return;
+ }
+
HANDLE_EMPTY_MATCH;
/* get the workspace */
ws = workspace_next_on_output();
else if (strcmp(which, "prev_on_output") == 0)
ws = workspace_prev_on_output();
+ else if (strcmp(which, "current") == 0)
+ ws = con_get_workspace(focused);
else {
ELOG("BUG: called with which=%s\n", which);
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
+}
+
+/**
+ * Implementation of 'move [window|container] [to] workspace back_and_forth'.
+ *
+ */
+void cmd_move_con_to_workspace_back_and_forth(I3_CMD) {
+ owindow *current;
+ Con *ws;
+
+ ws = workspace_back_and_forth_get();
+
+ if (ws == NULL) {
+ y(map_open);
+ ystr("success");
+ y(bool, false);
+ ystr("error");
+ ystr("No workspace was previously active.");
+ y(map_close);
+ return;
+ }
+
+ HANDLE_EMPTY_MATCH;
+
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ DLOG("matching: %p / %s\n", current->con, current->con->name);
+ con_move_to_workspace(current->con, ws, true, false);
+ }
+
+ cmd_output->needs_tree_render = true;
+ // XXX: default reply for now, make this a better reply
+ ysuccess(true);
}
/*
void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
if (strncasecmp(name, "__i3_", strlen("__i3_")) == 0) {
LOG("You cannot switch to the i3 internal workspaces.\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
owindow *current;
- /* Error out early to not create a non-existing workspace (in
- * workspace_get()) if we are not actually able to move anything. */
+ /* We have nothing to move:
+ * 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)) {
+ ELOG("No windows match your criteria, cannot move.\n");
+ ysuccess(false);
+ return;
+ }
+
if (match_is_empty(current_match) && focused->type == CT_WORKSPACE) {
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ELOG("No window to move, you have focused a workspace.\n");
+ ysuccess(false);
return;
}
/* get the workspace */
Con *ws = workspace_get(name, NULL);
+ ws = maybe_auto_back_and_forth_workspace(ws);
+
HANDLE_EMPTY_MATCH;
TAILQ_FOREACH(current, &owindows, owindows) {
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
- * Implementation of 'move [window|container] [to] workspace number <number>'.
+ * Implementation of 'move [window|container] [to] workspace number <name>'.
*
*/
void cmd_move_con_to_workspace_number(I3_CMD, char *which) {
owindow *current;
- /* Error out early to not create a non-existing workspace (in
- * workspace_get()) if we are not actually able to move anything. */
- if (match_is_empty(current_match) && focused->type == CT_WORKSPACE) {
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ /* We have nothing to move:
+ * 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)) {
+ ysuccess(false);
return;
}
- LOG("should move window to workspace with number %d\n", which);
+ LOG("should move window to workspace %s\n", which);
/* get the workspace */
Con *output, *workspace = NULL;
if (parsed_num == LONG_MIN ||
parsed_num == LONG_MAX ||
parsed_num < 0 ||
- *endptr != '\0') {
- LOG("Could not parse \"%s\" as a number.\n", which);
- cmd_output->json_output = sstrdup("{\"success\": false, "
- "\"error\": \"Could not parse number\"}");
+ endptr == which) {
+ LOG("Could not parse initial part of \"%s\" as a number.\n", which);
+ y(map_open);
+ ystr("success");
+ y(bool, false);
+ ystr("error");
+ // TODO: better error message
+ ystr("Could not parse number");
+ y(map_close);
return;
}
child->num == parsed_num);
if (!workspace) {
- cmd_output->json_output = sstrdup("{\"success\": false, "
- "\"error\": \"No such workspace\"}");
- return;
+ workspace = workspace_get(which, NULL);
}
+ workspace = maybe_auto_back_and_forth_workspace(workspace);
+
HANDLE_EMPTY_MATCH;
TAILQ_FOREACH(current, &owindows, owindows) {
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
static void cmd_resize_floating(I3_CMD, char *way, char *direction, Con *floating_con, int px) {
if (strcmp(direction, "up") == 0) {
floating_con->rect.y -= px;
floating_con->rect.height += px;
- } else if (strcmp(direction, "down") == 0) {
+ } 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;
}
}
-static void cmd_resize_tiling_direction(I3_CMD, char *way, char *direction, int ppt) {
+static bool cmd_resize_tiling_direction(I3_CMD, 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 ||
current->parent->layout == L_TABBED)
current = current->parent;
orientation_t search_orientation =
(strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0 ? HORIZ : VERT);
- while (current->type != CT_WORKSPACE &&
- current->type != CT_FLOATING_CON &&
- current->parent->orientation != search_orientation)
- current = current->parent;
+ do {
+ if (con_orientation(current->parent) != search_orientation) {
+ current = current->parent;
+ continue;
+ }
- /* get the default percentage */
- int children = con_num_children(current->parent);
- Con *other;
- LOG("ins. %d children\n", children);
- double percentage = 1.0 / children;
- LOG("default percentage = %f\n", percentage);
+ /* get the default percentage */
+ int children = con_num_children(current->parent);
+ LOG("ins. %d children\n", children);
+ percentage = 1.0 / children;
+ LOG("default percentage = %f\n", percentage);
+
+ orientation_t orientation = con_orientation(current->parent);
+
+ if ((orientation == HORIZ &&
+ (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0)) ||
+ (orientation == VERT &&
+ (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0))) {
+ LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n",
+ (orientation == HORIZ ? "horizontal" : "vertical"));
+ ysuccess(false);
+ return false;
+ }
- orientation_t orientation = current->parent->orientation;
+ if (strcmp(direction, "up") == 0 || strcmp(direction, "left") == 0) {
+ other = TAILQ_PREV(current, nodes_head, nodes);
+ } else {
+ other = TAILQ_NEXT(current, nodes);
+ }
+ if (other == TAILQ_END(workspaces)) {
+ LOG("No other container in this direction found, trying to look further up in the tree...\n");
+ current = current->parent;
+ continue;
+ }
+ break;
+ } while (current->type != CT_WORKSPACE &&
+ current->type != CT_FLOATING_CON);
- if ((orientation == HORIZ &&
- (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0)) ||
- (orientation == VERT &&
- (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0))) {
- LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n",
- (orientation == HORIZ ? "horizontal" : "vertical"));
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
- return;
+ if (other == NULL) {
+ LOG("No other container in this direction found, trying to look further up in the tree...\n");
+ ysuccess(false);
+ return false;
}
- if (strcmp(direction, "up") == 0 || strcmp(direction, "left") == 0) {
- other = TAILQ_PREV(current, nodes_head, nodes);
- } else {
- other = TAILQ_NEXT(current, nodes);
- }
- if (other == TAILQ_END(workspaces)) {
- LOG("No other container in this direction found, cannot resize.\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
- return;
- }
LOG("other->percent = %f\n", other->percent);
LOG("current->percent before = %f\n", current->percent);
if (current->percent == 0.0)
} else {
LOG("Not resizing, already at minimum size\n");
}
+
+ return true;
}
-static void cmd_resize_tiling_width_height(I3_CMD, char *way, char *direction, int ppt) {
+static bool cmd_resize_tiling_width_height(I3_CMD, 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->type != CT_WORKSPACE &&
current->type != CT_FLOATING_CON &&
- current->parent->orientation != search_orientation)
+ con_orientation(current->parent) != search_orientation)
current = current->parent;
/* get the default percentage */
double percentage = 1.0 / children;
LOG("default percentage = %f\n", percentage);
- orientation_t orientation = current->parent->orientation;
+ orientation_t orientation = con_orientation(current->parent);
if ((orientation == HORIZ &&
strcmp(direction, "height") == 0) ||
strcmp(direction, "width") == 0)) {
LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n",
(orientation == HORIZ ? "horizontal" : "vertical"));
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
- return;
+ ysuccess(false);
+ return false;
}
if (children == 1) {
LOG("This is the only container, cannot resize.\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
- return;
+ ysuccess(false);
+ return false;
}
/* Ensure all the other children have a percentage set. */
continue;
if (!definitelyGreaterThan(child->percent - subtract_percent, 0.05, DBL_EPSILON)) {
LOG("Not resizing, already at minimum size (child %p would end up with a size of %.f\n", child, child->percent - subtract_percent);
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
- return;
+ ysuccess(false);
+ return false;
}
}
if (!definitelyGreaterThan(new_current_percent, 0.05, DBL_EPSILON)) {
LOG("Not resizing, already at minimum size\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
- return;
+ ysuccess(false);
+ return false;
}
current->percent += ((double)ppt / 100.0);
child->percent -= subtract_percent;
LOG("child->percent after (%p) = %f\n", child, child->percent);
}
+
+ return true;
}
/*
cmd_resize_floating(current_match, cmd_output, way, direction, floating_con, px);
} else {
if (strcmp(direction, "width") == 0 ||
- strcmp(direction, "height") == 0)
- cmd_resize_tiling_width_height(current_match, cmd_output, way, direction, ppt);
- else cmd_resize_tiling_direction(current_match, cmd_output, way, direction, ppt);
+ strcmp(direction, "height") == 0) {
+ if (!cmd_resize_tiling_width_height(current_match, cmd_output, way, direction, ppt))
+ return;
+ } else {
+ if (!cmd_resize_tiling_direction(current_match, cmd_output, way, direction, ppt))
+ return;
+ }
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
border_style = BS_1PIXEL;
else {
ELOG("BUG: called with border_style=%s\n", border_style_str);
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
ws = workspace_prev_on_output();
else {
ELOG("BUG: called with which=%s\n", which);
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
- * Implementation of 'workspace number <number>'
+ * Implementation of 'workspace number <name>'
*
*/
void cmd_workspace_number(I3_CMD, char *which) {
if (parsed_num == LONG_MIN ||
parsed_num == LONG_MAX ||
parsed_num < 0 ||
- *endptr != '\0') {
- LOG("Could not parse \"%s\" as a number.\n", which);
- cmd_output->json_output = sstrdup("{\"success\": false, "
- "\"error\": \"Could not parse number\"}");
+ endptr == which) {
+ LOG("Could not parse initial part of \"%s\" as a number.\n", which);
+ y(map_open);
+ ystr("success");
+ y(bool, false);
+ ystr("error");
+ // TODO: better error message
+ ystr("Could not parse number");
+ y(map_close);
+
return;
}
child->num == parsed_num);
if (!workspace) {
- LOG("There is no workspace with number %d.\n", parsed_num);
- cmd_output->json_output = sstrdup("{\"success\": false, "
- "\"error\": \"No such workspace\"}");
+ LOG("There is no workspace with number %ld, creating a new one.\n", parsed_num);
+ ysuccess(true);
+ workspace_show_by_name(which);
+ cmd_output->needs_tree_render = true;
return;
}
-
+ if (maybe_back_and_forth(cmd_output, workspace->name))
+ return;
workspace_show(workspace);
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
void cmd_workspace_name(I3_CMD, char *name) {
if (strncasecmp(name, "__i3_", strlen("__i3_")) == 0) {
LOG("You cannot switch to the i3 internal workspaces.\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
DLOG("should switch to workspace %s\n", name);
-
- Con *ws = con_get_workspace(focused);
-
- /* Check if the command wants to switch to the current workspace */
- if (strcmp(ws->name, name) == 0) {
- DLOG("This workspace is already focused.\n");
- if (config.workspace_auto_back_and_forth) {
- workspace_back_and_forth();
- tree_render();
- }
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
- return;
- }
-
+ if (maybe_back_and_forth(cmd_output, name))
+ return;
workspace_show_by_name(name);
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
switch_mode(mode);
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
// 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);
+ output = get_output_next(D_UP, current_output, CLOSEST_OUTPUT);
else if (strcasecmp(name, "down") == 0)
- output = get_output_next(D_DOWN, current_output);
+ output = get_output_next(D_DOWN, current_output, CLOSEST_OUTPUT);
else if (strcasecmp(name, "left") == 0)
- output = get_output_next(D_LEFT, current_output);
+ output = get_output_next(D_LEFT, current_output, CLOSEST_OUTPUT);
else if (strcasecmp(name, "right") == 0)
- output = get_output_next(D_RIGHT, current_output);
+ output = get_output_next(D_RIGHT, current_output, CLOSEST_OUTPUT);
else
output = get_output_by_name(name);
if (!output) {
LOG("No such output found.\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
Con *ws = NULL;
GREP_FIRST(ws, output_get_content(output->con), workspace_is_visible(child));
if (!ws) {
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
TAILQ_FOREACH(current, &owindows, owindows) {
Output *current_output = get_output_containing(current->con->rect.x,
current->con->rect.y);
+ if (!current_output) {
+ ELOG("Cannot get current output. This is a bug in i3.\n");
+ ysuccess(false);
+ return;
+ }
Output *output = get_output_from_string(current_output, name);
if (!output) {
- LOG("No such output\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ELOG("Could not get output from string \"%s\"\n", name);
+ ysuccess(false);
return;
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
*
*/
void cmd_split(I3_CMD, char *direction) {
+ owindow *current;
/* TODO: use matches */
LOG("splitting in direction %c\n", direction[0]);
- tree_split(focused, (direction[0] == 'v' ? VERT : HORIZ));
+ if (match_is_empty(current_match))
+ tree_split(focused, (direction[0] == 'v' ? VERT : HORIZ));
+ else {
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ DLOG("matching: %p / %s\n", current->con, current->con->name);
+ tree_split(current->con, (direction[0] == 'v' ? VERT : HORIZ));
+ }
+ }
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
kill_mode = KILL_CLIENT;
else {
ELOG("BUG: called with kill_mode=%s\n", kill_mode_str);
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
start_application(command, no_startup_id);
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
focused->type != CT_WORKSPACE &&
focused->fullscreen_mode != CF_NONE) {
LOG("Cannot change focus while in fullscreen mode.\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
tree_next('n', VERT);
else {
ELOG("Invalid focus direction (%s)\n", direction);
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
focused->type != CT_WORKSPACE &&
focused->fullscreen_mode != CF_NONE) {
LOG("Cannot change focus while in fullscreen mode.\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
*
*/
void cmd_focus_level(I3_CMD, char *level) {
- if (focused &&
- focused->type != CT_WORKSPACE &&
- focused->fullscreen_mode != CF_NONE) {
- LOG("Cannot change focus while in fullscreen mode.\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
- return;
- }
-
DLOG("level = %s\n", level);
+ bool success = false;
+
+ /* Focusing the parent can only be allowed if the newly
+ * focused container won't escape the fullscreen container. */
+ if (strcmp(level, "parent") == 0) {
+ if (focused && focused->parent) {
+ if (con_fullscreen_permits_focusing(focused->parent))
+ success = level_up();
+ else
+ ELOG("'focus parent': Currently in fullscreen, not going up\n");
+ }
+ }
- if (strcmp(level, "parent") == 0)
- level_up();
- else level_down();
+ /* Focusing a child should always be allowed. */
+ else success = level_down();
- cmd_output->needs_tree_render = true;
+ cmd_output->needs_tree_render = success;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(success);
}
/*
*/
void cmd_focus(I3_CMD) {
DLOG("current_match = %p\n", current_match);
- if (focused &&
- focused->type != CT_WORKSPACE &&
- focused->fullscreen_mode != CF_NONE) {
- LOG("Cannot change focus while in fullscreen mode.\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
- return;
- }
-
- owindow *current;
if (match_is_empty(current_match)) {
ELOG("You have to specify which window/container should be focused.\n");
ELOG("Example: [class=\"urxvt\" title=\"irssi\"] focus\n");
- sasprintf(&(cmd_output->json_output),
- "{\"success\":false, \"error\":\"You have to "
- "specify which window/container should be focused\"}");
+ y(map_open);
+ ystr("success");
+ y(bool, false);
+ ystr("error");
+ ystr("You have to specify which window/container should be focused");
+ y(map_close);
+
return;
}
int count = 0;
+ owindow *current;
TAILQ_FOREACH(current, &owindows, owindows) {
Con *ws = con_get_workspace(current->con);
/* If no workspace could be found, this was a dock window.
if (!ws)
continue;
+ /* Check the fullscreen focus constraints. */
+ if (!con_fullscreen_permits_focusing(current->con)) {
+ LOG("Cannot change focus while in fullscreen mode (fullscreen rules).\n");
+ ysuccess(false);
+ return;
+ }
+
/* 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
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
}
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
- * Implementation of 'layout default|stacked|stacking|tabbed'.
+ * Implementation of 'layout default|stacked|stacking|tabbed|splitv|splith'.
*
*/
void cmd_layout(I3_CMD, char *layout_str) {
if (strcmp(layout_str, "stacking") == 0)
layout_str = "stacked";
- DLOG("changing layout to %s\n", layout_str);
owindow *current;
- int layout = (strcmp(layout_str, "default") == 0 ? L_DEFAULT :
- (strcmp(layout_str, "stacked") == 0 ? L_STACKED :
- L_TABBED));
+ int layout;
+ /* default is a special case which will be handled in con_set_layout(). */
+ if (strcmp(layout_str, "default") == 0)
+ layout = L_DEFAULT;
+ else if (strcmp(layout_str, "stacked") == 0)
+ layout = L_STACKED;
+ else if (strcmp(layout_str, "tabbed") == 0)
+ layout = L_TABBED;
+ else if (strcmp(layout_str, "splitv") == 0)
+ layout = L_SPLITV;
+ else if (strcmp(layout_str, "splith") == 0)
+ layout = L_SPLITH;
+ else {
+ ELOG("Unknown layout \"%s\", this is a mismatch between code and parser spec.\n", layout_str);
+ return;
+ }
+
+ DLOG("changing layout to %s (%d)\n", layout_str, layout);
/* check if the match is empty, not if the result is empty */
if (match_is_empty(current_match))
- con_set_layout(focused->parent, layout);
+ con_set_layout(focused, layout);
else {
TAILQ_FOREACH(current, &owindows, owindows) {
DLOG("matching: %p / %s\n", current->con, current->con->name);
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
+}
+
+/*
+ * Implementation of 'layout toggle [all|split]'.
+ *
+ */
+void cmd_layout_toggle(I3_CMD, char *toggle_mode) {
+ owindow *current;
+
+ if (toggle_mode == NULL)
+ toggle_mode = "default";
+
+ DLOG("toggling layout (mode = %s)\n", toggle_mode);
+
+ /* check if the match is empty, not if the result is empty */
+ if (match_is_empty(current_match))
+ con_toggle_layout(focused, toggle_mode);
+ else {
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ DLOG("matching: %p / %s\n", current->con, current->con->name);
+ con_toggle_layout(current->con, toggle_mode);
+ }
+ }
+
+ cmd_output->needs_tree_render = true;
+ // XXX: default reply for now, make this a better reply
+ ysuccess(true);
}
/*
*/
void cmd_exit(I3_CMD) {
LOG("Exiting due to user command.\n");
+ xcb_disconnect(conn);
exit(0);
/* unreached */
void cmd_reload(I3_CMD) {
LOG("reloading\n");
kill_configerror_nagbar(false);
+ kill_commanderror_nagbar(false);
load_configuration(conn, NULL, true);
x_set_i3_atoms();
/* Send an IPC event just in case the ws names have changed */
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"reload\"}");
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
i3_restart(false);
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
void cmd_open(I3_CMD) {
LOG("opening new container\n");
Con *con = tree_open_con(NULL, NULL);
+ con->layout = L_SPLITH;
con_focus(con);
- sasprintf(&(cmd_output->json_output),
- "{\"success\":true, \"id\":%ld}", (long int)con);
+
+ y(map_open);
+ ystr("success");
+ y(bool, true);
+ ystr("id");
+ y(integer, (long int)con);
+ y(map_close);
cmd_output->needs_tree_render = true;
}
if (!output) {
LOG("No such output found.\n");
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
Con *ws = NULL;
GREP_FIRST(ws, output_get_content(output->con), workspace_is_visible(child));
if (!ws) {
- cmd_output->json_output = sstrdup("{\"sucess\": false}");
+ ysuccess(false);
return;
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
if (!con_is_floating(focused)) {
ELOG("Cannot change position. The window/container is not floating\n");
- sasprintf(&(cmd_output->json_output),
- "{\"success\":false, \"error\":\"Cannot change position. "
- "The window/container is not floating.\"}");
+ y(map_open);
+ ystr("success");
+ y(bool, false);
+ ystr("error");
+ ystr("Cannot change position. The window/container is not floating.");
+ y(map_close);
return;
}
}
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
if (!con_is_floating(focused)) {
ELOG("Cannot change position. The window/container is not floating\n");
- sasprintf(&(cmd_output->json_output),
- "{\"success\":false, \"error\":\"Cannot change position. "
- "The window/container is not floating.\"}");
+ y(map_open);
+ ystr("success");
+ y(bool, false);
+ ystr("error");
+ ystr("Cannot change position. The window/container is not floating.");
+ y(map_close);
}
if (strcmp(method, "absolute") == 0) {
}
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
}
/*
if (!workspace) {
// TODO: we should include the old workspace name here and use yajl for
// generating the reply.
- cmd_output->json_output = sstrdup("{\"success\": false, "
- "\"error\":\"Old workspace not found\"}");
+ y(map_open);
+ ystr("success");
+ y(bool, false);
+ ystr("error");
+ // TODO: better error message
+ ystr("Old workspace not found");
+ y(map_close);
return;
}
if (check_dest != NULL) {
// TODO: we should include the new workspace name here and use yajl for
// generating the reply.
- cmd_output->json_output = sstrdup("{\"success\": false, "
- "\"error\":\"New workspace already exists\"}");
+ y(map_open);
+ ystr("success");
+ y(bool, false);
+ ystr("error");
+ // TODO: better error message
+ ystr("New workspace already exists");
+ y(map_close);
return;
}
con_focus(previously_focused);
cmd_output->needs_tree_render = true;
- cmd_output->json_output = sstrdup("{\"success\": true}");
+ ysuccess(true);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"rename\"}");
}