X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcommands.c;h=79071d6bb5f451dbae214fcb6fd2a53dbde7813f;hb=edda9306ed6ea940a4310b1b606e3b5e866741f1;hp=d3e2a6e3da59630c4b971b80eba04ef8cf082754;hpb=44f748a663fc0ae96b2a750a804cf470dcad1675;p=i3%2Fi3 diff --git a/src/commands.c b/src/commands.c index d3e2a6e3..79071d6b 100644 --- a/src/commands.c +++ b/src/commands.c @@ -65,28 +65,6 @@ static bool definitelyGreaterThan(float a, float b, float epsilon) { return (a - b) > ((fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon); } -/* - * Returns an 'output' corresponding to one of left/right/down/up or a specific - * output name. - * - */ -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_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; -} - /* * Returns the output containing the given container. */ @@ -516,27 +494,7 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) { LOG("should move window to workspace %s\n", name); /* get the workspace */ - Con *ws = NULL; - Con *output = NULL; - - /* first look for a workspace with this name */ - TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { - GREP_FIRST(ws, output_get_content(output), !strcasecmp(child->name, name)); - } - - /* if the name is plain digits, we interpret this as a "workspace number" - * command */ - if (!ws && name_is_digits(name)) { - long parsed_num = ws_name_to_number(name); - TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { - GREP_FIRST(ws, output_get_content(output), - child->num == parsed_num); - } - } - - /* if no workspace was found, make a new one */ - if (!ws) - ws = workspace_get(name, NULL); + Con *ws = workspace_get(name, NULL); ws = maybe_auto_back_and_forth_workspace(ws); @@ -1071,30 +1029,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; - - Con *ws = NULL; - Con *output = NULL; - - /* first look for a workspace with this name */ - TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { - GREP_FIRST(ws, output_get_content(output), !strcasecmp(child->name, name)); - } - - /* if the name is only digits, we interpret this as a "workspace number" - * command */ - if (!ws && name_is_digits(name)) { - long parsed_num = ws_name_to_number(name); - TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { - GREP_FIRST(ws, output_get_content(output), - child->num == parsed_num); - } - } - - /* if no workspace was found, make a new one */ - if (!ws) - ws = workspace_get(name, NULL); - - workspace_show(ws); + workspace_show_by_name(name); cmd_output->needs_tree_render = true; // XXX: default reply for now, make this a better reply @@ -1102,28 +1037,48 @@ void cmd_workspace_name(I3_CMD, char *name) { } /* - * Implementation of 'mark ' + * Implementation of 'mark [--toggle] ' * */ -void cmd_mark(I3_CMD, char *mark) { - DLOG("Clearing all windows which have that mark first\n"); +void cmd_mark(I3_CMD, char *mark, char *toggle) { + HANDLE_EMPTY_MATCH; - Con *con; - TAILQ_FOREACH(con, &all_cons, all_cons) { - if (con->mark && strcmp(con->mark, mark) == 0) - FREE(con->mark); + owindow *current = TAILQ_FIRST(&owindows); + if (current == NULL) { + ysuccess(false); + return; } - DLOG("marking window with str %s\n", mark); - owindow *current; - - HANDLE_EMPTY_MATCH; + /* Marks must be unique, i.e., no two windows must have the same mark. */ + if (current != TAILQ_LAST(&owindows, owindows_head)) { + yerror("A mark must not be put onto more than one window"); + return; + } - TAILQ_FOREACH(current, &owindows, owindows) { - DLOG("matching: %p / %s\n", current->con, current->con->name); + DLOG("matching: %p / %s\n", current->con, current->con->name); + current->con->mark_changed = true; + if (toggle != NULL && current->con->mark && strcmp(current->con->mark, mark) == 0) { + DLOG("removing window mark %s\n", mark); + FREE(current->con->mark); + } else { + DLOG("marking window with str %s\n", mark); + FREE(current->con->mark); current->con->mark = sstrdup(mark); } + DLOG("Clearing all non-matched windows with this mark\n"); + Con *con; + TAILQ_FOREACH(con, &all_cons, all_cons) { + /* Skip matched window, we took care of it already. */ + if (current->con == con) + continue; + + if (con->mark && strcmp(con->mark, mark) == 0) { + FREE(con->mark); + con->mark_changed = true; + } + } + cmd_output->needs_tree_render = true; // XXX: default reply for now, make this a better reply ysuccess(true); @@ -1137,14 +1092,20 @@ void cmd_unmark(I3_CMD, char *mark) { if (mark == NULL) { Con *con; TAILQ_FOREACH(con, &all_cons, all_cons) { + if (con->mark == NULL) + continue; + FREE(con->mark); + con->mark_changed = true; } DLOG("removed all window marks"); } else { Con *con; TAILQ_FOREACH(con, &all_cons, all_cons) { - if (con->mark && strcmp(con->mark, mark) == 0) + if (con->mark && strcmp(con->mark, mark) == 0) { FREE(con->mark); + con->mark_changed = true; + } } DLOG("removed window mark %s\n", mark); } @@ -1177,28 +1138,13 @@ void cmd_move_con_to_output(I3_CMD, char *name) { HANDLE_EMPTY_MATCH; - /* get the output */ Output *current_output = NULL; - Output *output; - // TODO: fix the handling of criteria TAILQ_FOREACH(current, &owindows, owindows) current_output = get_output_of_con(current->con); - assert(current_output != NULL); - // 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_wrap(D_UP, current_output); - else if (strcasecmp(name, "down") == 0) - output = get_output_next_wrap(D_DOWN, current_output); - else if (strcasecmp(name, "left") == 0) - output = get_output_next_wrap(D_LEFT, current_output); - else if (strcasecmp(name, "right") == 0) - output = get_output_next_wrap(D_RIGHT, current_output); - else - output = get_output_by_name(name); - + Output *output = get_output_from_string(current_output, name); if (!output) { LOG("No such output found.\n"); ysuccess(false); @@ -1265,102 +1211,13 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) { owindow *current; TAILQ_FOREACH(current, &owindows, owindows) { - Output *current_output = get_output_of_con(current->con); - 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) { - ELOG("Could not get output from string \"%s\"\n", name); + Con *ws = con_get_workspace(current->con); + bool success = workspace_move_to_output(ws, name); + if (!success) { + ELOG("Failed to move workspace to output.\n"); ysuccess(false); return; } - - Con *content = output_get_content(output->con); - LOG("got output %p with content %p\n", output, content); - - Con *previously_visible_ws = TAILQ_FIRST(&(content->nodes_head)); - LOG("Previously visible workspace = %p / %s\n", previously_visible_ws, previously_visible_ws->name); - - Con *ws = con_get_workspace(current->con); - LOG("should move workspace %p / %s\n", ws, ws->name); - bool workspace_was_visible = workspace_is_visible(ws); - - if (con_num_children(ws->parent) == 1) { - LOG("Creating a new workspace to replace \"%s\" (last on its output).\n", ws->name); - - /* check if we can find a workspace assigned to this output */ - bool used_assignment = false; - struct Workspace_Assignment *assignment; - TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) { - if (strcmp(assignment->output, current_output->name) != 0) - continue; - - /* 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)); - if (workspace != NULL) - continue; - - /* so create the workspace referenced to by this assignment */ - LOG("Creating workspace from assignment %s.\n", assignment->name); - workspace_get(assignment->name, NULL); - used_assignment = true; - break; - } - - /* if we couldn't create the workspace using an assignment, create - * it on the output */ - if (!used_assignment) - create_workspace_on_output(current_output, ws->parent); - - /* notify the IPC listeners */ - ipc_send_workspace_event("init", ws, NULL); - } - DLOG("Detaching\n"); - - /* detach from the old output and attach to the new output */ - Con *old_content = ws->parent; - con_detach(ws); - if (workspace_was_visible) { - /* The workspace which we just detached was visible, so focus - * the next one in the focus-stack. */ - Con *focus_ws = TAILQ_FIRST(&(old_content->focus_head)); - LOG("workspace was visible, focusing %p / %s now\n", focus_ws, focus_ws->name); - workspace_show(focus_ws); - } - con_attach(ws, content, false); - - /* 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)); - - ipc_send_workspace_event("move", ws, NULL); - if (workspace_was_visible) { - /* Focus the moved workspace on the destination output. */ - workspace_show(ws); - } - - /* 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; @@ -1915,25 +1772,18 @@ void cmd_move_window_to_center(I3_CMD, char *method) { } if (strcmp(method, "absolute") == 0) { - 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; + floating_center(focused->parent, croot->rect); floating_maybe_reassign_ws(focused->parent); cmd_output->needs_tree_render = true; } if (strcmp(method, "position") == 0) { - Rect *wsrect = &con_get_workspace(focused)->rect; - 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; + floating_center(focused->parent, con_get_workspace(focused)->rect); - floating_reposition(focused->parent, newrect); + cmd_output->needs_tree_render = true; } // XXX: default reply for now, make this a better reply @@ -2005,6 +1855,7 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) { !strcasecmp(child->name, old_name)); } else { workspace = con_get_workspace(focused); + old_name = workspace->name; } if (!workspace) { @@ -2034,6 +1885,24 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) { Con *parent = workspace->parent; con_detach(workspace); con_attach(workspace, parent, false); + + /* Move the workspace to the correct output if it has an assignment */ + struct Workspace_Assignment *assignment = NULL; + TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) { + if (assignment->output == NULL) + continue; + if (strcmp(assignment->name, workspace->name) != 0 && (!name_is_digits(assignment->name) || ws_name_to_number(assignment->name) != workspace->num)) { + continue; + } + + workspace_move_to_output(workspace, assignment->output); + + if (previously_focused) + workspace_show(con_get_workspace(previously_focused)); + + break; + } + /* Restore the previous focus since con_attach messes with the focus. */ con_focus(previously_focused);