From eb73059c610752fc18e0fcc5c5402bb9b7770574 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ingo=20B=C3=BCrk?= Date: Wed, 4 Mar 2015 09:22:25 +0100 Subject: [PATCH] Refactor functions for easy reuse --- include/output.h | 7 +++ include/workspace.h | 7 +++ src/commands.c | 123 ++------------------------------------------ src/output.c | 22 ++++++++ src/workspace.c | 108 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 149 insertions(+), 118 deletions(-) diff --git a/include/output.h b/include/output.h index 10ee7d17..6514c477 100644 --- a/include/output.h +++ b/include/output.h @@ -14,3 +14,10 @@ * */ Con *output_get_content(Con *output); + +/** + * Returns an 'output' corresponding to one of left/right/down/up or a specific + * output name. + * + */ +Output *get_output_from_string(Output *current_output, const char *output_str); diff --git a/include/workspace.h b/include/workspace.h index 9ee6f156..d0f801e0 100644 --- a/include/workspace.h +++ b/include/workspace.h @@ -179,3 +179,10 @@ Con *workspace_attach_to(Con *ws); * The container inherits the layout from the workspace. */ Con *workspace_encapsulate(Con *ws); + +/** + * Move the given workspace to the specified output. + * This returns true if and only if moving the workspace was successful. + * + */ +bool workspace_move_to_output(Con *ws, char *output); diff --git a/src/commands.c b/src/commands.c index 7d3c9e6e..49005ba7 100644 --- a/src/commands.c +++ b/src/commands.c @@ -62,28 +62,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. */ @@ -1259,102 +1237,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; @@ -2046,9 +1935,7 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) { continue; } - /* Focus this workspace for now, we will restore the previous focus anyway. */ - con_focus(workspace); - cmd_move_workspace_to_output(current_match, cmd_output, assignment->output); + workspace_move_to_output(workspace, assignment->output); break; } diff --git a/src/output.c b/src/output.c index 6499c65d..822a0f88 100644 --- a/src/output.c +++ b/src/output.c @@ -24,3 +24,25 @@ Con *output_get_content(Con *output) { return NULL; } + +/* + * Returns an 'output' corresponding to one of left/right/down/up or a specific + * output name. + * + */ +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; +} diff --git a/src/workspace.c b/src/workspace.c index a3056633..f55c920e 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -879,3 +879,111 @@ Con *workspace_encapsulate(Con *ws) { return new; } + +/** + * Move the given workspace to the specified output. + * This returns true if and only if moving the workspace was successful. + */ +bool workspace_move_to_output(Con *ws, char *name) { + LOG("Trying to move workspace %p / %s to output \"%s\".\n", ws, ws->name, name); + + Con *current_output_con = con_get_output(ws); + if (!current_output_con) { + ELOG("Could not get the output container for workspace %p / %s.\n", ws, ws->name); + return false; + } + + Output *current_output = get_output_by_name(current_output_con->name); + if (!current_output) { + ELOG("Cannot get current output. This is a bug in i3.\n"); + return false; + } + Output *output = get_output_from_string(current_output, name); + if (!output) { + ELOG("Could not get output from string \"%s\"\n", name); + return false; + } + + 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); + + 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 (assignment->output == NULL || 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; + } + + return true; +} -- 2.39.5