From: Fernando Tarlá Cardoso Lemos Date: Sat, 14 Jan 2012 22:09:09 +0000 (-0200) Subject: If moving the last ws, create a new one in its place. X-Git-Tag: 4.2~77 X-Git-Url: https://git.sur5r.net/?p=i3%2Fi3;a=commitdiff_plain;h=a22f161ab5ed129b2e4e613aa5a9bf700df366a6 If moving the last ws, create a new one in its place. This seems better than refusing to move the last workspace. --- diff --git a/include/workspace.h b/include/workspace.h index 21b733a6..8e682bb0 100644 --- a/include/workspace.h +++ b/include/workspace.h @@ -26,6 +26,14 @@ */ Con *workspace_get(const char *num, bool *created); +/* + * Returns a pointer to a new workspace in the given output. The workspace + * is created attached to the tree hierarchy through the given content + * container. + * + */ +Con *create_workspace_on_output(Output *output, Con *content); + #if 0 /** * Sets the name (or just its number) for the given workspace. This has to diff --git a/src/commands.c b/src/commands.c index 80be16cf..f570d6d8 100644 --- a/src/commands.c +++ b/src/commands.c @@ -787,10 +787,41 @@ char *cmd_move_workspace_to_output(Match *current_match, char *name) { Con *ws = con_get_workspace(current->con); LOG("should move workspace %p / %s\n", ws, ws->name); + if (con_num_children(ws->parent) == 1) { - LOG("Not moving workspace \"%s\", it is the only workspace on its output.\n", ws->name); - continue; + 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_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}"); } + bool workspace_was_visible = workspace_is_visible(ws); Con *old_content = ws->parent; con_detach(ws); diff --git a/src/randr.c b/src/randr.c index 1c01fdd5..85f0eab3 100644 --- a/src/randr.c +++ b/src/randr.c @@ -319,8 +319,6 @@ void output_init_con(Output *output) { * */ void init_ws_for_output(Output *output, Con *content) { - char *name; - /* go through all assignments and move the existing workspaces to this output */ struct Workspace_Assignment *assignment; TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) { @@ -404,116 +402,7 @@ void init_ws_for_output(Output *output, Con *content) { /* if there is still no workspace, we create the first free workspace */ DLOG("Now adding a workspace\n"); - - /* add a workspace to this output */ - Con *out, *current; - bool exists = true; - Con *ws = con_new(NULL, NULL); - ws->type = CT_WORKSPACE; - - /* try the configured workspace bindings first to find a free name */ - Binding *bind; - TAILQ_FOREACH(bind, bindings, bindings) { - DLOG("binding with command %s\n", bind->command); - if (strlen(bind->command) < strlen("workspace ") || - strncasecmp(bind->command, "workspace", strlen("workspace")) != 0) - continue; - DLOG("relevant command = %s\n", bind->command); - char *target = bind->command + strlen("workspace "); - /* We check if this is the workspace - * next/prev/next_on_output/prev_on_output/back_and_forth command. - * Beware: The workspace names "next", "prev", "next_on_output", - * "prev_on_output" and "back_and_forth" are OK, so we check before - * stripping the double quotes */ - if (strncasecmp(target, "next", strlen("next")) == 0 || - strncasecmp(target, "prev", strlen("prev")) == 0 || - strncasecmp(target, "next_on_output", strlen("next_on_output")) == 0 || - strncasecmp(target, "prev_on_output", strlen("prev_on_output")) == 0 || - strncasecmp(target, "back_and_forth", strlen("back_and_forth")) == 0) - continue; - if (*target == '"') - target++; - FREE(ws->name); - ws->name = strdup(target); - if (ws->name[strlen(ws->name)-1] == '"') - ws->name[strlen(ws->name)-1] = '\0'; - DLOG("trying name *%s*\n", ws->name); - - /* Ensure that this workspace is not assigned to a different output — - * otherwise we would create it, then move it over to its output, then - * find a new workspace, etc… */ - bool assigned = false; - TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) { - if (strcmp(assignment->name, ws->name) != 0 || - strcmp(assignment->output, output->name) == 0) - continue; - - assigned = true; - break; - } - - if (assigned) - continue; - - current = NULL; - TAILQ_FOREACH(out, &(croot->nodes_head), nodes) - GREP_FIRST(current, output_get_content(out), !strcasecmp(child->name, ws->name)); - - exists = (current != NULL); - if (!exists) { - /* Set ->num to the number of the workspace, if the name actually - * is a number or starts with a number */ - char *endptr = NULL; - long parsed_num = strtol(ws->name, &endptr, 10); - if (parsed_num == LONG_MIN || - parsed_num == LONG_MAX || - parsed_num < 0 || - endptr == ws->name) - ws->num = -1; - else ws->num = parsed_num; - LOG("Used number %d for workspace with name %s\n", ws->num, ws->name); - - break; - } - } - - if (exists) { - /* get the next unused workspace number */ - DLOG("Getting next unused workspace by number\n"); - int c = 0; - while (exists) { - c++; - - FREE(ws->name); - sasprintf(&(ws->name), "%d", c); - - current = NULL; - TAILQ_FOREACH(out, &(croot->nodes_head), nodes) - GREP_FIRST(current, output_get_content(out), !strcasecmp(child->name, ws->name)); - exists = (current != NULL); - - DLOG("result for ws %s / %d: exists = %d\n", ws->name, c, exists); - } - ws->num = c; - } - con_attach(ws, content, false); - - sasprintf(&name, "[i3 con] workspace %s", ws->name); - x_set_name(ws, name); - free(name); - - ws->fullscreen_mode = CF_OUTPUT; - - /* If default_orientation is set to NO_ORIENTATION we determine - * orientation depending on output resolution. */ - if (config.default_orientation == NO_ORIENTATION) { - ws->orientation = (output->rect.height > output->rect.width) ? VERT : HORIZ; - DLOG("Auto orientation. Workspace size set to (%d,%d), setting orientation to %d.\n", - output->rect.width, output->rect.height, ws->orientation); - } else { - ws->orientation = config.default_orientation; - } - + Con *ws = create_workspace_on_output(output, content); /* TODO: Set focus in main.c */ con_focus(ws); diff --git a/src/workspace.c b/src/workspace.c index 55d4af61..4fc8ba1b 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -88,6 +88,127 @@ Con *workspace_get(const char *num, bool *created) { return workspace; } +/* + * Returns a pointer to a new workspace in the given output. The workspace + * is created attached to the tree hierarchy through the given content + * container. + * + */ +Con *create_workspace_on_output(Output *output, Con *content) { + /* add a workspace to this output */ + Con *out, *current; + char *name; + bool exists = true; + Con *ws = con_new(NULL, NULL); + ws->type = CT_WORKSPACE; + + /* try the configured workspace bindings first to find a free name */ + Binding *bind; + TAILQ_FOREACH(bind, bindings, bindings) { + DLOG("binding with command %s\n", bind->command); + if (strlen(bind->command) < strlen("workspace ") || + strncasecmp(bind->command, "workspace", strlen("workspace")) != 0) + continue; + DLOG("relevant command = %s\n", bind->command); + char *target = bind->command + strlen("workspace "); + /* We check if this is the workspace + * next/prev/next_on_output/prev_on_output/back_and_forth command. + * Beware: The workspace names "next", "prev", "next_on_output", + * "prev_on_output" and "back_and_forth" are OK, so we check before + * stripping the double quotes */ + if (strncasecmp(target, "next", strlen("next")) == 0 || + strncasecmp(target, "prev", strlen("prev")) == 0 || + strncasecmp(target, "next_on_output", strlen("next_on_output")) == 0 || + strncasecmp(target, "prev_on_output", strlen("prev_on_output")) == 0 || + strncasecmp(target, "back_and_forth", strlen("back_and_forth")) == 0) + continue; + if (*target == '"') + target++; + FREE(ws->name); + ws->name = strdup(target); + if (ws->name[strlen(ws->name)-1] == '"') + ws->name[strlen(ws->name)-1] = '\0'; + DLOG("trying name *%s*\n", ws->name); + + /* Ensure that this workspace is not assigned to a different output — + * otherwise we would create it, then move it over to its output, then + * find a new workspace, etc… */ + bool assigned = false; + struct Workspace_Assignment *assignment; + TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) { + if (strcmp(assignment->name, ws->name) != 0 || + strcmp(assignment->output, output->name) == 0) + continue; + + assigned = true; + break; + } + + if (assigned) + continue; + + current = NULL; + TAILQ_FOREACH(out, &(croot->nodes_head), nodes) + GREP_FIRST(current, output_get_content(out), !strcasecmp(child->name, ws->name)); + + exists = (current != NULL); + if (!exists) { + /* Set ->num to the number of the workspace, if the name actually + * is a number or starts with a number */ + char *endptr = NULL; + long parsed_num = strtol(ws->name, &endptr, 10); + if (parsed_num == LONG_MIN || + parsed_num == LONG_MAX || + parsed_num < 0 || + endptr == ws->name) + ws->num = -1; + else ws->num = parsed_num; + LOG("Used number %d for workspace with name %s\n", ws->num, ws->name); + + break; + } + } + + if (exists) { + /* get the next unused workspace number */ + DLOG("Getting next unused workspace by number\n"); + int c = 0; + while (exists) { + c++; + + FREE(ws->name); + sasprintf(&(ws->name), "%d", c); + + current = NULL; + TAILQ_FOREACH(out, &(croot->nodes_head), nodes) + GREP_FIRST(current, output_get_content(out), !strcasecmp(child->name, ws->name)); + exists = (current != NULL); + + DLOG("result for ws %s / %d: exists = %d\n", ws->name, c, exists); + } + ws->num = c; + } + con_attach(ws, content, false); + + sasprintf(&name, "[i3 con] workspace %s", ws->name); + x_set_name(ws, name); + free(name); + + ws->fullscreen_mode = CF_OUTPUT; + + /* If default_orientation is set to NO_ORIENTATION we determine + * orientation depending on output resolution. */ + if (config.default_orientation == NO_ORIENTATION) { + ws->orientation = (output->rect.height > output->rect.width) ? VERT : HORIZ; + DLOG("Auto orientation. Workspace size set to (%d,%d), setting orientation to %d.\n", + output->rect.width, output->rect.height, ws->orientation); + } else { + ws->orientation = config.default_orientation; + } + + return ws; +} + /* * Returns true if the workspace is currently visible. Especially important for * multi-monitor environments, as they can have multiple currenlty active