Deny moving a sticky container to workspace if it's the same output

Rationale: Sticky containers are always assigned to the visible
workspace.

The basic idea here is to check the destination's output (move.c:190).
But if the command was `move container to workspace x` then a workspace
might have been created for it. We could destroy the workspace in this
case, but that results in unnecessary IPC events.

To avoid this, the logic for `move container to workspace x` has been
adjusted. It now delays creating the workspace until the end, and uses
`workspace_get_initial_output` to determine and check the output before
creating it.
This commit is contained in:
Ryan Dwyer 2018-08-08 10:04:11 +10:00
parent a0649190de
commit 5653fc754b
3 changed files with 36 additions and 10 deletions

View file

@ -16,6 +16,8 @@ struct sway_workspace {
extern char *prev_workspace_name; extern char *prev_workspace_name;
struct sway_container *workspace_get_initial_output(const char *name);
char *workspace_next_name(const char *output_name); char *workspace_next_name(const char *output_name);
bool workspace_switch(struct sway_container *workspace, bool workspace_switch(struct sway_container *workspace,

View file

@ -100,7 +100,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
// determine destination // determine destination
if (strcasecmp(argv[1], "workspace") == 0) { if (strcasecmp(argv[1], "workspace") == 0) {
// move container to workspace x // move container to workspace x
struct sway_container *ws; struct sway_container *ws = NULL;
char *ws_name = NULL;
if (strcasecmp(argv[2], "next") == 0 || if (strcasecmp(argv[2], "next") == 0 ||
strcasecmp(argv[2], "prev") == 0 || strcasecmp(argv[2], "prev") == 0 ||
strcasecmp(argv[2], "next_on_output") == 0 || strcasecmp(argv[2], "next_on_output") == 0 ||
@ -110,14 +111,13 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
} else if (strcasecmp(argv[2], "back_and_forth") == 0) { } else if (strcasecmp(argv[2], "back_and_forth") == 0) {
if (!(ws = workspace_by_name(argv[2]))) { if (!(ws = workspace_by_name(argv[2]))) {
if (prev_workspace_name) { if (prev_workspace_name) {
ws = workspace_create(NULL, prev_workspace_name); ws_name = strdup(prev_workspace_name);
} else { } else {
return cmd_results_new(CMD_FAILURE, "move", return cmd_results_new(CMD_FAILURE, "move",
"No workspace was previously active."); "No workspace was previously active.");
} }
} }
} else { } else {
char *ws_name = NULL;
if (strcasecmp(argv[2], "number") == 0) { if (strcasecmp(argv[2], "number") == 0) {
// move "container to workspace number x" // move "container to workspace number x"
if (argc < 4) { if (argc < 4) {
@ -141,12 +141,26 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
ws = workspace_by_name(ws_name); ws = workspace_by_name(ws_name);
} }
} }
}
if (!ws) { if (!ws) {
// We have to create the workspace, but if the container is
// sticky and the workspace is going to be created on the same
// output, we'll bail out first.
if (container_is_floating(current) && current->is_sticky) {
struct sway_container *old_output =
container_parent(current, C_OUTPUT);
struct sway_container *new_output =
workspace_get_initial_output(ws_name);
if (old_output == new_output) {
free(ws_name);
return cmd_results_new(CMD_FAILURE, "move",
"Can't move sticky container to another workspace "
"on the same output");
}
}
ws = workspace_create(NULL, ws_name); ws = workspace_create(NULL, ws_name);
} }
free(ws_name); free(ws_name);
}
destination = seat_get_focus_inactive(config->handler_context.seat, ws); destination = seat_get_focus_inactive(config->handler_context.seat, ws);
} else if (strcasecmp(argv[1], "output") == 0) { } else if (strcasecmp(argv[1], "output") == 0) {
struct sway_container *source = container_parent(current, C_OUTPUT); struct sway_container *source = container_parent(current, C_OUTPUT);
@ -173,6 +187,16 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
return cmd_results_new(CMD_INVALID, "move", expected_syntax); return cmd_results_new(CMD_INVALID, "move", expected_syntax);
} }
if (container_is_floating(current) && current->is_sticky) {
struct sway_container *old_output = container_parent(current, C_OUTPUT);
struct sway_container *new_output = destination->type == C_OUTPUT ?
destination : container_parent(destination, C_OUTPUT);
if (old_output == new_output) {
return cmd_results_new(CMD_FAILURE, "move", "Can't move sticky "
"container to another workspace on the same output");
}
}
// move container, arrange windows and return focus // move container, arrange windows and return focus
container_move_to(current, destination); container_move_to(current, destination);
struct sway_container *focus = struct sway_container *focus =

View file

@ -18,7 +18,7 @@
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
static struct sway_container *get_workspace_initial_output(const char *name) { struct sway_container *workspace_get_initial_output(const char *name) {
struct sway_container *parent; struct sway_container *parent;
// Search for workspace<->output pair // Search for workspace<->output pair
int e = config->workspace_outputs->length; int e = config->workspace_outputs->length;
@ -48,7 +48,7 @@ static struct sway_container *get_workspace_initial_output(const char *name) {
struct sway_container *workspace_create(struct sway_container *output, struct sway_container *workspace_create(struct sway_container *output,
const char *name) { const char *name) {
if (output == NULL) { if (output == NULL) {
output = get_workspace_initial_output(name); output = workspace_get_initial_output(name);
} }
wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name); wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name);