mirror of
https://github.com/NickHu/sway
synced 2024-12-28 22:23:30 +01:00
Merge pull request #1693 from swaywm/move-cmd
Partially implement move command
This commit is contained in:
commit
7e3aa1daa8
12 changed files with 271 additions and 41 deletions
|
@ -36,4 +36,6 @@ void output_damage_whole(struct sway_output *output);
|
|||
void output_damage_whole_view(struct sway_output *output,
|
||||
struct sway_view *view);
|
||||
|
||||
struct sway_container *output_by_name(const char *name);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -84,9 +84,14 @@ struct sway_container {
|
|||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
// Raised after the tree updates, but before arrange_windows
|
||||
// Passed the previous parent
|
||||
struct wl_signal reparent;
|
||||
} events;
|
||||
};
|
||||
|
||||
const char *container_type_to_str(enum sway_container_type type);
|
||||
|
||||
// TODO only one container create function and pass the type?
|
||||
struct sway_container *container_output_create(
|
||||
struct sway_output *sway_output);
|
||||
|
|
|
@ -11,9 +11,6 @@ enum movement_direction {
|
|||
MOVE_DOWN,
|
||||
MOVE_PARENT,
|
||||
MOVE_CHILD,
|
||||
MOVE_NEXT,
|
||||
MOVE_PREV,
|
||||
MOVE_FIRST
|
||||
};
|
||||
|
||||
struct sway_container;
|
||||
|
@ -32,7 +29,8 @@ struct sway_root {
|
|||
|
||||
void layout_init(void);
|
||||
|
||||
void container_add_child(struct sway_container *parent, struct sway_container *child);
|
||||
void container_add_child(struct sway_container *parent,
|
||||
struct sway_container *child);
|
||||
|
||||
struct sway_container *container_add_sibling(struct sway_container *parent,
|
||||
struct sway_container *child);
|
||||
|
@ -44,7 +42,11 @@ struct sway_container *container_reap_empty(struct sway_container *container);
|
|||
void container_move_to(struct sway_container* container,
|
||||
struct sway_container* destination);
|
||||
|
||||
enum sway_container_layout container_get_default_layout(struct sway_container *output);
|
||||
void container_move(struct sway_container *container,
|
||||
enum movement_direction dir, int move_amt);
|
||||
|
||||
enum sway_container_layout container_get_default_layout(
|
||||
struct sway_container *output);
|
||||
|
||||
void container_sort_workspaces(struct sway_container *output);
|
||||
|
||||
|
|
|
@ -162,6 +162,7 @@ static struct cmd_handler command_handlers[] = {
|
|||
{ "focus", cmd_focus },
|
||||
{ "kill", cmd_kill },
|
||||
{ "layout", cmd_layout },
|
||||
{ "move", cmd_move },
|
||||
{ "reload", cmd_reload },
|
||||
};
|
||||
|
||||
|
|
|
@ -20,10 +20,6 @@ static bool parse_movement_direction(const char *name,
|
|||
*out = MOVE_PARENT;
|
||||
} else if (strcasecmp(name, "child") == 0) {
|
||||
*out = MOVE_CHILD;
|
||||
} else if (strcasecmp(name, "next") == 0) {
|
||||
*out = MOVE_NEXT;
|
||||
} else if (strcasecmp(name, "prev") == 0) {
|
||||
*out = MOVE_PREV;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -51,7 +47,8 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
|
|||
"Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'");
|
||||
}
|
||||
|
||||
struct sway_container *next_focus = container_get_in_direction(con, seat, direction);
|
||||
struct sway_container *next_focus = container_get_in_direction(
|
||||
con, seat, direction);
|
||||
if (next_focus) {
|
||||
sway_seat_set_focus(seat, next_focus);
|
||||
}
|
||||
|
|
184
sway/commands/move.c
Normal file
184
sway/commands/move.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "sway/commands.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/layout.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "stringop.h"
|
||||
#include "list.h"
|
||||
|
||||
static const char* expected_syntax =
|
||||
"Expected 'move <left|right|up|down> <[px] px>' or "
|
||||
"'move <container|window> to workspace <name>' or "
|
||||
"'move <container|window|workspace> to output <name|direction>' or "
|
||||
"'move position mouse'";
|
||||
|
||||
static struct sway_container *output_in_direction(const char *direction,
|
||||
struct wlr_output *reference, int ref_ox, int ref_oy) {
|
||||
int ref_lx = ref_ox + reference->lx,
|
||||
ref_ly = ref_oy + reference->ly;
|
||||
struct {
|
||||
char *name;
|
||||
enum wlr_direction direction;
|
||||
} names[] = {
|
||||
{ "up", WLR_DIRECTION_UP },
|
||||
{ "down", WLR_DIRECTION_DOWN },
|
||||
{ "left", WLR_DIRECTION_LEFT },
|
||||
{ "right", WLR_DIRECTION_RIGHT },
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); ++i) {
|
||||
if (strcasecmp(names[i].name, direction) == 0) {
|
||||
struct wlr_output *adjacent = wlr_output_layout_adjacent_output(
|
||||
root_container.sway_root->output_layout,
|
||||
names[i].direction, reference, ref_lx, ref_ly);
|
||||
if (adjacent) {
|
||||
struct sway_output *sway_output = adjacent->data;
|
||||
return sway_output->swayc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return output_by_name(direction);
|
||||
}
|
||||
|
||||
static struct cmd_results *cmd_move_container(struct sway_container *current,
|
||||
int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "move container/window",
|
||||
EXPECTED_AT_LEAST, 4))) {
|
||||
return error;
|
||||
} else if (strcasecmp(argv[1], "to") == 0
|
||||
&& strcasecmp(argv[2], "workspace") == 0) {
|
||||
// move container to workspace x
|
||||
if (current->type == C_WORKSPACE) {
|
||||
// TODO: Wrap children in a container and move that
|
||||
return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
|
||||
} else if (current->type != C_CONTAINER && current->type != C_VIEW) {
|
||||
return cmd_results_new(CMD_FAILURE, "move",
|
||||
"Can only move containers and views.");
|
||||
}
|
||||
struct sway_container *ws;
|
||||
const char *num_name = NULL;
|
||||
char *ws_name = NULL;
|
||||
if (argc == 5 && strcasecmp(argv[3], "number") == 0) {
|
||||
// move "container to workspace number x"
|
||||
num_name = argv[4];
|
||||
ws = workspace_by_number(num_name);
|
||||
} else {
|
||||
ws_name = join_args(argv + 3, argc - 3);
|
||||
ws = workspace_by_name(ws_name);
|
||||
}
|
||||
if (!ws) {
|
||||
ws = workspace_create(ws_name ? ws_name : num_name);
|
||||
}
|
||||
free(ws_name);
|
||||
struct sway_container *old_parent = current->parent;
|
||||
struct sway_container *focus = sway_seat_get_focus_inactive(
|
||||
config->handler_context.seat, ws);
|
||||
container_move_to(current, focus);
|
||||
sway_seat_set_focus(config->handler_context.seat, old_parent);
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
} else if (strcasecmp(argv[1], "to") == 0
|
||||
&& strcasecmp(argv[2], "output") == 0) {
|
||||
if (current->type == C_WORKSPACE) {
|
||||
// TODO: Wrap children in a container and move that
|
||||
return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
|
||||
} else if (current->type != C_CONTAINER
|
||||
&& current->type != C_VIEW) {
|
||||
return cmd_results_new(CMD_FAILURE, "move",
|
||||
"Can only move containers and views.");
|
||||
}
|
||||
struct sway_container *source = container_parent(current, C_OUTPUT);
|
||||
struct sway_container *destination = output_in_direction(argv[3],
|
||||
source->sway_output->wlr_output, current->x, current->y);
|
||||
if (!destination) {
|
||||
return cmd_results_new(CMD_FAILURE, "move workspace",
|
||||
"Can't find output with name/direction '%s'", argv[3]);
|
||||
}
|
||||
struct sway_container *focus = sway_seat_get_focus_inactive(
|
||||
config->handler_context.seat, destination);
|
||||
if (!focus) {
|
||||
// We've never been to this output before
|
||||
focus = destination->children->items[0];
|
||||
}
|
||||
struct sway_container *old_parent = current->parent;
|
||||
container_move_to(current, focus);
|
||||
sway_seat_set_focus(config->handler_context.seat, old_parent);
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
return cmd_results_new(CMD_INVALID, "move", expected_syntax);
|
||||
}
|
||||
|
||||
static struct cmd_results *cmd_move_workspace(struct sway_container *current,
|
||||
int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) {
|
||||
return error;
|
||||
} else if (strcasecmp(argv[1], "to") != 0
|
||||
|| strcasecmp(argv[2], "output") != 0) {
|
||||
return cmd_results_new(CMD_INVALID, "move", expected_syntax);
|
||||
}
|
||||
struct sway_container *source = container_parent(current, C_OUTPUT);
|
||||
int center_x = current->width / 2 + current->x,
|
||||
center_y = current->height / 2 + current->y;
|
||||
struct sway_container *destination = output_in_direction(argv[3],
|
||||
source->sway_output->wlr_output, center_x, center_y);
|
||||
if (!destination) {
|
||||
return cmd_results_new(CMD_FAILURE, "move workspace",
|
||||
"Can't find output with name/direction '%s'", argv[3]);
|
||||
}
|
||||
if (current->type != C_WORKSPACE) {
|
||||
current = container_parent(current, C_WORKSPACE);
|
||||
}
|
||||
container_move_to(current, destination);
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_move(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
int move_amt = 10;
|
||||
if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) {
|
||||
return error;
|
||||
}
|
||||
struct sway_container *current = config->handler_context.current_container;
|
||||
|
||||
if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0)) {
|
||||
char *inv;
|
||||
move_amt = (int)strtol(argv[1], &inv, 10);
|
||||
if (*inv != '\0' && strcasecmp(inv, "px") != 0) {
|
||||
return cmd_results_new(CMD_FAILURE, "move",
|
||||
"Invalid distance specified");
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[0], "left") == 0) {
|
||||
container_move(current, MOVE_LEFT, move_amt);
|
||||
} else if (strcasecmp(argv[0], "right") == 0) {
|
||||
container_move(current, MOVE_RIGHT, move_amt);
|
||||
} else if (strcasecmp(argv[0], "up") == 0) {
|
||||
container_move(current, MOVE_UP, move_amt);
|
||||
} else if (strcasecmp(argv[0], "down") == 0) {
|
||||
container_move(current, MOVE_DOWN, move_amt);
|
||||
} else if (strcasecmp(argv[0], "container") == 0
|
||||
|| strcasecmp(argv[0], "window") == 0) {
|
||||
return cmd_move_container(current, argc, argv);
|
||||
} else if (strcasecmp(argv[0], "workspace") == 0) {
|
||||
return cmd_move_workspace(current, argc, argv);
|
||||
} else if (strcasecmp(argv[0], "scratchpad") == 0
|
||||
|| (strcasecmp(argv[0], "to") == 0
|
||||
&& strcasecmp(argv[1], "scratchpad") == 0)) {
|
||||
// TODO: scratchpad
|
||||
return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
|
||||
} else if (strcasecmp(argv[0], "position") == 0) {
|
||||
// TODO: floating
|
||||
return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
|
||||
} else {
|
||||
return cmd_results_new(CMD_INVALID, "move", expected_syntax);
|
||||
}
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
|
@ -229,9 +229,12 @@ static void render_output(struct sway_output *output, struct timespec *when,
|
|||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
struct sway_container *focus =
|
||||
sway_seat_get_focus_inactive(seat, output->swayc);
|
||||
struct sway_container *workspace = (focus->type == C_WORKSPACE ?
|
||||
focus :
|
||||
container_parent(focus, C_WORKSPACE));
|
||||
if (!focus) {
|
||||
// We've never been to this output before
|
||||
focus = output->swayc->children->items[0];
|
||||
}
|
||||
struct sway_container *workspace = focus->type == C_WORKSPACE ?
|
||||
focus : container_parent(focus, C_WORKSPACE);
|
||||
|
||||
struct render_data rdata = {
|
||||
.output = output,
|
||||
|
|
|
@ -97,8 +97,8 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard,
|
|||
config->handler_context.seat = keyboard->seat_device->sway_seat;
|
||||
struct cmd_results *results = execute_command(binding->command, NULL);
|
||||
if (results->status != CMD_SUCCESS) {
|
||||
wlr_log(L_DEBUG, "could not run command for binding: %s",
|
||||
binding->command);
|
||||
wlr_log(L_DEBUG, "could not run command for binding: %s (%s)",
|
||||
binding->command, results->error);
|
||||
}
|
||||
free_cmd_results(results);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ sway_sources = files(
|
|||
'commands/input.c',
|
||||
'commands/layout.c',
|
||||
'commands/mode.c',
|
||||
'commands/move.c',
|
||||
'commands/seat.c',
|
||||
'commands/seat/attach.c',
|
||||
'commands/seat/fallback.c',
|
||||
|
|
|
@ -33,6 +33,23 @@ static list_t *get_bfs_queue() {
|
|||
return bfs_queue;
|
||||
}
|
||||
|
||||
const char *container_type_to_str(enum sway_container_type type) {
|
||||
switch (type) {
|
||||
case C_ROOT:
|
||||
return "C_ROOT";
|
||||
case C_OUTPUT:
|
||||
return "C_OUTPUT";
|
||||
case C_WORKSPACE:
|
||||
return "C_WORKSPACE";
|
||||
case C_CONTAINER:
|
||||
return "C_CONTAINER";
|
||||
case C_VIEW:
|
||||
return "C_VIEW";
|
||||
default:
|
||||
return "C_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static void notify_new_container(struct sway_container *container) {
|
||||
wl_signal_emit(&root_container.sway_root->events.new_container, container);
|
||||
ipc_event_window(container, "new");
|
||||
|
@ -54,6 +71,7 @@ static struct sway_container *container_create(enum sway_container_type type) {
|
|||
}
|
||||
|
||||
wl_signal_init(&c->events.destroy);
|
||||
wl_signal_init(&c->events.reparent);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
|
|
@ -106,8 +106,10 @@ struct sway_container *container_reap_empty(struct sway_container *container) {
|
|||
if (!sway_assert(container, "reaping null container")) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_log(L_DEBUG, "reaping %p %s", container, container->name);
|
||||
while (container != &root_container && container->children->length == 0) {
|
||||
wlr_log(L_DEBUG, "Reaping %p %s '%s'", container,
|
||||
container_type_to_str(container->type), container->name);
|
||||
while (container->type != C_ROOT && container->type != C_OUTPUT
|
||||
&& container->children->length == 0) {
|
||||
if (container->type == C_WORKSPACE) {
|
||||
if (!workspace_is_visible(container)) {
|
||||
struct sway_container *parent = container->parent;
|
||||
|
@ -138,22 +140,46 @@ struct sway_container *container_remove_child(struct sway_container *child) {
|
|||
return container_reap_empty(parent);
|
||||
}
|
||||
|
||||
void container_move_to(struct sway_container* container,
|
||||
struct sway_container* destination) {
|
||||
void container_move_to(struct sway_container *container,
|
||||
struct sway_container *destination) {
|
||||
if (container == destination
|
||||
|| container_has_anscestor(container, destination)) {
|
||||
return;
|
||||
}
|
||||
struct sway_container *old_parent = container_remove_child(container);
|
||||
container->width = container->height = 0;
|
||||
struct sway_container *new_parent =
|
||||
container_add_sibling(destination, container);
|
||||
struct sway_container *new_parent;
|
||||
if (destination->type == C_VIEW) {
|
||||
new_parent = container_add_sibling(destination, container);
|
||||
} else {
|
||||
new_parent = destination;
|
||||
container_add_child(destination, container);
|
||||
}
|
||||
wl_signal_emit(&container->events.reparent, old_parent);
|
||||
if (container->type == C_WORKSPACE) {
|
||||
struct sway_seat *seat = sway_input_manager_get_default_seat(
|
||||
input_manager);
|
||||
if (old_parent->children->length == 0) {
|
||||
char *ws_name = workspace_next_name(old_parent->name);
|
||||
struct sway_container *ws =
|
||||
container_workspace_create(old_parent, ws_name);
|
||||
free(ws_name);
|
||||
sway_seat_set_focus(seat, ws);
|
||||
}
|
||||
container_sort_workspaces(new_parent);
|
||||
sway_seat_set_focus(seat, new_parent);
|
||||
}
|
||||
if (old_parent) {
|
||||
arrange_windows(old_parent, -1, -1);
|
||||
}
|
||||
arrange_windows(new_parent, -1, -1);
|
||||
}
|
||||
|
||||
void container_move(struct sway_container *container,
|
||||
enum movement_direction dir, int move_amt) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
enum sway_container_layout container_get_default_layout(
|
||||
struct sway_container *output) {
|
||||
if (config->default_layout != L_NONE) {
|
||||
|
@ -521,26 +547,6 @@ static struct sway_container *get_swayc_in_direction_under(
|
|||
}
|
||||
}
|
||||
|
||||
if (dir == MOVE_PREV || dir == MOVE_NEXT) {
|
||||
int focused_idx = index_child(container);
|
||||
if (focused_idx == -1) {
|
||||
return NULL;
|
||||
} else {
|
||||
int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) %
|
||||
parent->children->length;
|
||||
if (desired < 0) {
|
||||
desired += parent->children->length;
|
||||
}
|
||||
return parent->children->items[desired];
|
||||
}
|
||||
}
|
||||
|
||||
// If moving to an adjacent output we need a starting position (since this
|
||||
// output might border to multiple outputs).
|
||||
//struct wlc_point abs_pos;
|
||||
//get_layout_center_position(container, &abs_pos);
|
||||
|
||||
|
||||
// TODO WLR fullscreen
|
||||
/*
|
||||
if (container->type == C_VIEW && swayc_is_fullscreen(container)) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <strings.h>
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/layout.h"
|
||||
#include "sway/output.h"
|
||||
|
@ -37,3 +38,13 @@ struct sway_container *container_output_destroy(struct sway_container *output) {
|
|||
container_destroy(output);
|
||||
return &root_container;
|
||||
}
|
||||
|
||||
struct sway_container *output_by_name(const char *name) {
|
||||
for (int i = 0; i < root_container.children->length; ++i) {
|
||||
struct sway_container *output = root_container.children->items[i];
|
||||
if (strcasecmp(output->name, name) == 0){
|
||||
return output;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue