From 515150229847c9ebdfd0cabb6f0026fca9d57a23 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 4 Feb 2018 13:39:10 -0500 Subject: [PATCH 01/36] basic focus overhaul --- include/sway/container.h | 6 ++ include/sway/input/seat.h | 16 ++++- include/sway/layout.h | 6 ++ sway/commands.c | 5 +- sway/commands/kill.c | 7 +- sway/commands/workspace.c | 3 +- sway/desktop/xdg_shell_v6.c | 3 +- sway/input/input-manager.c | 2 +- sway/input/seat.c | 135 ++++++++++++++++++++++++++++++------ sway/tree/container.c | 33 +++++++-- sway/tree/layout.c | 30 ++++++++ sway/tree/workspace.c | 17 +++-- 12 files changed, 224 insertions(+), 39 deletions(-) diff --git a/include/sway/container.h b/include/sway/container.h index 0c66932d6..997240bd6 100644 --- a/include/sway/container.h +++ b/include/sway/container.h @@ -162,4 +162,10 @@ void container_map(swayc_t *container, swayc_t *swayc_at(swayc_t *parent, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); +/** + * Get a list of containers that are descendents of the container in rendering + * order + */ +list_t *container_list_children(swayc_t *con); + #endif diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index b21cbccb7..8d5d6b75a 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -12,14 +12,26 @@ struct sway_seat_device { struct wl_list link; // sway_seat::devices }; +struct sway_seat_container { + struct sway_seat *seat; + swayc_t *container; + + struct wl_list link; // sway_seat::focus_stack + + struct wl_listener destroy; +}; + struct sway_seat { struct wlr_seat *wlr_seat; struct seat_config *config; struct sway_cursor *cursor; struct sway_input_manager *input; - swayc_t *focus; + + bool has_focus; + struct wl_list focus_stack; // list of containers in focus order struct wl_listener focus_destroy; + struct wl_listener new_container; struct wl_list devices; // sway_seat_device::link @@ -44,6 +56,8 @@ void sway_seat_configure_xcursor(struct sway_seat *seat); void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container); +swayc_t *sway_seat_get_focus(struct sway_seat *seat, swayc_t *container); + void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); #endif diff --git a/include/sway/layout.h b/include/sway/layout.h index af5614531..69a666741 100644 --- a/include/sway/layout.h +++ b/include/sway/layout.h @@ -2,6 +2,7 @@ #define _SWAY_LAYOUT_H #include +#include "sway/container.h" struct sway_container; @@ -11,10 +12,15 @@ struct sway_root { struct wl_listener output_layout_change; struct wl_list unmanaged_views; // sway_view::unmanaged_view_link + + struct { + struct wl_signal new_container; + } events; }; void init_layout(void); void add_child(struct sway_container *parent, struct sway_container *child); +swayc_t *add_sibling(swayc_t *parent, swayc_t *child); struct sway_container *remove_child(struct sway_container *child); enum swayc_layouts default_layout(struct sway_container *output); void sort_workspaces(struct sway_container *output); diff --git a/sway/commands.c b/sway/commands.c index 0d4aa104a..6bb4db0bc 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -281,7 +281,10 @@ struct cmd_results *handle_command(char *_exec) { seat = sway_input_manager_get_default_seat(input_manager); } if (seat) { - config->handler_context.current_container = seat->focus; + config->handler_context.current_container = + (seat->has_focus ? + sway_seat_get_focus(seat, &root_container) : + NULL); struct cmd_results *res = handler->handle(argc-1, argv+1); if (res->status != CMD_SUCCESS) { free_argv(argc, argv); diff --git a/sway/commands/kill.c b/sway/commands/kill.c index cebf7f3c7..4b3666be2 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c @@ -10,11 +10,16 @@ struct cmd_results *cmd_kill(int argc, char **argv) { return cmd_results_new(CMD_FAILURE, "kill", "Command 'kill' cannot be used in the config file"); } + if (config->handler_context.current_container == NULL) { + wlr_log(L_DEBUG, "no container to kill"); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } enum swayc_types type = config->handler_context.current_container->type; - if (type != C_VIEW || type != C_CONTAINER) { + if (type != C_VIEW && type != C_CONTAINER) { return cmd_results_new(CMD_INVALID, NULL, "Can only kill views and containers with this command"); } + // TODO close arbitrary containers without a view struct sway_view *view = config->handler_context.current_container->sway_view; diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index 12984ed4a..e7d6cc9f9 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -90,7 +90,8 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { free(name); } workspace_switch(ws); - current_container = config->handler_context.seat->focus; + current_container = + sway_seat_get_focus(config->handler_context.seat, &root_container); swayc_t *new_output = swayc_parent_by_type(current_container, C_OUTPUT); if (config->mouse_warping && old_output != new_output) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index ca56a9c01..04d890159 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -135,7 +135,8 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy); struct sway_seat *seat = input_manager_current_seat(input_manager); - swayc_t *cont = new_view(seat->focus, sway_view); + swayc_t *focus = sway_seat_get_focus(seat, &root_container); + swayc_t *cont = new_view(focus, sway_view); sway_view->swayc = cont; arrange_windows(cont->parent, -1, -1); diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index d789c7eb8..a406636e5 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -282,7 +282,7 @@ bool sway_input_manager_has_focus(struct sway_input_manager *input, swayc_t *container) { struct sway_seat *seat = NULL; wl_list_for_each(seat, &input->seats, link) { - if (seat->focus == container) { + if (seat->has_focus && sway_seat_get_focus(seat, &root_container) == container) { return true; } } diff --git a/sway/input/seat.c b/sway/input/seat.c index 5e87986d0..cbf05abd4 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -32,6 +32,44 @@ void sway_seat_destroy(struct sway_seat *seat) { wlr_seat_destroy(seat->wlr_seat); } +static void handle_seat_container_destroy(struct wl_listener *listener, + void *data) { + struct sway_seat_container *seat_con = + wl_container_of(listener, seat_con, destroy); + wl_list_remove(&seat_con->link); + wl_list_remove(&seat_con->destroy.link); + free(seat_con); +} + +static struct sway_seat_container *seat_container_from_container( + struct sway_seat *seat, swayc_t *con) { + struct sway_seat_container *seat_con = NULL; + wl_list_for_each(seat_con, &seat->focus_stack, link) { + if (seat_con->container == con) { + return seat_con; + } + } + + seat_con = calloc(1, sizeof(struct sway_seat_container)); + if (seat_con == NULL) { + wlr_log(L_ERROR, "could not allocate seat container"); + return NULL; + } + + seat_con->container = con; + wl_list_insert(seat->focus_stack.prev, &seat_con->link); + wl_signal_add(&con->events.destroy, &seat_con->destroy); + seat_con->destroy.notify = handle_seat_container_destroy; + + return seat_con; +} + +static void handle_new_container(struct wl_listener *listener, void *data) { + struct sway_seat *seat = wl_container_of(listener, seat, new_container); + swayc_t *con = data; + seat_container_from_container(seat, con); +} + struct sway_seat *sway_seat_create(struct sway_input_manager *input, const char *seat_name) { struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); @@ -52,6 +90,24 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input, return NULL; } + // init the focus stack + wl_list_init(&seat->focus_stack); + list_t *containers = container_list_children(&root_container); + if (containers == NULL) { + wlr_seat_destroy(seat->wlr_seat); + free(seat); + return NULL; + } + for (int i = containers->length - 1; i >= 0; --i) { + swayc_t *con = containers->items[i]; + seat_container_from_container(seat, con); + } + free(containers); + + wl_signal_add(&root_container.sway_root->events.new_container, + &seat->new_container); + seat->new_container.notify = handle_new_container; + seat->input = input; wl_list_init(&seat->devices); @@ -82,12 +138,15 @@ static void seat_configure_keyboard(struct sway_seat *seat, sway_keyboard_configure(seat_device->keyboard); wlr_seat_set_keyboard(seat->wlr_seat, seat_device->input_device->wlr_device); - if (seat->focus && seat->focus->type == C_VIEW) { - // force notify reenter to pick up the new configuration - wlr_seat_keyboard_clear_focus(seat->wlr_seat); - wlr_seat_keyboard_notify_enter(seat->wlr_seat, - seat->focus->sway_view->surface, wlr_keyboard->keycodes, - wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); + if (seat->has_focus) { + swayc_t *focus = sway_seat_get_focus(seat, &root_container); + if (focus && focus->type == C_VIEW) { + // force notify reenter to pick up the new configuration + wlr_seat_keyboard_clear_focus(seat->wlr_seat); + wlr_seat_keyboard_notify_enter(seat->wlr_seat, + focus->sway_view->surface, wlr_keyboard->keycodes, + wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); + } } } @@ -211,35 +270,43 @@ static void handle_focus_destroy(struct wl_listener *listener, void *data) { } void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { - swayc_t *last_focus = seat->focus; + swayc_t *last_focus = + (seat->has_focus ? sway_seat_get_focus(seat, &root_container) : NULL); - if (last_focus == container) { + if (container && last_focus == container) { return; } - if (last_focus && last_focus->type == C_VIEW) { + if (last_focus) { wl_list_remove(&seat->focus_destroy.link); + seat->has_focus = false; } - if (container && container->type == C_VIEW) { - struct sway_view *view = container->sway_view; - view_set_activated(view, true); + if (container) { + struct sway_seat_container *seat_con = + seat_container_from_container(seat, container); wl_signal_add(&container->events.destroy, &seat->focus_destroy); seat->focus_destroy.notify = handle_focus_destroy; + seat->has_focus = true; - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); - if (keyboard) { - wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, - keyboard->keycodes, keyboard->num_keycodes, - &keyboard->modifiers); - } else { - wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, - NULL, 0, NULL); + wl_list_remove(&seat_con->link); + wl_list_insert(&seat->focus_stack, &seat_con->link); + + if (container->type == C_VIEW) { + struct sway_view *view = container->sway_view; + view_set_activated(view, true); + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); + if (keyboard) { + wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, + keyboard->keycodes, keyboard->num_keycodes, + &keyboard->modifiers); + } else { + wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, + NULL, 0, NULL); + } } } - seat->focus = container; - if (last_focus && last_focus->type == C_VIEW && !sway_input_manager_has_focus(seat->input, last_focus)) { struct sway_view *view = last_focus->sway_view; @@ -247,6 +314,30 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { } } +swayc_t *sway_seat_get_focus(struct sway_seat *seat, swayc_t *container) { + struct sway_seat_container *current = NULL; + swayc_t *parent = NULL; + wl_list_for_each(current, &seat->focus_stack, link) { + if (current->container->type < C_WORKSPACE) { + continue; + } + parent = current->container->parent; + + if (current->container == container) { + return current->container; + } + + while (parent) { + if (parent == container) { + return current->container; + } + parent = parent->parent; + } + } + + return NULL; +} + void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config) { // clear configs diff --git a/sway/tree/container.c b/sway/tree/container.c index 48aabd865..67fac5ee5 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -158,12 +158,13 @@ swayc_t *new_output(struct sway_output *sway_output) { // struct instead of trying to do focus semantics like this struct sway_seat *seat = NULL; wl_list_for_each(seat, &input_manager->seats, link) { - if (!seat->focus) { - seat->focus = ws; + if (!seat->has_focus) { + sway_seat_set_focus(seat, ws); } } free(ws_name); + wl_signal_emit(&root_container.sway_root->events.new_container, output); return output; } @@ -185,6 +186,7 @@ swayc_t *new_workspace(swayc_t *output, const char *name) { add_child(output, workspace); sort_workspaces(output); + wl_signal_emit(&root_container.sway_root->events.new_container, workspace); return workspace; } @@ -207,9 +209,9 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view) { add_child(sibling, swayc); } else { // Regular case, create as sibling of current container - // TODO WLR - //add_sibling(sibling, swayc); + add_sibling(sibling, swayc); } + wl_signal_emit(&root_container.sway_root->events.new_container, swayc); return swayc; } @@ -378,3 +380,26 @@ void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), voi f(container, data); } } + +/** + * Get a list of containers that are descendents of the container in rendering + * order + */ +list_t *container_list_children(swayc_t *con) { + list_t *list = create_list(); + list_t *queue = create_list(); + + list_add(queue, con); + + swayc_t *current = NULL; + while (queue->length) { + current = queue->items[0]; + list_del(queue, 0); + list_add(list, current); + // TODO floating containers + list_cat(queue, current->children); + } + + list_free(queue); + return list; +} diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 41ff81b2f..45f8c3ae3 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -48,10 +48,12 @@ void init_layout(void) { root_container.layout = L_NONE; root_container.name = strdup("root"); root_container.children = create_list(); + wl_signal_init(&root_container.events.destroy); root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); root_container.sway_root->output_layout = wlr_output_layout_create(); wl_list_init(&root_container.sway_root->unmanaged_views); + wl_signal_init(&root_container.sway_root->events.new_container); root_container.sway_root->output_layout_change.notify = output_layout_change_notify; @@ -59,6 +61,34 @@ void init_layout(void) { &root_container.sway_root->output_layout_change); } +int index_child(const swayc_t *child) { + // TODO handle floating + swayc_t *parent = child->parent; + int i, len; + len = parent->children->length; + for (i = 0; i < len; ++i) { + if (parent->children->items[i] == child) { + break; + } + } + + if (!sway_assert(i < len, "Stray container")) { + return -1; + } + return i; +} + +swayc_t *add_sibling(swayc_t *fixed, swayc_t *active) { + // TODO handle floating + swayc_t *parent = fixed->parent; + int i = index_child(fixed); + list_insert(parent->children, i + 1, active); + active->parent = parent; + // focus new child + parent->focused = active; + return active->parent; +} + void add_child(swayc_t *parent, swayc_t *child) { wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", child, child->type, child->width, child->height, diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 23c630b65..ce5b425c5 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -63,9 +63,10 @@ static bool _workspace_by_name(swayc_t *view, void *data) { swayc_t *workspace_by_name(const char *name) { struct sway_seat *seat = input_manager_current_seat(input_manager); swayc_t *current_workspace = NULL, *current_output = NULL; - if (seat->focus) { - current_workspace = swayc_parent_by_type(seat->focus, C_WORKSPACE); - current_output = swayc_parent_by_type(seat->focus, C_OUTPUT); + if (seat->has_focus) { + swayc_t *focus = sway_seat_get_focus(seat, &root_container); + current_workspace = swayc_parent_by_type(focus, C_WORKSPACE); + current_output = swayc_parent_by_type(focus, C_OUTPUT); } if (strcmp(name, "prev") == 0) { return workspace_prev(current_workspace); @@ -102,7 +103,8 @@ swayc_t *workspace_create(const char *name) { } // Otherwise create a new one struct sway_seat *seat = input_manager_current_seat(input_manager); - parent = seat->focus; + swayc_t *focus = sway_seat_get_focus(seat, &root_container); + parent = focus; parent = swayc_parent_by_type(parent, C_OUTPUT); return new_workspace(parent, name); } @@ -193,12 +195,13 @@ bool workspace_switch(swayc_t *workspace) { return false; } struct sway_seat *seat = input_manager_current_seat(input_manager); - if (!seat || !seat->focus) { + swayc_t *focus = sway_seat_get_focus(seat, &root_container); + if (!seat || !focus) { return false; } - swayc_t *active_ws = seat->focus; + swayc_t *active_ws = focus; if (active_ws->type != C_WORKSPACE) { - swayc_parent_by_type(seat->focus, C_WORKSPACE); + swayc_parent_by_type(focus, C_WORKSPACE); } if (config->auto_back_and_forth From 7d8f2c52aa96e4cbe55fe6fb00895401a85f95b6 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 6 Feb 2018 18:54:10 -0500 Subject: [PATCH 02/36] make index_child static --- sway/tree/layout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 45f8c3ae3..16d5cbc5d 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -61,7 +61,7 @@ void init_layout(void) { &root_container.sway_root->output_layout_change); } -int index_child(const swayc_t *child) { +static int index_child(const swayc_t *child) { // TODO handle floating swayc_t *parent = child->parent; int i, len; From a7d49da23956c245f0e6b8f7dc9cb532eb14c4b9 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 7 Feb 2018 18:17:57 -0500 Subject: [PATCH 03/36] separate seat get focus and seat get focus inactive --- include/sway/input/seat.h | 4 +++- sway/commands.c | 4 +--- sway/commands/workspace.c | 2 +- sway/desktop/xdg_shell_v6.c | 2 +- sway/input/input-manager.c | 2 +- sway/input/seat.c | 32 +++++++++++++++++++------------- sway/tree/workspace.c | 8 ++++---- 7 files changed, 30 insertions(+), 24 deletions(-) diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 8d5d6b75a..26a7e5dc2 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -56,7 +56,9 @@ void sway_seat_configure_xcursor(struct sway_seat *seat); void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container); -swayc_t *sway_seat_get_focus(struct sway_seat *seat, swayc_t *container); +swayc_t *sway_seat_get_focus(struct sway_seat *seat); + +swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container); void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); diff --git a/sway/commands.c b/sway/commands.c index 6bb4db0bc..d8d29a1cf 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -282,9 +282,7 @@ struct cmd_results *handle_command(char *_exec) { } if (seat) { config->handler_context.current_container = - (seat->has_focus ? - sway_seat_get_focus(seat, &root_container) : - NULL); + sway_seat_get_focus(seat); struct cmd_results *res = handler->handle(argc-1, argv+1); if (res->status != CMD_SUCCESS) { free_argv(argc, argv); diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index e7d6cc9f9..fa8913984 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -91,7 +91,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { } workspace_switch(ws); current_container = - sway_seat_get_focus(config->handler_context.seat, &root_container); + sway_seat_get_focus(config->handler_context.seat); swayc_t *new_output = swayc_parent_by_type(current_container, C_OUTPUT); if (config->mouse_warping && old_output != new_output) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 04d890159..b44d9e54f 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -135,7 +135,7 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy); struct sway_seat *seat = input_manager_current_seat(input_manager); - swayc_t *focus = sway_seat_get_focus(seat, &root_container); + swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container); swayc_t *cont = new_view(focus, sway_view); sway_view->swayc = cont; diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index a406636e5..90eb8cf63 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -282,7 +282,7 @@ bool sway_input_manager_has_focus(struct sway_input_manager *input, swayc_t *container) { struct sway_seat *seat = NULL; wl_list_for_each(seat, &input->seats, link) { - if (seat->has_focus && sway_seat_get_focus(seat, &root_container) == container) { + if (sway_seat_get_focus(seat) == container) { return true; } } diff --git a/sway/input/seat.c b/sway/input/seat.c index cbf05abd4..d2ffca645 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -137,16 +137,14 @@ static void seat_configure_keyboard(struct sway_seat *seat, struct wlr_keyboard *wlr_keyboard = seat_device->input_device->wlr_device->keyboard; sway_keyboard_configure(seat_device->keyboard); wlr_seat_set_keyboard(seat->wlr_seat, - seat_device->input_device->wlr_device); - if (seat->has_focus) { - swayc_t *focus = sway_seat_get_focus(seat, &root_container); - if (focus && focus->type == C_VIEW) { - // force notify reenter to pick up the new configuration - wlr_seat_keyboard_clear_focus(seat->wlr_seat); - wlr_seat_keyboard_notify_enter(seat->wlr_seat, - focus->sway_view->surface, wlr_keyboard->keycodes, - wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); - } + seat_device->input_device->wlr_device); + swayc_t *focus = sway_seat_get_focus(seat); + if (focus && focus->type == C_VIEW) { + // force notify reenter to pick up the new configuration + wlr_seat_keyboard_clear_focus(seat->wlr_seat); + wlr_seat_keyboard_notify_enter(seat->wlr_seat, + focus->sway_view->surface, wlr_keyboard->keycodes, + wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); } } @@ -266,12 +264,13 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) { static void handle_focus_destroy(struct wl_listener *listener, void *data) { struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy); swayc_t *container = data; + // TODO dont set focus to the parent, set focus to the next focus inactive + // of the parent sway_seat_set_focus(seat, container->parent); } void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { - swayc_t *last_focus = - (seat->has_focus ? sway_seat_get_focus(seat, &root_container) : NULL); + swayc_t *last_focus = sway_seat_get_focus(seat); if (container && last_focus == container) { return; @@ -314,7 +313,7 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { } } -swayc_t *sway_seat_get_focus(struct sway_seat *seat, swayc_t *container) { +swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container) { struct sway_seat_container *current = NULL; swayc_t *parent = NULL; wl_list_for_each(current, &seat->focus_stack, link) { @@ -338,6 +337,13 @@ swayc_t *sway_seat_get_focus(struct sway_seat *seat, swayc_t *container) { return NULL; } +swayc_t *sway_seat_get_focus(struct sway_seat *seat) { + if (!seat->has_focus) { + return NULL; + } + return sway_seat_get_focus_inactive(seat, &root_container); +} + void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config) { // clear configs diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index ce5b425c5..29f07f74a 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -63,8 +63,8 @@ static bool _workspace_by_name(swayc_t *view, void *data) { swayc_t *workspace_by_name(const char *name) { struct sway_seat *seat = input_manager_current_seat(input_manager); swayc_t *current_workspace = NULL, *current_output = NULL; - if (seat->has_focus) { - swayc_t *focus = sway_seat_get_focus(seat, &root_container); + swayc_t *focus = sway_seat_get_focus(seat); + if (focus) { current_workspace = swayc_parent_by_type(focus, C_WORKSPACE); current_output = swayc_parent_by_type(focus, C_OUTPUT); } @@ -103,7 +103,7 @@ swayc_t *workspace_create(const char *name) { } // Otherwise create a new one struct sway_seat *seat = input_manager_current_seat(input_manager); - swayc_t *focus = sway_seat_get_focus(seat, &root_container); + swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container); parent = focus; parent = swayc_parent_by_type(parent, C_OUTPUT); return new_workspace(parent, name); @@ -195,7 +195,7 @@ bool workspace_switch(swayc_t *workspace) { return false; } struct sway_seat *seat = input_manager_current_seat(input_manager); - swayc_t *focus = sway_seat_get_focus(seat, &root_container); + swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container); if (!seat || !focus) { return false; } From bfd2e8536485c2a8c21eadaa46d03b0709e85fcf Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 10 Feb 2018 15:15:27 -0500 Subject: [PATCH 04/36] refactor workspace.h --- include/sway/workspace.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/sway/workspace.h b/include/sway/workspace.h index 30bbdaa8a..ca6f9bdb1 100644 --- a/include/sway/workspace.h +++ b/include/sway/workspace.h @@ -1,7 +1,7 @@ #ifndef _SWAY_WORKSPACE_H #define _SWAY_WORKSPACE_H -struct sway_container; +#include extern char *prev_workspace_name; @@ -12,9 +12,9 @@ bool workspace_switch(swayc_t *workspace); struct sway_container *workspace_by_number(const char* name); swayc_t *workspace_by_name(const char*); -struct sway_container *workspace_output_next(struct sway_container *current); -struct sway_container *workspace_next(struct sway_container *current); -struct sway_container *workspace_output_prev(struct sway_container *current); -struct sway_container *workspace_prev(struct sway_container *current); +struct sway_container *workspace_output_next(swayc_t *current); +struct sway_container *workspace_next(swayc_t *current); +struct sway_container *workspace_output_prev(swayc_t *current); +struct sway_container *workspace_prev(swayc_t *current); #endif From 095ddb1561001f21b812dbe0daa5e06bc688ed98 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 10 Feb 2018 15:49:07 -0500 Subject: [PATCH 05/36] fix build for output damage --- sway/desktop/output.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a650665f4..6b6d727a8 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -125,8 +125,9 @@ static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, double width = surface->surface->current->width; double height = surface->surface->current->height; - struct wlr_xdg_surface_v6 *popup; - wl_list_for_each(popup, &surface->popups, popup_link) { + struct wlr_xdg_popup_v6 *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface_v6 *popup = popup_state->base; if (!popup->configured) { continue; } @@ -216,7 +217,12 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; struct sway_server *server = soutput->server; - wlr_output_make_current(wlr_output); + float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + wlr_renderer_clear(renderer, &clear_color); + + int buffer_age = -1; + wlr_output_make_current(wlr_output, &buffer_age); wlr_renderer_begin(server->renderer, wlr_output); swayc_t *workspace = soutput->swayc->focused; @@ -236,7 +242,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } wlr_renderer_end(server->renderer); - wlr_output_swap_buffers(wlr_output); + wlr_output_swap_buffers(wlr_output, &soutput->last_frame, NULL); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); From 145b4fdf582d3817a19819250cf01836b193c76f Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 10 Feb 2018 16:52:45 -0500 Subject: [PATCH 06/36] use bfs iterator to collect focus stack --- include/sway/container.h | 6 +++--- sway/input/seat.c | 27 ++++++++++++++++----------- sway/tree/container.c | 15 +++++++-------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/include/sway/container.h b/include/sway/container.h index 997240bd6..01e166add 100644 --- a/include/sway/container.h +++ b/include/sway/container.h @@ -163,9 +163,9 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); /** - * Get a list of containers that are descendents of the container in rendering - * order + * Apply the function for each child of the container breadth first. */ -list_t *container_list_children(swayc_t *con); +void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data), + void *data); #endif diff --git a/sway/input/seat.c b/sway/input/seat.c index d2ffca645..ab751b54b 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -70,6 +70,20 @@ static void handle_new_container(struct wl_listener *listener, void *data) { seat_container_from_container(seat, con); } +static void collect_focus_iter(swayc_t *con, void *data) { + struct sway_seat *seat = data; + if (con->type > C_WORKSPACE) { + return; + } + struct sway_seat_container *seat_con = + seat_container_from_container(seat, con); + if (!seat_con) { + return; + } + wl_list_remove(&seat_con->link); + wl_list_insert(&seat->focus_stack, &seat_con->link); +} + struct sway_seat *sway_seat_create(struct sway_input_manager *input, const char *seat_name) { struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); @@ -92,17 +106,8 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input, // init the focus stack wl_list_init(&seat->focus_stack); - list_t *containers = container_list_children(&root_container); - if (containers == NULL) { - wlr_seat_destroy(seat->wlr_seat); - free(seat); - return NULL; - } - for (int i = containers->length - 1; i >= 0; --i) { - swayc_t *con = containers->items[i]; - seat_container_from_container(seat, con); - } - free(containers); + + container_for_each_bfs(&root_container, collect_focus_iter, seat); wl_signal_add(&root_container.sway_root->events.new_container, &seat->new_container); diff --git a/sway/tree/container.c b/sway/tree/container.c index 67fac5ee5..ebf9f98e6 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -381,13 +381,13 @@ void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), voi } } -/** - * Get a list of containers that are descendents of the container in rendering - * order - */ -list_t *container_list_children(swayc_t *con) { - list_t *list = create_list(); +void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data), + void *data) { list_t *queue = create_list(); + if (queue == NULL) { + wlr_log(L_ERROR, "could not allocate list"); + return; + } list_add(queue, con); @@ -395,11 +395,10 @@ list_t *container_list_children(swayc_t *con) { while (queue->length) { current = queue->items[0]; list_del(queue, 0); - list_add(list, current); + f(current, data); // TODO floating containers list_cat(queue, current->children); } list_free(queue); - return list; } From ce3a1b3922850124c562e56ea9a783b090e969b9 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 10 Feb 2018 18:10:29 -0500 Subject: [PATCH 07/36] properly pick next focus --- sway/input/seat.c | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/sway/input/seat.c b/sway/input/seat.c index ab751b54b..2abe8a1fa 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -36,13 +36,35 @@ static void handle_seat_container_destroy(struct wl_listener *listener, void *data) { struct sway_seat_container *seat_con = wl_container_of(listener, seat_con, destroy); + struct sway_seat *seat = seat_con->seat; + swayc_t *con = seat_con->container; + + bool is_focus = (sway_seat_get_focus(seat) == con); + wl_list_remove(&seat_con->link); + + if (is_focus) { + // pick next focus + sway_seat_set_focus(seat, NULL); + swayc_t *next = sway_seat_get_focus_inactive(seat, con->parent); + if (next == NULL) { + next = con->parent; + } + sway_seat_set_focus(seat, next); + } + wl_list_remove(&seat_con->destroy.link); + free(seat_con); } static struct sway_seat_container *seat_container_from_container( struct sway_seat *seat, swayc_t *con) { + if (con->type < C_WORKSPACE) { + // these don't get seat containers ever + return NULL; + } + struct sway_seat_container *seat_con = NULL; wl_list_for_each(seat_con, &seat->focus_stack, link) { if (seat_con->container == con) { @@ -57,6 +79,7 @@ static struct sway_seat_container *seat_container_from_container( } seat_con->container = con; + seat_con->seat = seat; wl_list_insert(seat->focus_stack.prev, &seat_con->link); wl_signal_add(&con->events.destroy, &seat_con->destroy); seat_con->destroy.notify = handle_seat_container_destroy; @@ -266,14 +289,6 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) { seat->cursor->cursor->y); } -static void handle_focus_destroy(struct wl_listener *listener, void *data) { - struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy); - swayc_t *container = data; - // TODO dont set focus to the parent, set focus to the next focus inactive - // of the parent - sway_seat_set_focus(seat, container->parent); -} - void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { swayc_t *last_focus = sway_seat_get_focus(seat); @@ -281,17 +296,12 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { return; } - if (last_focus) { - wl_list_remove(&seat->focus_destroy.link); - seat->has_focus = false; - } - if (container) { struct sway_seat_container *seat_con = seat_container_from_container(seat, container); - wl_signal_add(&container->events.destroy, &seat->focus_destroy); - seat->focus_destroy.notify = handle_focus_destroy; - seat->has_focus = true; + if (!seat_con) { + return; + } wl_list_remove(&seat_con->link); wl_list_insert(&seat->focus_stack, &seat_con->link); @@ -316,15 +326,14 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { struct sway_view *view = last_focus->sway_view; view_set_activated(view, false); } + + seat->has_focus = (container != NULL); } swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container) { struct sway_seat_container *current = NULL; swayc_t *parent = NULL; wl_list_for_each(current, &seat->focus_stack, link) { - if (current->container->type < C_WORKSPACE) { - continue; - } parent = current->container->parent; if (current->container == container) { From 93084c9cf80901b160e0eb50b72a8e607289a678 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 10 Feb 2018 19:53:50 -0500 Subject: [PATCH 08/36] remove old focus member --- include/sway/container.h | 4 ---- sway/desktop/output.c | 7 ++++++- sway/ipc-json.c | 4 ++-- sway/tree/container.c | 1 - sway/tree/layout.c | 5 ----- sway/tree/workspace.c | 20 +++++++++++--------- 6 files changed, 19 insertions(+), 22 deletions(-) diff --git a/include/sway/container.h b/include/sway/container.h index 01e166add..48363be62 100644 --- a/include/sway/container.h +++ b/include/sway/container.h @@ -106,10 +106,6 @@ struct sway_container { * The parent of this container. NULL for the root container. */ struct sway_container *parent; - /** - * Which of this container's children has focus. - */ - struct sway_container *focused; /** * Number of master views in auto layouts. diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 6b6d727a8..6bbaf9381 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -225,7 +225,12 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { wlr_output_make_current(wlr_output, &buffer_age); wlr_renderer_begin(server->renderer, wlr_output); - swayc_t *workspace = soutput->swayc->focused; + struct sway_seat *seat = input_manager_current_seat(input_manager); + swayc_t *focus = sway_seat_get_focus_inactive(seat, soutput->swayc); + swayc_t *workspace = (focus->type == C_WORKSPACE ? + focus : + swayc_parent_by_type(focus, C_WORKSPACE)); + swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, soutput); // render unmanaged views on top diff --git a/sway/ipc-json.c b/sway/ipc-json.c index bab9a2014..f0afdc9f6 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -74,8 +74,8 @@ static void ipc_json_describe_output(swayc_t *container, json_object *object) { json_object_object_add(object, "refresh", json_object_new_int(wlr_output->refresh)); json_object_object_add(object, "transform", json_object_new_string(ipc_json_get_output_transform(wlr_output->transform))); - json_object_object_add(object, "current_workspace", - (container->focused) ? json_object_new_string(container->focused->name) : NULL); + // TODO WLR need to set "current_workspace" to the currently focused + // workspace in a way that makes sense with multiseat } static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) { diff --git a/sway/tree/container.c b/sway/tree/container.c index ebf9f98e6..d1fb7a79b 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -151,7 +151,6 @@ swayc_t *new_output(struct sway_output *sway_output) { char *ws_name = workspace_next_name(output->name); wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); swayc_t *ws = new_workspace(output, ws_name); - output->focused = ws; // Set each seat's focus if not already set // TODO FOCUS: this is probably stupid, we shouldn't define focus in two // places. We should probably put the active workspace on the sway_output diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 16d5cbc5d..3651d2793 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -84,8 +84,6 @@ swayc_t *add_sibling(swayc_t *fixed, swayc_t *active) { int i = index_child(fixed); list_insert(parent->children, i + 1, active); active->parent = parent; - // focus new child - parent->focused = active; return active->parent; } @@ -96,9 +94,6 @@ void add_child(swayc_t *parent, swayc_t *child) { list_add(parent->children, child); child->parent = parent; // set focus for this container - if (!parent->focused) { - parent->focused = child; - } /* TODO WLR if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) { child = new_container(child, parent->workspace_layout); diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 29f07f74a..861fda4dd 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -120,9 +120,15 @@ swayc_t *workspace_output_prev_next_impl(swayc_t *output, bool next) { return NULL; } + struct sway_seat *seat = input_manager_current_seat(input_manager); + swayc_t *focus = sway_seat_get_focus_inactive(seat, output); + swayc_t *workspace = (focus->type == C_WORKSPACE ? + focus : + swayc_parent_by_type(focus, C_WORKSPACE)); + int i; for (i = 0; i < output->children->length; i++) { - if (output->children->items[i] == output->focused) { + if (output->children->items[i] == workspace) { return output->children->items[ wrap(i + (next ? 1 : -1), output->children->length)]; } @@ -225,16 +231,12 @@ bool workspace_switch(swayc_t *workspace) { // TODO: Deal with sticky containers wlr_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); - // TODO FOCUS: Focus the last view this seat had focused on this workspace - if (workspace->children->length) { - // TODO FOCUS: This is really fucking stupid - sway_seat_set_focus(seat, workspace->children->items[0]); - } else { - sway_seat_set_focus(seat, workspace); + swayc_t *next = sway_seat_get_focus_inactive(seat, workspace); + if (next == NULL) { + next = workspace; } + sway_seat_set_focus(seat, next); swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT); - // TODO FOCUS: take a look at this - output->focused = workspace; arrange_windows(output, -1, -1); return true; } From 946d9459c57fc38b2536d40a45b7d4c9186b6734 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 14 Feb 2018 14:30:27 -0500 Subject: [PATCH 09/36] get swayc in direction --- include/sway/input/seat.h | 3 + include/sway/layout.h | 14 +++ sway/input/seat.c | 10 +++ sway/tree/layout.c | 174 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 201 insertions(+) diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 26a7e5dc2..f9244f432 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -60,6 +60,9 @@ swayc_t *sway_seat_get_focus(struct sway_seat *seat); swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container); +swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat, + enum swayc_types type); + void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); #endif diff --git a/include/sway/layout.h b/include/sway/layout.h index 69a666741..e82c4442a 100644 --- a/include/sway/layout.h +++ b/include/sway/layout.h @@ -4,6 +4,18 @@ #include #include "sway/container.h" +enum movement_direction { + MOVE_LEFT, + MOVE_RIGHT, + MOVE_UP, + MOVE_DOWN, + MOVE_PARENT, + MOVE_CHILD, + MOVE_NEXT, + MOVE_PREV, + MOVE_FIRST +}; + struct sway_container; struct sway_root { @@ -25,5 +37,7 @@ struct sway_container *remove_child(struct sway_container *child); enum swayc_layouts default_layout(struct sway_container *output); void sort_workspaces(struct sway_container *output); void arrange_windows(struct sway_container *container, double width, double height); +swayc_t *get_swayc_in_direction(swayc_t *container, + struct sway_seat *seat, enum movement_direction dir); #endif diff --git a/sway/input/seat.c b/sway/input/seat.c index 2abe8a1fa..648e79143 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -358,6 +358,16 @@ swayc_t *sway_seat_get_focus(struct sway_seat *seat) { return sway_seat_get_focus_inactive(seat, &root_container); } +swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat, + enum swayc_types type) { + swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container); + if (focus->type == type) { + return focus; + } + + return swayc_parent_by_type(focus, type); +} + void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config) { // clear configs diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 3651d2793..9768279ae 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -10,6 +10,7 @@ #include "sway/layout.h" #include "sway/output.h" #include "sway/view.h" +#include "sway/input/seat.h" #include "list.h" #include "log.h" @@ -346,3 +347,176 @@ void apply_vert_layout(swayc_t *container, */ } } + +/** + * Get swayc in the direction of newly entered output. + */ +static swayc_t *get_swayc_in_output_direction(swayc_t *output, + enum movement_direction dir, struct sway_seat *seat) { + // XXX is this really a seat function or can we do it with the default + // seat? + if (!output) { + return NULL; + } + + swayc_t *ws = sway_seat_get_focus_inactive(seat, output); + if (ws->type != C_WORKSPACE) { + ws = swayc_parent_by_type(ws, C_WORKSPACE); + } + + if (ws && ws->children->length > 0) { + switch (dir) { + case MOVE_LEFT: + // get most right child of new output + return ws->children->items[ws->children->length-1]; + case MOVE_RIGHT: + // get most left child of new output + return ws->children->items[0]; + case MOVE_UP: + case MOVE_DOWN: + { + swayc_t *focused = sway_seat_get_focus_inactive(seat, ws); + if (focused && focused->parent) { + swayc_t *parent = focused->parent; + if (parent->layout == L_VERT) { + if (dir == MOVE_UP) { + // get child furthest down on new output + return parent->children->items[parent->children->length-1]; + } else if (dir == MOVE_DOWN) { + // get child furthest up on new output + return parent->children->items[0]; + } + } + return focused; + } + break; + } + default: + break; + } + } + + return output; +} + +static void get_absolute_center_position(swayc_t *container, int *x, int *y) { + *x = container->x + container->width/2; + *y = container->y + container->height/2; +} + +static swayc_t *get_swayc_in_direction_under(swayc_t *container, + enum movement_direction dir, struct sway_seat *seat, swayc_t *limit) { + if (dir == MOVE_CHILD) { + return sway_seat_get_focus_inactive(seat, container); + } + + swayc_t *parent = container->parent; + if (dir == MOVE_PARENT) { + if (parent->type == C_OUTPUT) { + return NULL; + } else { + return parent; + } + } + + 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_absolute_center_position(container, &abs_pos); + + + // TODO WLR fullscreen + /* + if (container->type == C_VIEW && swayc_is_fullscreen(container)) { + wlr_log(L_DEBUG, "Moving from fullscreen view, skipping to output"); + container = swayc_parent_by_type(container, C_OUTPUT); + get_absolute_center_position(container, &abs_pos); + swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true); + return get_swayc_in_output_direction(output, dir); + } + if (container->type == C_WORKSPACE && container->fullscreen) { + sway_log(L_DEBUG, "Moving to fullscreen view"); + return container->fullscreen; + } + */ + + swayc_t *wrap_candidate = NULL; + while (true) { + // Test if we can even make a difference here + bool can_move = false; + int desired; + int idx = index_child(container); + if (parent->type == C_ROOT) { + struct wlr_output_layout *layout = root_container.sway_root->output_layout; + wlr_output_layout_adjacent_output(layout, container->sway_output->wlr_output); + //swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true); + if (!output || output == container) { + return wrap_candidate; + } + wlr_log(L_DEBUG, "Moving between outputs"); + return get_swayc_in_output_direction(output, dir, seat); + } else { + if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { + if (parent->layout == L_HORIZ || parent->layout == L_TABBED) { + can_move = true; + desired = idx + (dir == MOVE_LEFT ? -1 : 1); + } + } else { + if (parent->layout == L_VERT || parent->layout == L_STACKED) { + can_move = true; + desired = idx + (dir == MOVE_UP ? -1 : 1); + } + } + } + + if (can_move) { + // TODO handle floating + if (desired < 0 || desired >= parent->children->length) { + can_move = false; + int len = parent->children->length; + if (!wrap_candidate && len > 1) { + if (desired < 0) { + wrap_candidate = parent->children->items[len-1]; + } else { + wrap_candidate = parent->children->items[0]; + } + if (config->force_focus_wrapping) { + return wrap_candidate; + } + } + } else { + wlr_log(L_DEBUG, "%s cont %d-%p dir %i sibling %d: %p", __func__, + idx, container, dir, desired, parent->children->items[desired]); + return parent->children->items[desired]; + } + } + + if (!can_move) { + container = parent; + parent = parent->parent; + if (!parent || container == limit) { + // wrapping is the last chance + return wrap_candidate; + } + } + } +} + +swayc_t *get_swayc_in_direction(swayc_t *container, struct sway_seat *seat, + enum movement_direction dir) { + return get_swayc_in_direction_under(container, dir, seat, NULL); +} From 06c71f115bb0632ef1e75d881d509665198e1eef Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 14 Feb 2018 14:42:06 -0500 Subject: [PATCH 10/36] input device destroy --- include/sway/input/input-manager.h | 1 + sway/input/input-manager.c | 61 +++++++++++++++--------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 66ace2626..a76c38807 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -16,6 +16,7 @@ struct sway_input_device { struct wlr_input_device *wlr_device; struct input_config *config; struct wl_list link; + struct wl_listener device_destroy; }; struct sway_input_manager { diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index d789c7eb8..f59daea32 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -160,7 +160,32 @@ static void sway_input_manager_libinput_config_pointer(struct sway_input_device } } -static void input_add_notify(struct wl_listener *listener, void *data) { +static void handle_device_destroy(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + + struct sway_input_device *input_device = + input_sway_device_from_wlr(input_manager, device); + + if (!sway_assert(input_device, "could not find sway device")) { + return; + } + + wlr_log(L_DEBUG, "removing device: '%s'", + input_device->identifier); + + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input_manager->seats, link) { + sway_seat_remove_device(seat, input_device); + } + + wl_list_remove(&input_device->link); + wl_list_remove(&input_device->device_destroy.link); + free_input_config(input_device->config); + free(input_device->identifier); + free(input_device); +} + +static void handle_new_input(struct wl_listener *listener, void *data) { struct sway_input_manager *input = wl_container_of(listener, input, input_add); struct wlr_input_device *device = data; @@ -226,32 +251,9 @@ static void input_add_notify(struct wl_listener *listener, void *data) { "device '%s' is not configured on any seats", input_device->identifier); } -} -static void input_remove_notify(struct wl_listener *listener, void *data) { - struct sway_input_manager *input = - wl_container_of(listener, input, input_remove); - struct wlr_input_device *device = data; - - struct sway_input_device *input_device = - input_sway_device_from_wlr(input, device); - - if (!sway_assert(input_device, "could not find sway device")) { - return; - } - - wlr_log(L_DEBUG, "removing device: '%s'", - input_device->identifier); - - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &input->seats, link) { - sway_seat_remove_device(seat, input_device); - } - - wl_list_remove(&input_device->link); - free_input_config(input_device->config); - free(input_device->identifier); - free(input_device); + wl_signal_add(&device->events.destroy, &input_device->device_destroy); + input_device->device_destroy.notify = handle_device_destroy; } struct sway_input_manager *sway_input_manager_create( @@ -269,11 +271,8 @@ struct sway_input_manager *sway_input_manager_create( // create the default seat input_manager_get_seat(input, default_seat); - input->input_add.notify = input_add_notify; - wl_signal_add(&server->backend->events.input_add, &input->input_add); - - input->input_remove.notify = input_remove_notify; - wl_signal_add(&server->backend->events.input_remove, &input->input_remove); + input->input_add.notify = handle_new_input; + wl_signal_add(&server->backend->events.new_input, &input->input_add); return input; } From 7dfbf06de9a5659d4c73edf53c38ee07068a2877 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 14 Feb 2018 14:51:51 -0500 Subject: [PATCH 11/36] output destroy --- include/sway/output.h | 1 + include/sway/server.h | 7 +++---- sway/desktop/output.c | 12 +++++++----- sway/server.c | 8 ++------ sway/tree/container.c | 2 ++ 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index 7ca02d7b5..95d647052 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -14,6 +14,7 @@ struct sway_output { struct timespec last_frame; struct wl_listener frame; + struct wl_listener output_destroy; }; #endif diff --git a/include/sway/server.h b/include/sway/server.h index d497e1328..1600babee 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -24,8 +24,7 @@ struct sway_server { struct sway_input_manager *input; - struct wl_listener output_add; - struct wl_listener output_remove; + struct wl_listener new_output; struct wl_listener output_frame; struct wlr_xdg_shell_v6 *xdg_shell_v6; @@ -45,8 +44,8 @@ bool server_init(struct sway_server *server); void server_fini(struct sway_server *server); void server_run(struct sway_server *server); -void output_add_notify(struct wl_listener *listener, void *data); -void output_remove_notify(struct wl_listener *listener, void *data); +void handle_new_output(struct wl_listener *listener, void *data); +void handle_output_destroy(struct wl_listener *listener, void *data); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); void handle_xwayland_surface(struct wl_listener *listener, void *data); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a650665f4..16183870f 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -243,8 +243,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { soutput->last_frame = now; } -void output_add_notify(struct wl_listener *listener, void *data) { - struct sway_server *server = wl_container_of(listener, server, output_add); +void handle_new_output(struct wl_listener *listener, void *data) { + struct sway_server *server = wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; wlr_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); @@ -269,12 +269,14 @@ void output_add_notify(struct wl_listener *listener, void *data) { sway_input_manager_configure_xcursor(input_manager); - output->frame.notify = output_frame_notify; wl_signal_add(&wlr_output->events.frame, &output->frame); + output->frame.notify = output_frame_notify; + + wl_signal_add(&wlr_output->events.destroy, &output->output_destroy); + output->output_destroy.notify = handle_output_destroy; } -void output_remove_notify(struct wl_listener *listener, void *data) { - struct sway_server *server = wl_container_of(listener, server, output_remove); +void handle_output_destroy(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); diff --git a/sway/server.c b/sway/server.c index b5eb510be..0753d37e7 100644 --- a/sway/server.c +++ b/sway/server.c @@ -48,12 +48,8 @@ bool server_init(struct sway_server *server) { server->data_device_manager = wlr_data_device_manager_create(server->wl_display); - server->output_add.notify = output_add_notify; - wl_signal_add(&server->backend->events.output_add, &server->output_add); - - server->output_remove.notify = output_remove_notify; - wl_signal_add(&server->backend->events.output_remove, - &server->output_remove); + server->new_output.notify = handle_new_output; + wl_signal_add(&server->backend->events.new_output, &server->new_output); server->xdg_shell_v6 = wlr_xdg_shell_v6_create(server->wl_display); wl_signal_add(&server->xdg_shell_v6->events.new_surface, diff --git a/sway/tree/container.c b/sway/tree/container.c index 48aabd865..1a468c199 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -235,6 +235,8 @@ swayc_t *destroy_output(swayc_t *output) { } } + wl_list_remove(&output->sway_output->output_destroy.link); + wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); free_swayc(output); From c6cb87be19dba185e32af59e1e7fd1217a15c08b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 14 Feb 2018 14:55:38 -0500 Subject: [PATCH 12/36] output damage fix --- sway/desktop/output.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 16183870f..a66601b56 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -125,8 +125,9 @@ static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, double width = surface->surface->current->width; double height = surface->surface->current->height; - struct wlr_xdg_surface_v6 *popup; - wl_list_for_each(popup, &surface->popups, popup_link) { + struct wlr_xdg_popup_v6 *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface_v6 *popup = popup_state->base; if (!popup->configured) { continue; } @@ -215,8 +216,13 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct sway_output *soutput = wl_container_of(listener, soutput, frame); struct wlr_output *wlr_output = data; struct sway_server *server = soutput->server; + float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + wlr_renderer_clear(renderer, &clear_color); - wlr_output_make_current(wlr_output); + int buffer_age = -1; + wlr_output_make_current(wlr_output, &buffer_age); + wlr_renderer_begin(server->renderer, wlr_output); wlr_renderer_begin(server->renderer, wlr_output); swayc_t *workspace = soutput->swayc->focused; @@ -236,7 +242,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } wlr_renderer_end(server->renderer); - wlr_output_swap_buffers(wlr_output); + wlr_output_swap_buffers(wlr_output, &soutput->last_frame, NULL); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); From 780d9fe1e3ee051a4d9eb08d1c049e19d72c1d6a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 14 Feb 2018 15:23:56 -0500 Subject: [PATCH 13/36] cleanup layout.c --- sway/tree/layout.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 205f42eb5..5e8f4c562 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -173,8 +173,8 @@ void arrange_windows(swayc_t *container, double width, double height) { height = floor(height); wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", container, - container->name, container->width, container->height, container->x, - container->y); + container->name, container->width, container->height, container->x, + container->y); double x = 0, y = 0; switch (container->type) { @@ -275,8 +275,8 @@ static void apply_horiz_layout(swayc_t *container, for (int i = start; i < end; ++i) { swayc_t *child = container->children->items[i]; wlr_log(L_DEBUG, - "Calculating arrangement for %p:%d (will scale %f by %f)", - child, child->type, width, scale); + "Calculating arrangement for %p:%d (will scale %f by %f)", + child, child->type, width, scale); view_set_position(child->sway_view, child_x, y); if (i == end - 1) { @@ -325,8 +325,8 @@ void apply_vert_layout(swayc_t *container, for (i = start; i < end; ++i) { swayc_t *child = container->children->items[i]; wlr_log(L_DEBUG, - "Calculating arrangement for %p:%d (will scale %f by %f)", - child, child->type, height, scale); + "Calculating arrangement for %p:%d (will scale %f by %f)", + child, child->type, height, scale); view_set_position(child->sway_view, x, child_y); if (i == end - 1) { @@ -373,24 +373,23 @@ static swayc_t *get_swayc_in_output_direction(swayc_t *output, // get most left child of new output return ws->children->items[0]; case MOVE_UP: - case MOVE_DOWN: - { - swayc_t *focused = sway_seat_get_focus_inactive(seat, ws); - if (focused && focused->parent) { - swayc_t *parent = focused->parent; - if (parent->layout == L_VERT) { - if (dir == MOVE_UP) { - // get child furthest down on new output - return parent->children->items[parent->children->length-1]; - } else if (dir == MOVE_DOWN) { - // get child furthest up on new output - return parent->children->items[0]; - } + case MOVE_DOWN: { + swayc_t *focused = sway_seat_get_focus_inactive(seat, ws); + if (focused && focused->parent) { + swayc_t *parent = focused->parent; + if (parent->layout == L_VERT) { + if (dir == MOVE_UP) { + // get child furthest down on new output + return parent->children->items[parent->children->length-1]; + } else if (dir == MOVE_DOWN) { + // get child furthest up on new output + return parent->children->items[0]; } - return focused; } - break; + return focused; } + break; + } default: break; } From 52670c636cf5115560ce6d20e2aaab1d55c49d0b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 14 Feb 2018 16:47:23 -0500 Subject: [PATCH 14/36] basic focus (without direction) --- sway/commands.c | 1 + sway/commands/focus.c | 32 ++++++++++++++++++++++++++++++++ sway/ipc-server.c | 1 + sway/meson.build | 1 + 4 files changed, 35 insertions(+) create mode 100644 sway/commands/focus.c diff --git a/sway/commands.c b/sway/commands.c index d8d29a1cf..bc2a85d7f 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -132,6 +132,7 @@ static struct cmd_handler handlers[] = { { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, { "exit", cmd_exit }, + { "focus", cmd_focus }, { "include", cmd_include }, { "input", cmd_input }, { "kill", cmd_kill }, diff --git a/sway/commands/focus.c b/sway/commands/focus.c new file mode 100644 index 000000000..5286851fb --- /dev/null +++ b/sway/commands/focus.c @@ -0,0 +1,32 @@ +#include +#include "log.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "sway/view.h" +#include "sway/commands.h" + +struct cmd_results *cmd_focus(int argc, char **argv) { + swayc_t *con = config->handler_context.current_container; + struct sway_seat *seat = config->handler_context.seat; + + if (!sway_assert(seat, "'focus' command called without seat context")) { + return cmd_results_new(CMD_FAILURE, "focus", + "Command 'focus' called without seat context (this is a bug in sway)"); + } + + if (config->reading) { + return cmd_results_new(CMD_FAILURE, "focus", + "Command 'focus' cannot be used in the config file"); + } + if (con == NULL) { + wlr_log(L_DEBUG, "no container to focus"); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + + if (argc == 0) { + sway_seat_set_focus(seat, con); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/ipc-server.c b/sway/ipc-server.c index a16a2b806..ee259c990 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -336,6 +336,7 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_COMMAND: { config_clear_handler_context(config); + config->handler_context.seat = input_manager_current_seat(input_manager); struct cmd_results *results = handle_command(buf); const char *json = cmd_results_to_json(results); char reply[256]; diff --git a/sway/meson.build b/sway/meson.build index 271d4a998..8d5a97d2e 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -10,6 +10,7 @@ sway_sources = files( 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', + 'commands/focus.c', 'commands/kill.c', 'commands/include.c', 'commands/input.c', From a3ae67af4e47467b134b876e42a148b1895e7283 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 14 Feb 2018 17:12:21 -0500 Subject: [PATCH 15/36] basic focus in direction --- sway/commands/focus.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 5286851fb..ba47d1e13 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -1,3 +1,4 @@ +#include #include #include "log.h" #include "sway/input/input-manager.h" @@ -5,6 +6,30 @@ #include "sway/view.h" #include "sway/commands.h" +static bool parse_movement_direction(const char *name, enum movement_direction *out) { + if (strcasecmp(name, "left") == 0) { + *out = MOVE_LEFT; + } else if (strcasecmp(name, "right") == 0) { + *out = MOVE_RIGHT; + } else if (strcasecmp(name, "up") == 0) { + *out = MOVE_UP; + } else if (strcasecmp(name, "down") == 0) { + *out = MOVE_DOWN; + } else if (strcasecmp(name, "parent") == 0) { + *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; + } + + return true; +} + struct cmd_results *cmd_focus(int argc, char **argv) { swayc_t *con = config->handler_context.current_container; struct sway_seat *seat = config->handler_context.seat; @@ -22,11 +47,27 @@ struct cmd_results *cmd_focus(int argc, char **argv) { wlr_log(L_DEBUG, "no container to focus"); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } + if (con->type < C_WORKSPACE) { + return cmd_results_new(CMD_FAILURE, "focus", + "Command 'focus' cannot be used above the workspace level"); + } if (argc == 0) { sway_seat_set_focus(seat, con); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } + // TODO mode_toggle + enum movement_direction direction = 0; + if (!parse_movement_direction(argv[0], &direction)) { + return cmd_results_new(CMD_INVALID, "focus", + "Expected 'focus ' or 'focus output '"); + } + + swayc_t *next_focus = get_swayc_in_direction(con, seat, direction); + if (next_focus) { + sway_seat_set_focus(seat, next_focus); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } From 9510a20fcda00eecf077cc5cb06f5d47d87bccee Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 17 Feb 2018 13:32:04 -0500 Subject: [PATCH 16/36] arrange windows after output add --- sway/desktop/output.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index e250d4505..ba282c2ce 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -286,6 +286,8 @@ void handle_new_output(struct wl_listener *listener, void *data) { wl_signal_add(&wlr_output->events.destroy, &output->output_destroy); output->output_destroy.notify = handle_output_destroy; + + arrange_windows(&root_container, -1, -1); } void handle_output_destroy(struct wl_listener *listener, void *data) { From 7c089442c3c9877eec2422780f6ce57315de2d11 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 17 Feb 2018 15:18:21 -0500 Subject: [PATCH 17/36] use box projection function --- sway/desktop/output.c | 43 +------------------------------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index ba282c2ce..7b7fcbb9d 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -57,46 +57,7 @@ static void render_surface(struct wlr_surface *surface, }; if (wlr_output_layout_intersects(layout, wlr_output, &render_box)) { float matrix[16]; - - float translate_center[16]; - wlr_matrix_translate(&translate_center, - (int)ox + render_width / 2, (int)oy + render_height / 2, 0); - - float rotate[16]; - wlr_matrix_rotate(&rotate, rotation); - - float translate_origin[16]; - wlr_matrix_translate(&translate_origin, -render_width / 2, - -render_height / 2, 0); - - float scale[16]; - wlr_matrix_scale(&scale, render_width, render_height, 1); - - float transform[16]; - wlr_matrix_mul(&translate_center, &rotate, &transform); - wlr_matrix_mul(&transform, &translate_origin, &transform); - wlr_matrix_mul(&transform, &scale, &transform); - - if (surface->current->transform != WL_OUTPUT_TRANSFORM_NORMAL) { - float surface_translate_center[16]; - wlr_matrix_translate(&surface_translate_center, 0.5, 0.5, 0); - - float surface_transform[16]; - wlr_matrix_transform(surface_transform, - wlr_output_transform_invert(surface->current->transform)); - - float surface_translate_origin[16]; - wlr_matrix_translate(&surface_translate_origin, -0.5, -0.5, 0); - - wlr_matrix_mul(&transform, &surface_translate_center, - &transform); - wlr_matrix_mul(&transform, &surface_transform, &transform); - wlr_matrix_mul(&transform, &surface_translate_origin, - &transform); - } - - wlr_matrix_mul(&wlr_output->transform_matrix, &transform, &matrix); - + wlr_matrix_project_box(&matrix, &render_box, surface->current->transform, 0, &wlr_output->transform_matrix); wlr_render_with_matrix(server.renderer, surface->texture, &matrix); @@ -220,8 +181,6 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); wlr_renderer_clear(renderer, &clear_color); - wlr_renderer_clear(renderer, &clear_color); - int buffer_age = -1; wlr_output_make_current(wlr_output, &buffer_age); wlr_renderer_begin(server->renderer, wlr_output); From 80927985fbb40e0bdf2a3c4322d808a9681cca6a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 17 Feb 2018 16:30:32 -0500 Subject: [PATCH 18/36] fix output rendering issue --- sway/desktop/output.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 7b7fcbb9d..a3d9efd87 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -46,18 +46,22 @@ static void render_surface(struct wlr_surface *surface, int height = surface->current->height; int render_width = width * wlr_output->scale; int render_height = height * wlr_output->scale; - double ox = lx, oy = ly; - wlr_output_layout_output_coords(layout, wlr_output, &ox, &oy); - ox *= wlr_output->scale; - oy *= wlr_output->scale; + int owidth, oheight; + wlr_output_effective_resolution(wlr_output, &owidth, &oheight); - struct wlr_box render_box = { - .x = lx, .y = ly, + // FIXME: view coords are inconsistently assumed to be in output or layout coords + struct wlr_box layout_box = { + .x = lx + owidth, .y = ly + oheight, .width = render_width, .height = render_height, }; - if (wlr_output_layout_intersects(layout, wlr_output, &render_box)) { + if (wlr_output_layout_intersects(layout, wlr_output, &layout_box)) { + struct wlr_box render_box = { + .x = lx, .y = ly, + .width = render_width, .height = render_height + }; float matrix[16]; - wlr_matrix_project_box(&matrix, &render_box, surface->current->transform, 0, &wlr_output->transform_matrix); + wlr_matrix_project_box(&matrix, &render_box, + surface->current->transform, 0, &wlr_output->transform_matrix); wlr_render_with_matrix(server.renderer, surface->texture, &matrix); From fb37e802252b35fd63c68df6b19549b715474821 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 17 Feb 2018 18:33:02 -0500 Subject: [PATCH 19/36] basic move focus in direction across outputs --- sway/tree/layout.c | 86 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 5e8f4c562..6a5743039 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -398,9 +398,58 @@ static swayc_t *get_swayc_in_output_direction(swayc_t *output, return output; } -static void get_absolute_center_position(swayc_t *container, int *x, int *y) { - *x = container->x + container->width/2; - *y = container->y + container->height/2; +static void get_layout_center_position(swayc_t *container, int *x, int *y) { + // FIXME view coords are inconsistently referred to in layout/output systems + if (container->type == C_OUTPUT) { + *x = container->x + container->width/2; + *y = container->y + container->height/2; + } else { + swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); + if (container->type == C_WORKSPACE) { + // Workspace coordinates are actually wrong/arbitrary, but should + // be same as output. + *x = output->x; + *y = output->y; + } else { + *x = output->x + container->x; + *y = output->y + container->y; + } + } +} + +static bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out) { + *out = 0; + switch (dir) { + case MOVE_UP: + *out = WLR_DIRECTION_UP; + break; + case MOVE_DOWN: + *out = WLR_DIRECTION_DOWN; + break; + case MOVE_LEFT: + *out = WLR_DIRECTION_LEFT; + break; + case MOVE_RIGHT: + *out = WLR_DIRECTION_RIGHT; + break; + default: + break; + } + + return *out != 0; +} + +static swayc_t *sway_output_from_wlr(struct wlr_output *output) { + if (output == NULL) { + return NULL; + } + for (int i = 0; i < root_container.children->length; ++i) { + swayc_t *o = root_container.children->items[i]; + if (o->type == C_OUTPUT && o->sway_output->wlr_output == output) { + return o; + } + } + return NULL; } static swayc_t *get_swayc_in_direction_under(swayc_t *container, @@ -435,7 +484,7 @@ static swayc_t *get_swayc_in_direction_under(swayc_t *container, // 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_absolute_center_position(container, &abs_pos); + //get_layout_center_position(container, &abs_pos); // TODO WLR fullscreen @@ -443,7 +492,7 @@ static swayc_t *get_swayc_in_direction_under(swayc_t *container, if (container->type == C_VIEW && swayc_is_fullscreen(container)) { wlr_log(L_DEBUG, "Moving from fullscreen view, skipping to output"); container = swayc_parent_by_type(container, C_OUTPUT); - get_absolute_center_position(container, &abs_pos); + get_layout_center_position(container, &abs_pos); swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true); return get_swayc_in_output_direction(output, dir); } @@ -460,17 +509,28 @@ static swayc_t *get_swayc_in_direction_under(swayc_t *container, int desired; int idx = index_child(container); if (parent->type == C_ROOT) { - // TODO - /* + enum wlr_direction wlr_dir = 0; + if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir), + "got invalid direction: %d", dir)) { + return NULL; + } + int lx, ly; + get_layout_center_position(container, &lx, &ly); struct wlr_output_layout *layout = root_container.sway_root->output_layout; - wlr_output_layout_adjacent_output(layout, container->sway_output->wlr_output); - //swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true); - if (!output || output == container) { + struct wlr_output *wlr_adjacent = + wlr_output_layout_adjacent_output(layout, wlr_dir, + container->sway_output->wlr_output, lx, ly); + swayc_t *adjacent = sway_output_from_wlr(wlr_adjacent); + + if (!adjacent || adjacent == container) { return wrap_candidate; } - wlr_log(L_DEBUG, "Moving between outputs"); - return get_swayc_in_output_direction(output, dir, seat); - */ + // TODO descend into the focus-inactive of the physically closest + // view of the output + //swayc_t *new_con = get_swayc_in_output_direction(adjacent, dir, seat); + swayc_t *new_con = sway_seat_get_focus_inactive(seat, adjacent); + return new_con; + } else { if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { if (parent->layout == L_HORIZ || parent->layout == L_TABBED) { From 176d24f02dfaa0a7866dd4ea278d0cbf30fa23bb Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 17 Feb 2018 19:03:21 -0500 Subject: [PATCH 20/36] choose adjacent container between outputs --- sway/tree/layout.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 6a5743039..be494791c 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -364,7 +364,12 @@ static swayc_t *get_swayc_in_output_direction(swayc_t *output, ws = swayc_parent_by_type(ws, C_WORKSPACE); } - if (ws && ws->children->length > 0) { + if (ws == NULL) { + wlr_log(L_ERROR, "got an output without a workspace"); + return NULL; + } + + if (ws->children->length > 0) { switch (dir) { case MOVE_LEFT: // get most right child of new output @@ -395,7 +400,7 @@ static swayc_t *get_swayc_in_output_direction(swayc_t *output, } } - return output; + return ws; } static void get_layout_center_position(swayc_t *container, int *x, int *y) { @@ -525,12 +530,13 @@ static swayc_t *get_swayc_in_direction_under(swayc_t *container, if (!adjacent || adjacent == container) { return wrap_candidate; } - // TODO descend into the focus-inactive of the physically closest - // view of the output - //swayc_t *new_con = get_swayc_in_output_direction(adjacent, dir, seat); - swayc_t *new_con = sway_seat_get_focus_inactive(seat, adjacent); - return new_con; - + swayc_t *next = get_swayc_in_output_direction(adjacent, dir, seat); + if (next->children->length) { + // TODO consider floating children as well + return sway_seat_get_focus_inactive(seat, next); + } else { + return next; + } } else { if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { if (parent->layout == L_HORIZ || parent->layout == L_TABBED) { From f0ca2cb5c367a0142b6988d04c6b996f1c296055 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 17 Feb 2018 19:05:17 -0500 Subject: [PATCH 21/36] use quotes for container include --- include/sway/workspace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sway/workspace.h b/include/sway/workspace.h index ca6f9bdb1..fee54255c 100644 --- a/include/sway/workspace.h +++ b/include/sway/workspace.h @@ -1,7 +1,7 @@ #ifndef _SWAY_WORKSPACE_H #define _SWAY_WORKSPACE_H -#include +#include "sway/container.h" extern char *prev_workspace_name; From 5e9fe97e36b5e33b9919c2cfee776fc8eac05959 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 18 Feb 2018 11:20:18 -0500 Subject: [PATCH 22/36] Add -Wno-unused-function This is temporary, it helps while we work on porting and large swaths of the code are commented out. --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 493921263..fc995c815 100644 --- a/meson.build +++ b/meson.build @@ -10,6 +10,7 @@ project( ) add_project_arguments('-Wno-unused-parameter', language: 'c') +add_project_arguments('-Wno-unused-function', language: 'c') cc = meson.get_compiler('c') From b88f06e70a62722e70855772dcfa5b20b3a10291 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 19 Feb 2018 17:55:16 -0500 Subject: [PATCH 23/36] bugfix: get right layout box for rendering views --- sway/desktop/output.c | 2 +- sway/tree/layout.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a3d9efd87..039aba254 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -51,7 +51,7 @@ static void render_surface(struct wlr_surface *surface, // FIXME: view coords are inconsistently assumed to be in output or layout coords struct wlr_box layout_box = { - .x = lx + owidth, .y = ly + oheight, + .x = lx + wlr_output->lx, .y = ly + wlr_output->ly, .width = render_width, .height = render_height, }; if (wlr_output_layout_intersects(layout, wlr_output, &layout_box)) { diff --git a/sway/tree/layout.c b/sway/tree/layout.c index be494791c..3c78b6bc5 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -531,7 +531,10 @@ static swayc_t *get_swayc_in_direction_under(swayc_t *container, return wrap_candidate; } swayc_t *next = get_swayc_in_output_direction(adjacent, dir, seat); - if (next->children->length) { + if (next == NULL) { + return NULL; + } + if (next->children && next->children->length) { // TODO consider floating children as well return sway_seat_get_focus_inactive(seat, next); } else { From 66a975038c2f6cc3d2ebb5210d182b0440bc0a88 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 20 Feb 2018 19:01:02 -0500 Subject: [PATCH 24/36] add doc to sway_seat_get_focus_inactive() --- include/sway/input/seat.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index f9244f432..1d55bec7a 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -58,6 +58,15 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container); swayc_t *sway_seat_get_focus(struct sway_seat *seat); +/** + * Return the last container to be focused for the seat (or the most recently + * opened if no container has received focused) that is a child of the given + * container. The focus-inactive container of the root window is the focused + * container for the seat (if the seat does have focus). This function can be + * used to determine what container gets focused next if the focused container + * is destroyed, or focus moves to a container with children and we need to + * descend into the next leaf in focus order. + */ swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container); swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat, From 4c4cc9c99943b4f80f1551c421b372b016dd04e6 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 20 Feb 2018 19:04:03 -0500 Subject: [PATCH 25/36] remove old comments --- sway/tree/container.c | 3 --- sway/tree/layout.c | 2 -- 2 files changed, 5 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index a62681333..84e14ba69 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -152,9 +152,6 @@ swayc_t *new_output(struct sway_output *sway_output) { wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); swayc_t *ws = new_workspace(output, ws_name); // Set each seat's focus if not already set - // TODO FOCUS: this is probably stupid, we shouldn't define focus in two - // places. We should probably put the active workspace on the sway_output - // struct instead of trying to do focus semantics like this struct sway_seat *seat = NULL; wl_list_for_each(seat, &input_manager->seats, link) { if (!seat->has_focus) { diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 3c78b6bc5..91f0f36f5 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -353,8 +353,6 @@ void apply_vert_layout(swayc_t *container, */ static swayc_t *get_swayc_in_output_direction(swayc_t *output, enum movement_direction dir, struct sway_seat *seat) { - // XXX is this really a seat function or can we do it with the default - // seat? if (!output) { return NULL; } From 316effd7b1f6b60f70038f9a5df5d58eb879cf90 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 20 Feb 2018 19:06:56 -0500 Subject: [PATCH 26/36] make handle_output_destroy() static --- include/sway/server.h | 1 - sway/desktop/output.c | 40 ++++++++++++++++++++-------------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/include/sway/server.h b/include/sway/server.h index 1600babee..3fcdb1baf 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -45,7 +45,6 @@ void server_fini(struct sway_server *server); void server_run(struct sway_server *server); void handle_new_output(struct wl_listener *listener, void *data); -void handle_output_destroy(struct wl_listener *listener, void *data); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); void handle_xwayland_surface(struct wl_listener *listener, void *data); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 039aba254..8e0daeeaf 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -218,6 +218,26 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { soutput->last_frame = now; } +static void handle_output_destroy(struct wl_listener *listener, void *data) { + struct wlr_output *wlr_output = data; + wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); + + swayc_t *output_container = NULL; + for (int i = 0 ; i < root_container.children->length; ++i) { + swayc_t *child = root_container.children->items[i]; + if (child->type == C_OUTPUT && + child->sway_output->wlr_output == wlr_output) { + output_container = child; + break; + } + } + if (!output_container) { + return; + } + + destroy_output(output_container); +} + void handle_new_output(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; @@ -252,23 +272,3 @@ void handle_new_output(struct wl_listener *listener, void *data) { arrange_windows(&root_container, -1, -1); } - -void handle_output_destroy(struct wl_listener *listener, void *data) { - struct wlr_output *wlr_output = data; - wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); - - swayc_t *output_container = NULL; - for (int i = 0 ; i < root_container.children->length; ++i) { - swayc_t *child = root_container.children->items[i]; - if (child->type == C_OUTPUT && - child->sway_output->wlr_output == wlr_output) { - output_container = child; - break; - } - } - if (!output_container) { - return; - } - - destroy_output(output_container); -} From 4b3aa59b8bfaa5d6136b54ba7f347f5d93fa210f Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 20 Feb 2018 19:09:38 -0500 Subject: [PATCH 27/36] rename new_input listener on input-manager --- include/sway/input/input-manager.h | 4 ++-- sway/input/input-manager.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index a76c38807..eab7dc90f 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -20,11 +20,11 @@ struct sway_input_device { }; struct sway_input_manager { - struct wl_listener input_add; - struct wl_listener input_remove; struct sway_server *server; struct wl_list devices; struct wl_list seats; + + struct wl_listener new_input; }; struct sway_input_manager *sway_input_manager_create( diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index e6708bade..27c2c72eb 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -187,7 +187,7 @@ static void handle_device_destroy(struct wl_listener *listener, void *data) { static void handle_new_input(struct wl_listener *listener, void *data) { struct sway_input_manager *input = - wl_container_of(listener, input, input_add); + wl_container_of(listener, input, new_input); struct wlr_input_device *device = data; struct sway_input_device *input_device = @@ -271,8 +271,8 @@ struct sway_input_manager *sway_input_manager_create( // create the default seat input_manager_get_seat(input, default_seat); - input->input_add.notify = handle_new_input; - wl_signal_add(&server->backend->events.new_input, &input->input_add); + input->new_input.notify = handle_new_input; + wl_signal_add(&server->backend->events.new_input, &input->new_input); return input; } From 23e9f5dc350b8d1f399ffe2e5b761f21dc9c46a8 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 20 Feb 2018 19:21:32 -0500 Subject: [PATCH 28/36] use wl_container_of() in output destroy callback --- sway/desktop/output.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 8e0daeeaf..63420d0cc 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -219,23 +219,11 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } static void handle_output_destroy(struct wl_listener *listener, void *data) { + struct sway_output *output = wl_container_of(listener, output, output_destroy); struct wlr_output *wlr_output = data; wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); - swayc_t *output_container = NULL; - for (int i = 0 ; i < root_container.children->length; ++i) { - swayc_t *child = root_container.children->items[i]; - if (child->type == C_OUTPUT && - child->sway_output->wlr_output == wlr_output) { - output_container = child; - break; - } - } - if (!output_container) { - return; - } - - destroy_output(output_container); + destroy_output(output->swayc); } void handle_new_output(struct wl_listener *listener, void *data) { From bcb870bcf2b31b4b03ef746bd60b74eb3ea9cb78 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 20 Feb 2018 19:47:48 -0500 Subject: [PATCH 29/36] bug: fix crash on focus up --- sway/tree/layout.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 91f0f36f5..3d04a1a74 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -421,7 +421,6 @@ static void get_layout_center_position(swayc_t *container, int *x, int *y) { } static bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out) { - *out = 0; switch (dir) { case MOVE_UP: *out = WLR_DIRECTION_UP; @@ -436,10 +435,10 @@ static bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out *out = WLR_DIRECTION_RIGHT; break; default: - break; + return false; } - return *out != 0; + return true; } static swayc_t *sway_output_from_wlr(struct wlr_output *output) { From 66d1e0b313c6bbee142bb08e4af07ce6f15cffca Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 22 Feb 2018 18:03:46 -0500 Subject: [PATCH 30/36] basic layout command --- include/sway/container.h | 2 ++ sway/commands.c | 1 + sway/commands/layout.c | 65 ++++++++++++++++++++++++++++++++++++++++ sway/meson.build | 1 + sway/tree/container.c | 12 ++++++++ 5 files changed, 81 insertions(+) create mode 100644 sway/commands/layout.c diff --git a/include/sway/container.h b/include/sway/container.h index 48363be62..f200a1a2e 100644 --- a/include/sway/container.h +++ b/include/sway/container.h @@ -164,4 +164,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data), void *data); +swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout); + #endif diff --git a/sway/commands.c b/sway/commands.c index bc2a85d7f..a7eb6b4a6 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -136,6 +136,7 @@ static struct cmd_handler handlers[] = { { "include", cmd_include }, { "input", cmd_input }, { "kill", cmd_kill }, + { "layout", cmd_layout }, { "output", cmd_output }, { "reload", cmd_reload }, { "seat", cmd_seat }, diff --git a/sway/commands/layout.c b/sway/commands/layout.c new file mode 100644 index 000000000..d953abc8c --- /dev/null +++ b/sway/commands/layout.c @@ -0,0 +1,65 @@ +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/layout.h" +#include "log.h" + +struct cmd_results *cmd_layout(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) { + return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file."); + } + if (!config->active) { + return cmd_results_new(CMD_FAILURE, "layout", "Can only be used when sway is running."); + } + if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { + return error; + } + swayc_t *parent = config->handler_context.current_container; + if (!sway_assert(parent != NULL, "command called without container context")) { + return NULL; + } + + // TODO: floating + /* + if (parent->is_floating) { + return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); + } + */ + + while (parent->type == C_VIEW) { + parent = parent->parent; + } + + // TODO: stacks and tabs + + if (strcasecmp(argv[0], "default") == 0) { + swayc_change_layout(parent, parent->prev_layout); + if (parent->layout == L_NONE) { + swayc_t *output = swayc_parent_by_type(parent, C_OUTPUT); + swayc_change_layout(parent, default_layout(output)); + } + } else { + if (parent->layout != L_TABBED && parent->layout != L_STACKED) { + parent->prev_layout = parent->layout; + } + + if (strcasecmp(argv[0], "splith") == 0) { + swayc_change_layout(parent, L_HORIZ); + } else if (strcasecmp(argv[0], "splitv") == 0) { + swayc_change_layout(parent, L_VERT); + } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { + if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE + || parent->workspace_layout == L_HORIZ)) { + swayc_change_layout(parent, L_VERT); + } else { + swayc_change_layout(parent, L_HORIZ); + } + } + } + + arrange_windows(parent, parent->width, parent->height); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index 8d5a97d2e..26e56ad21 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -14,6 +14,7 @@ sway_sources = files( 'commands/kill.c', 'commands/include.c', 'commands/input.c', + 'commands/layout.c', 'commands/seat.c', 'commands/seat/attach.c', 'commands/seat/fallback.c', diff --git a/sway/tree/container.c b/sway/tree/container.c index 84e14ba69..b56e72e19 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -400,3 +400,15 @@ void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data), list_free(queue); } + +swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout) { + if (container->type == C_WORKSPACE) { + container->workspace_layout = layout; + if (layout == L_HORIZ || layout == L_VERT) { + container->layout = layout; + } + } else { + container->layout = layout; + } + return container; +} From 6becfc14310e1443fc058b57c3ff756f3cb06af3 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 24 Feb 2018 12:49:42 -0500 Subject: [PATCH 31/36] update log.h for latest wlr --- include/log.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/log.h b/include/log.h index 350a59ef3..a97481274 100644 --- a/include/log.h +++ b/include/log.h @@ -5,11 +5,11 @@ void _sway_abort(const char *filename, ...) ATTRIB_PRINTF(1, 2); #define sway_abort(FMT, ...) \ - _sway_abort("[%s:%d] " FMT, _strip_path(__FILE__), __LINE__, ##__VA_ARGS__) + _sway_abort("[%s:%d] " FMT, wlr_strip_path(__FILE__), __LINE__, ##__VA_ARGS__) bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3); #define sway_assert(COND, FMT, ...) \ - _sway_assert(COND, "[%s:%d] %s:" FMT, _strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__) + _sway_assert(COND, "[%s:%d] %s:" FMT, wlr_strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__) void error_handler(int sig); From ac8269d536bf636bd0fbf8047cf6516912634864 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 24 Feb 2018 12:50:24 -0500 Subject: [PATCH 32/36] take seat param for handle_command and rename --- include/sway/commands.h | 4 ++-- sway/commands.c | 46 ++++++++++++++++++++++++----------------- sway/input/keyboard.c | 2 +- sway/ipc-server.c | 3 +-- sway/server.c | 2 +- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/include/sway/commands.h b/include/sway/commands.h index 4ee7af2a3..9ff18823d 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -46,9 +46,9 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val); /** - * Parse and handles a command. + * Parse and executes a command. */ -struct cmd_results *handle_command(char *command); +struct cmd_results *execute_command(char *command, struct sway_seat *seat); /** * Parse and handles a command during config file loading. * diff --git a/sway/commands.c b/sway/commands.c index a7eb6b4a6..66614058c 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -198,7 +198,7 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) { return res; } -struct cmd_results *handle_command(char *_exec) { +struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { // Even though this function will process multiple commands we will only // return the last error, if any (for now). (Since we have access to an // error string we could e.g. concatenate all errors there.) @@ -209,6 +209,16 @@ struct cmd_results *handle_command(char *_exec) { char *cmd; list_t *containers = NULL; + if (seat == NULL) { + // passing a NULL seat means we just pick the default seat + seat = sway_input_manager_get_default_seat(input_manager); + if (!sway_assert(seat, "could not find a seat to run the command on")) { + return NULL; + } + } + + config->handler_context.seat = seat; + head = exec; do { // Extract criteria (valid for this command list only). @@ -278,24 +288,22 @@ struct cmd_results *handle_command(char *_exec) { if (!has_criteria) { // without criteria, the command acts upon the focused // container - struct sway_seat *seat = config->handler_context.seat; - if (!seat) { - seat = sway_input_manager_get_default_seat(input_manager); + config->handler_context.current_container = + sway_seat_get_focus_inactive(seat, &root_container); + if (!sway_assert(config->handler_context.current_container, + "could not get focus-inactive for root container")) { + return NULL; } - if (seat) { - config->handler_context.current_container = - sway_seat_get_focus(seat); - struct cmd_results *res = handler->handle(argc-1, argv+1); - if (res->status != CMD_SUCCESS) { - free_argv(argc, argv); - if (results) { - free_cmd_results(results); - } - results = res; - goto cleanup; + struct cmd_results *res = handler->handle(argc-1, argv+1); + if (res->status != CMD_SUCCESS) { + free_argv(argc, argv); + if (results) { + free_cmd_results(results); } - free_cmd_results(res); + results = res; + goto cleanup; } + free_cmd_results(res); } else { for (int i = 0; i < containers->length; ++i) { config->handler_context.current_container = containers->items[i]; @@ -322,13 +330,13 @@ cleanup: return results; } -// this is like handle_command above, except: +// this is like execute_command above, except: // 1) it ignores empty commands (empty lines) // 2) it does variable substitution // 3) it doesn't split commands (because the multiple commands are supposed to // be chained together) -// 4) handle_command handles all state internally while config_command has some -// state handled outside (notably the block mode, in read_config) +// 4) execute_command handles all state internally while config_command has +// some state handled outside (notably the block mode, in read_config) struct cmd_results *config_command(char *exec, enum cmd_status block) { struct cmd_results *results = NULL; int argc; diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 6dc57d461..996850525 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -95,7 +95,7 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard, binding->command); config_clear_handler_context(config); config->handler_context.seat = keyboard->seat_device->sway_seat; - struct cmd_results *results = handle_command(binding->command); + 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); diff --git a/sway/ipc-server.c b/sway/ipc-server.c index ee259c990..4c0953e8a 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -336,8 +336,7 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_COMMAND: { config_clear_handler_context(config); - config->handler_context.seat = input_manager_current_seat(input_manager); - struct cmd_results *results = handle_command(buf); + struct cmd_results *results = execute_command(buf, NULL); const char *json = cmd_results_to_json(results); char reply[256]; int length = snprintf(reply, sizeof(reply), "%s", json); diff --git a/sway/server.c b/sway/server.c index 0753d37e7..495769ee7 100644 --- a/sway/server.c +++ b/sway/server.c @@ -22,7 +22,7 @@ static void server_ready(struct wl_listener *listener, void *data) { config->active = true; while (config->cmd_queue->length) { char *line = config->cmd_queue->items[0]; - struct cmd_results *res = handle_command(line); + struct cmd_results *res = execute_command(line, NULL); if (res->status != CMD_SUCCESS) { wlr_log(L_ERROR, "Error on line '%s': %s", line, res->error); } From 5b219a15982b9626f85535c082ee2adb460ad11d Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 24 Feb 2018 13:20:34 -0500 Subject: [PATCH 33/36] separate config directives and commands --- sway/commands.c | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/sway/commands.c b/sway/commands.c index 66614058c..ed8da3dcd 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -125,25 +125,35 @@ struct cmd_results *add_color(const char *name, char *buffer, const char *color) return NULL; } -/* Keep alphabetized */ +/** + * handlers that can run in either config or command context + * Keep alphabetized + */ static struct cmd_handler handlers[] = { { "bindcode", cmd_bindcode }, { "bindsym", cmd_bindsym }, { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, - { "exit", cmd_exit }, - { "focus", cmd_focus }, { "include", cmd_include }, { "input", cmd_input }, - { "kill", cmd_kill }, - { "layout", cmd_layout }, { "output", cmd_output }, - { "reload", cmd_reload }, { "seat", cmd_seat }, { "set", cmd_set }, { "workspace", cmd_workspace }, }; +/** + * Commands that can *not* run in the config loading context + * Keep alphabetized + */ +static struct cmd_handler command_handlers[] = { + { "exit", cmd_exit }, + { "focus", cmd_focus }, + { "kill", cmd_kill }, + { "layout", cmd_layout }, + { "reload", cmd_reload }, +}; + static int handler_compare(const void *_a, const void *_b) { const struct cmd_handler *a = _a; const struct cmd_handler *b = _b; @@ -181,20 +191,34 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) { struct cmd_handler *res = NULL; wlr_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT); + bool config_loading = config->reading || !config->active; + if (block == CMD_BLOCK_INPUT) { - res = bsearch(&d, input_handlers, + // input commands can run in either context + return bsearch(&d, input_handlers, sizeof(input_handlers) / sizeof(struct cmd_handler), sizeof(struct cmd_handler), handler_compare); } else if (block == CMD_BLOCK_SEAT) { - res = bsearch(&d, seat_handlers, + // seat commands can run in either context + return bsearch(&d, seat_handlers, sizeof(seat_handlers) / sizeof(struct cmd_handler), sizeof(struct cmd_handler), handler_compare); - } else { - res = bsearch(&d, handlers, - sizeof(handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); } + if (!config_loading) { + res = bsearch(&d, command_handlers, + sizeof(command_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + + if (res) { + return res; + } + } + + res = bsearch(&d, handlers, + sizeof(handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + return res; } From 7262bf655f7a19af1d4c8681be74d70bfc6b8911 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 24 Feb 2018 13:22:57 -0500 Subject: [PATCH 34/36] remove checks for command handlers --- sway/commands/exit.c | 3 --- sway/commands/focus.c | 14 -------------- sway/commands/kill.c | 8 -------- sway/commands/layout.c | 9 --------- sway/commands/reload.c | 3 --- 5 files changed, 37 deletions(-) diff --git a/sway/commands/exit.c b/sway/commands/exit.c index 4bb6a97be..d5353c205 100644 --- a/sway/commands/exit.c +++ b/sway/commands/exit.c @@ -6,9 +6,6 @@ void sway_terminate(int exit_code); struct cmd_results *cmd_exit(int argc, char **argv) { struct cmd_results *error = NULL; - if (config->reading) { - return cmd_results_new(CMD_FAILURE, "exit", "Can't be used in config file."); - } if ((error = checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0))) { return error; } diff --git a/sway/commands/focus.c b/sway/commands/focus.c index ba47d1e13..f1a8078f7 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -33,20 +33,6 @@ static bool parse_movement_direction(const char *name, enum movement_direction * struct cmd_results *cmd_focus(int argc, char **argv) { swayc_t *con = config->handler_context.current_container; struct sway_seat *seat = config->handler_context.seat; - - if (!sway_assert(seat, "'focus' command called without seat context")) { - return cmd_results_new(CMD_FAILURE, "focus", - "Command 'focus' called without seat context (this is a bug in sway)"); - } - - if (config->reading) { - return cmd_results_new(CMD_FAILURE, "focus", - "Command 'focus' cannot be used in the config file"); - } - if (con == NULL) { - wlr_log(L_DEBUG, "no container to focus"); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } if (con->type < C_WORKSPACE) { return cmd_results_new(CMD_FAILURE, "focus", "Command 'focus' cannot be used above the workspace level"); diff --git a/sway/commands/kill.c b/sway/commands/kill.c index 4b3666be2..f408ce2a9 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c @@ -6,14 +6,6 @@ #include "sway/commands.h" struct cmd_results *cmd_kill(int argc, char **argv) { - if (config->reading) { - return cmd_results_new(CMD_FAILURE, "kill", - "Command 'kill' cannot be used in the config file"); - } - if (config->handler_context.current_container == NULL) { - wlr_log(L_DEBUG, "no container to kill"); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } enum swayc_types type = config->handler_context.current_container->type; if (type != C_VIEW && type != C_CONTAINER) { return cmd_results_new(CMD_INVALID, NULL, diff --git a/sway/commands/layout.c b/sway/commands/layout.c index d953abc8c..b0fc5d664 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c @@ -7,19 +7,10 @@ struct cmd_results *cmd_layout(int argc, char **argv) { struct cmd_results *error = NULL; - if (config->reading) { - return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file."); - } - if (!config->active) { - return cmd_results_new(CMD_FAILURE, "layout", "Can only be used when sway is running."); - } if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { return error; } swayc_t *parent = config->handler_context.current_container; - if (!sway_assert(parent != NULL, "command called without container context")) { - return NULL; - } // TODO: floating /* diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 419c7de3d..d54d40db6 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c @@ -4,9 +4,6 @@ struct cmd_results *cmd_reload(int argc, char **argv) { struct cmd_results *error = NULL; - if (config->reading) { - return cmd_results_new(CMD_FAILURE, "reload", "Can't be used in config file."); - } if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { return error; } From 2154b7c7d623d99e2623f1928f6e77e95255a2d3 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 24 Feb 2018 13:34:47 -0500 Subject: [PATCH 35/36] add config handlers --- sway/commands.c | 19 ++++++++++++++++++- sway/commands/set.c | 1 - 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/sway/commands.c b/sway/commands.c index ed8da3dcd..b52eb2006 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -138,10 +138,17 @@ static struct cmd_handler handlers[] = { { "input", cmd_input }, { "output", cmd_output }, { "seat", cmd_seat }, - { "set", cmd_set }, { "workspace", cmd_workspace }, }; +/** + * Commands that can *only* run in the config loading context + * Keep alphabetized + */ +static struct cmd_handler config_handlers[] = { + { "set", cmd_set }, +}; + /** * Commands that can *not* run in the config loading context * Keep alphabetized @@ -215,6 +222,16 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) { } } + if (config->reading) { + res = bsearch(&d, config_handlers, + sizeof(config_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + + if (res) { + return res; + } + } + res = bsearch(&d, handlers, sizeof(handlers) / sizeof(struct cmd_handler), sizeof(struct cmd_handler), handler_compare); diff --git a/sway/commands/set.c b/sway/commands/set.c index 856c73e79..84e9b792c 100644 --- a/sway/commands/set.c +++ b/sway/commands/set.c @@ -27,7 +27,6 @@ void free_sway_variable(struct sway_variable *var) { struct cmd_results *cmd_set(int argc, char **argv) { char *tmp; struct cmd_results *error = NULL; - if (!config->reading) return cmd_results_new(CMD_FAILURE, "set", "Can only be used in config file."); if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) { return error; } From 1cca3965f395f624f698cc162946c6cbd6b10673 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 24 Feb 2018 14:30:47 -0500 Subject: [PATCH 36/36] static bfs queue --- sway/tree/container.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index b56e72e19..fafbdb03c 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -17,6 +17,21 @@ #include "sway/workspace.h" #include "log.h" +static list_t *bfs_queue; + +static list_t *get_bfs_queue() { + if (!bfs_queue) { + bfs_queue = create_list(); + if (!bfs_queue) { + wlr_log(L_ERROR, "could not allocate list for bfs queue"); + return NULL; + } + } + bfs_queue->length = 0; + + return bfs_queue; +} + swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { if (!container->children) { @@ -273,7 +288,11 @@ swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) { swayc_t *swayc_at(swayc_t *parent, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - list_t *queue = create_list(); + list_t *queue = get_bfs_queue(); + if (!queue) { + return NULL; + } + list_add(queue, parent); swayc_t *swayc = NULL; @@ -313,7 +332,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, *sx = view_sx - popup_sx; *sy = view_sy - popup_sy; *surface = popup->surface; - list_free(queue); return swayc; } break; @@ -332,7 +350,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, *sx = view_sx - sub_x; *sy = view_sy - sub_y; *surface = subsurface->surface; - list_free(queue); return swayc; } @@ -344,7 +361,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, *sx = view_sx; *sy = view_sy; *surface = swayc->sway_view->surface; - list_free(queue); return swayc; } } else { @@ -352,8 +368,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, } } - list_free(queue); - return NULL; } @@ -381,7 +395,11 @@ void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), voi void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data), void *data) { - list_t *queue = create_list(); + list_t *queue = get_bfs_queue(); + if (!queue) { + return; + } + if (queue == NULL) { wlr_log(L_ERROR, "could not allocate list"); return; @@ -397,8 +415,6 @@ void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data), // TODO floating containers list_cat(queue, current->children); } - - list_free(queue); } swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout) {