X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcommands.c;h=baf19893b02c7d69fd70c5f4f12f1dbe8bb850f7;hb=c2b6b06da7db49bd3ecd6fa1561ef2b407ff64a3;hp=801c93063a0346932b080cf888bbbc5f8ac9cbcb;hpb=617afc67a25c9bb7bf91a7659319e07fbe32d758;p=i3%2Fi3 diff --git a/src/commands.c b/src/commands.c index 801c9306..baf19893 100644 --- a/src/commands.c +++ b/src/commands.c @@ -16,48 +16,50 @@ #include "shmlog.h" // Macros to make the YAJL API a bit easier to use. -#define y(x, ...) (cmd_output->json_gen != NULL ? yajl_gen_ ## x (cmd_output->json_gen, ##__VA_ARGS__) : 0) -#define ystr(str) (cmd_output->json_gen != NULL ? yajl_gen_string(cmd_output->json_gen, (unsigned char*)str, strlen(str)) : 0) -#define ysuccess(success) do { \ - if (cmd_output->json_gen != NULL) { \ - y(map_open); \ - ystr("success"); \ - y(bool, success); \ - y(map_close); \ - } \ -} while (0) -#define yerror(message) do { \ - if (cmd_output->json_gen != NULL) { \ - y(map_open); \ - ystr("success"); \ - y(bool, false); \ - ystr("error"); \ - ystr(message); \ - y(map_close); \ - } \ -} while (0) +#define y(x, ...) (cmd_output->json_gen != NULL ? yajl_gen_##x(cmd_output->json_gen, ##__VA_ARGS__) : 0) +#define ystr(str) (cmd_output->json_gen != NULL ? yajl_gen_string(cmd_output->json_gen, (unsigned char *)str, strlen(str)) : 0) +#define ysuccess(success) \ + do { \ + if (cmd_output->json_gen != NULL) { \ + y(map_open); \ + ystr("success"); \ + y(bool, success); \ + y(map_close); \ + } \ + } while (0) +#define yerror(message) \ + do { \ + if (cmd_output->json_gen != NULL) { \ + y(map_open); \ + ystr("success"); \ + y(bool, false); \ + ystr("error"); \ + ystr(message); \ + y(map_close); \ + } \ + } while (0) /** When the command did not include match criteria (!), we use the currently * 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. */ -#define HANDLE_EMPTY_MATCH do { \ - if (match_is_empty(current_match)) { \ - owindow *ow = smalloc(sizeof(owindow)); \ - ow->con = focused; \ - TAILQ_INIT(&owindows); \ - TAILQ_INSERT_TAIL(&owindows, ow, owindows); \ - } \ -} while (0) - +#define HANDLE_EMPTY_MATCH \ + do { \ + if (match_is_empty(current_match)) { \ + owindow *ow = smalloc(sizeof(owindow)); \ + ow->con = focused; \ + TAILQ_INIT(&owindows); \ + TAILQ_INSERT_TAIL(&owindows, ow, owindows); \ + } \ + } while (0) /* * Returns true if a is definitely greater than b (using the given epsilon) * */ static bool definitelyGreaterThan(float a, float b, float epsilon) { - return (a - b) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon); + return (a - b) > ((fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon); } /* @@ -76,7 +78,8 @@ static Output *get_output_from_string(Output *current_output, const char *output 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); + else + output = get_output_by_name(output_str); return output; } @@ -358,7 +361,7 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) { (end && *end != '\0')) { ELOG("Could not parse con id \"%s\"\n", cvalue); } else { - current_match->con_id = (Con*)parsed; + current_match->con_id = (Con *)parsed; DLOG("id as int = %p\n", current_match->con_id); } return; @@ -420,7 +423,7 @@ void cmd_move_con_to_workspace(I3_CMD, char *which) { * 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 && - !con_has_children(focused))) { + !con_has_children(focused))) { ysuccess(false); return; } @@ -502,9 +505,8 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) { ELOG("No windows match your criteria, cannot move.\n"); ysuccess(false); return; - } - else if (match_is_empty(current_match) && focused->type == CT_WORKSPACE && - !con_has_children(focused)) { + } else if (match_is_empty(current_match) && focused->type == CT_WORKSPACE && + !con_has_children(focused)) { ysuccess(false); return; } @@ -539,7 +541,7 @@ void cmd_move_con_to_workspace_number(I3_CMD, char *which) { * 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 && - !con_has_children(focused))) { + !con_has_children(focused))) { ysuccess(false); return; } @@ -548,12 +550,9 @@ void cmd_move_con_to_workspace_number(I3_CMD, char *which) { /* get the workspace */ Con *output, *workspace = NULL; - char *endptr = NULL; - long parsed_num = strtol(which, &endptr, 10); - if (parsed_num == LONG_MIN || - parsed_num == LONG_MAX || - parsed_num < 0 || - endptr == which) { + long parsed_num = ws_name_to_number(which); + + if (parsed_num == -1) { LOG("Could not parse initial part of \"%s\" as a number.\n", which); // TODO: better error message yerror("Could not parse number"); @@ -561,8 +560,8 @@ void cmd_move_con_to_workspace_number(I3_CMD, char *which) { } TAILQ_FOREACH(output, &(croot->nodes_head), nodes) - GREP_FIRST(workspace, output_get_content(output), - child->num == parsed_num); + GREP_FIRST(workspace, output_get_content(output), + child->num == parsed_num); if (!workspace) { workspace = workspace_get(which, NULL); @@ -815,7 +814,7 @@ void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resiz * Implementation of 'border normal|none|1pixel|toggle|pixel'. * */ -void cmd_border(I3_CMD, char *border_style_str, char *border_width ) { +void cmd_border(I3_CMD, char *border_style_str, char *border_width) { DLOG("border style should be changed to %s with border width %s\n", border_style_str, border_width); owindow *current; @@ -845,7 +844,7 @@ void cmd_border(I3_CMD, char *border_style_str, char *border_width ) { border_style = BS_NORMAL; else if (strcmp(border_style_str, "pixel") == 0) border_style = BS_PIXEL; - else if (strcmp(border_style_str, "1pixel") == 0){ + else if (strcmp(border_style_str, "1pixel") == 0) { border_style = BS_PIXEL; tmp_border_width = 1; } else if (strcmp(border_style_str, "none") == 0) @@ -952,22 +951,18 @@ void cmd_workspace(I3_CMD, char *which) { void cmd_workspace_number(I3_CMD, char *which) { Con *output, *workspace = NULL; - char *endptr = NULL; - long parsed_num = strtol(which, &endptr, 10); - if (parsed_num == LONG_MIN || - parsed_num == LONG_MAX || - parsed_num < 0 || - endptr == which) { + long parsed_num = ws_name_to_number(which); + + if (parsed_num == -1) { LOG("Could not parse initial part of \"%s\" as a number.\n", which); // TODO: better error message yerror("Could not parse number"); - return; } TAILQ_FOREACH(output, &(croot->nodes_head), nodes) - GREP_FIRST(workspace, output_get_content(output), - child->num == parsed_num); + GREP_FIRST(workspace, output_get_content(output), + child->num == parsed_num); if (!workspace) { LOG("There is no workspace with number %ld, creating a new one.\n", parsed_num); @@ -1010,7 +1005,7 @@ void cmd_workspace_name(I3_CMD, char *name) { DLOG("should switch to workspace %s\n", name); if (maybe_back_and_forth(cmd_output, name)) - return; + return; workspace_show_by_name(name); cmd_output->needs_tree_render = true; @@ -1051,19 +1046,19 @@ void cmd_mark(I3_CMD, char *mark) { * */ void cmd_unmark(I3_CMD, char *mark) { - if (mark == NULL) { - Con *con; - TAILQ_FOREACH(con, &all_cons, all_cons) { - FREE(con->mark); - } - DLOG("removed all window marks"); - } else { - Con *con; - TAILQ_FOREACH(con, &all_cons, all_cons) { - if (con->mark && strcmp(con->mark, mark) == 0) - FREE(con->mark); - } - DLOG("removed window mark %s\n", mark); + if (mark == NULL) { + Con *con; + TAILQ_FOREACH(con, &all_cons, all_cons) { + FREE(con->mark); + } + DLOG("removed all window marks"); + } else { + Con *con; + TAILQ_FOREACH(con, &all_cons, all_cons) { + if (con->mark && strcmp(con->mark, mark) == 0) + FREE(con->mark); + } + DLOG("removed window mark %s\n", mark); } cmd_output->needs_tree_render = true; @@ -1100,7 +1095,7 @@ void cmd_move_con_to_output(I3_CMD, char *name) { // TODO: fix the handling of criteria TAILQ_FOREACH(current, &owindows, owindows) - current_output = get_output_of_con(current->con); + current_output = get_output_of_con(current->con); assert(current_output != NULL); @@ -1218,8 +1213,8 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) { /* check if this workspace is already attached to the tree */ Con *workspace = NULL, *out; TAILQ_FOREACH(out, &(croot->nodes_head), nodes) - GREP_FIRST(workspace, output_get_content(out), - !strcasecmp(child->name, assignment->name)); + GREP_FIRST(workspace, output_get_content(out), + !strcasecmp(child->name, assignment->name)); if (workspace != NULL) continue; @@ -1255,7 +1250,7 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) { /* fix the coordinates of the floating containers */ Con *floating_con; TAILQ_FOREACH(floating_con, &(ws->floating_head), floating_windows) - floating_fix_coordinates(floating_con, &(old_content->rect), &(content->rect)); + floating_fix_coordinates(floating_con, &(old_content->rect), &(content->rect)); ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"move\"}"); if (workspace_was_visible) { @@ -1398,7 +1393,8 @@ void cmd_focus_window_mode(I3_CMD, char *window_mode) { current = TAILQ_FIRST(&(ws->focus_head)); if (current != NULL && current->type == CT_FLOATING_CON) window_mode = "tiling"; - else window_mode = "floating"; + else + window_mode = "floating"; } TAILQ_FOREACH(current, &(ws->focus_head), focused) { if ((strcmp(window_mode, "floating") == 0 && current->type != CT_FLOATING_CON) || @@ -1435,7 +1431,8 @@ void cmd_focus_level(I3_CMD, char *level) { } /* Focusing a child should always be allowed. */ - else success = level_down(); + else + success = level_down(); cmd_output->needs_tree_render = success; // XXX: default reply for now, make this a better reply @@ -1510,7 +1507,8 @@ void cmd_focus(I3_CMD) { if (count > 1) LOG("WARNING: Your criteria for the focus command matches %d containers, " - "while only exactly one container can be focused at a time.\n", count); + "while only exactly one container can be focused at a time.\n", + count); cmd_output->needs_tree_render = true; // XXX: default reply for now, make this a better reply @@ -1547,29 +1545,36 @@ void cmd_move_direction(I3_CMD, char *direction, char *move_px) { // TODO: We could either handle this in the parser itself as a separate token (and make the stack typed) or we need a better way to convert a string to a number with error checking int px = atoi(move_px); - /* TODO: make 'move' work with criteria. */ - DLOG("moving in direction %s, px %s\n", direction, move_px); - if (con_is_floating(focused)) { - DLOG("floating move with %d pixels\n", px); - Rect newrect = focused->parent->rect; - if (strcmp(direction, "left") == 0) { - newrect.x -= px; - } else if (strcmp(direction, "right") == 0) { - newrect.x += px; - } else if (strcmp(direction, "up") == 0) { - newrect.y -= px; - } else if (strcmp(direction, "down") == 0) { - newrect.y += px; + owindow *current; + HANDLE_EMPTY_MATCH; + + Con *initially_focused = focused; + + TAILQ_FOREACH (current, &owindows, owindows) { + DLOG("moving in direction %s, px %s\n", direction, move_px); + if (con_is_floating(current->con)) { + DLOG("floating move with %d pixels\n", px); + Rect newrect = current->con->parent->rect; + if (strcmp(direction, "left") == 0) { + newrect.x -= px; + } else if (strcmp(direction, "right") == 0) { + newrect.x += px; + } else if (strcmp(direction, "up") == 0) { + newrect.y -= px; + } else if (strcmp(direction, "down") == 0) { + newrect.y += px; + } + floating_reposition(current->con->parent, newrect); + } else { + tree_move(current->con, (strcmp(direction, "right") == 0 ? D_RIGHT : (strcmp(direction, "left") == 0 ? D_LEFT : (strcmp(direction, "up") == 0 ? D_UP : D_DOWN)))); + cmd_output->needs_tree_render = true; } - floating_reposition(focused->parent, newrect); - } else { - tree_move((strcmp(direction, "right") == 0 ? D_RIGHT : - (strcmp(direction, "left") == 0 ? D_LEFT : - (strcmp(direction, "up") == 0 ? D_UP : - D_DOWN)))); - cmd_output->needs_tree_render = true; } + /* the move command should not disturb focus */ + if (focused != initially_focused) + con_focus(initially_focused); + // XXX: default reply for now, make this a better reply ysuccess(true); } @@ -1649,6 +1654,8 @@ void cmd_layout_toggle(I3_CMD, char *toggle_mode) { */ void cmd_exit(I3_CMD) { LOG("Exiting due to user command.\n"); + ipc_shutdown(); + unlink(config.ipc_socket_path); xcb_disconnect(conn); exit(0); @@ -1680,6 +1687,14 @@ void cmd_reload(I3_CMD) { */ void cmd_restart(I3_CMD) { LOG("restarting i3\n"); + ipc_shutdown(); + /* We need to call this manually since atexit handlers don’t get called + * when exec()ing */ + purge_zerobyte_logfile(); + /* The unlink call is intentionally after the purge_zerobyte_logfile() so + * that the latter does not remove the directory yet. We need to store the + * restart layout state in there. */ + unlink(config.ipc_socket_path); i3_restart(false); // XXX: default reply for now, make this a better reply @@ -1722,7 +1737,7 @@ void cmd_focus_output(I3_CMD, char *name) { Output *output; TAILQ_FOREACH(current, &owindows, owindows) - current_output = get_output_of_con(current->con); + current_output = get_output_of_con(current->con); assert(current_output != NULL); output = get_output_from_string(current_output, name); @@ -1753,7 +1768,6 @@ void cmd_focus_output(I3_CMD, char *name) { * */ void cmd_move_window_to_position(I3_CMD, char *method, char *cx, char *cy) { - int x = atoi(cx); int y = atoi(cy); @@ -1791,7 +1805,6 @@ void cmd_move_window_to_position(I3_CMD, char *method, char *cx, char *cy) { * */ void cmd_move_window_to_center(I3_CMD, char *method) { - if (!con_is_floating(focused)) { ELOG("Cannot change position. The window/container is not floating\n"); yerror("Cannot change position. The window/container is not floating."); @@ -1802,8 +1815,8 @@ void cmd_move_window_to_center(I3_CMD, char *method) { Rect *rect = &focused->parent->rect; DLOG("moving to absolute center\n"); - rect->x = croot->rect.width/2 - rect->width/2; - rect->y = croot->rect.height/2 - rect->height/2; + rect->x = croot->rect.width / 2 - rect->width / 2; + rect->y = croot->rect.height / 2 - rect->height / 2; floating_maybe_reassign_ws(focused->parent); cmd_output->needs_tree_render = true; @@ -1814,8 +1827,8 @@ void cmd_move_window_to_center(I3_CMD, char *method) { Rect newrect = focused->parent->rect; DLOG("moving to center\n"); - newrect.x = wsrect->width/2 - newrect.width/2; - newrect.y = wsrect->height/2 - newrect.height/2; + newrect.x = wsrect->width / 2 - newrect.width / 2; + newrect.y = wsrect->height / 2 - newrect.height / 2; floating_reposition(focused->parent, newrect); } @@ -1885,8 +1898,8 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) { Con *output, *workspace = NULL; if (old_name) { TAILQ_FOREACH(output, &(croot->nodes_head), nodes) - GREP_FIRST(workspace, output_get_content(output), - !strcasecmp(child->name, old_name)); + GREP_FIRST(workspace, output_get_content(output), + !strcasecmp(child->name, old_name)); } else { workspace = con_get_workspace(focused); } @@ -1901,8 +1914,8 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) { Con *check_dest = NULL; TAILQ_FOREACH(output, &(croot->nodes_head), nodes) - GREP_FIRST(check_dest, output_get_content(output), - !strcasecmp(child->name, new_name)); + GREP_FIRST(check_dest, output_get_content(output), + !strcasecmp(child->name, new_name)); if (check_dest != NULL) { // TODO: we should include the new workspace name here and use yajl for @@ -1915,14 +1928,8 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) { /* Change the name and try to parse it as a number. */ FREE(workspace->name); workspace->name = sstrdup(new_name); - char *endptr = NULL; - long parsed_num = strtol(new_name, &endptr, 10); - if (parsed_num == LONG_MIN || - parsed_num == LONG_MAX || - parsed_num < 0 || - endptr == new_name) - workspace->num = -1; - else workspace->num = parsed_num; + + workspace->num = ws_name_to_number(new_name); LOG("num = %d\n", workspace->num); /* By re-attaching, the sort order will be correct afterwards. */ @@ -1973,7 +1980,7 @@ bool cmd_bar_mode(char *bar_mode, char *bar_id) { changed_sth = true; if (bar_id) - break; + break; } if (bar_id && !changed_sth) { @@ -2016,7 +2023,7 @@ bool cmd_bar_hidden_state(char *bar_hidden_state, char *bar_id) { changed_sth = true; if (bar_id) - break; + break; } if (bar_id && !changed_sth) { @@ -2054,7 +2061,7 @@ void cmd_bar(I3_CMD, char *bar_type, char *bar_value, char *bar_id) { * */ void cmd_shmlog(I3_CMD, char *argument) { - if (!strcmp(argument,"toggle")) + if (!strcmp(argument, "toggle")) /* Toggle shm log, if size is not 0. If it is 0, set it to default. */ shmlog_size = shmlog_size ? -shmlog_size : default_shmlog_size; else if (!strcmp(argument, "on")) @@ -2086,7 +2093,7 @@ void cmd_shmlog(I3_CMD, char *argument) { */ void cmd_debuglog(I3_CMD, char *argument) { bool logging = get_debug_logging(); - if (!strcmp(argument,"toggle")) { + if (!strcmp(argument, "toggle")) { LOG("%s debug logging\n", logging ? "Disabling" : "Enabling"); set_debug_logging(!logging); } else if (!strcmp(argument, "on") && !logging) {