diff options
Diffstat (limited to 'sway/commands/focus.c')
-rw-r--r-- | sway/commands/focus.c | 264 |
1 files changed, 102 insertions, 162 deletions
diff --git a/sway/commands/focus.c b/sway/commands/focus.c index f342e524..e31898af 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -34,211 +34,139 @@ static bool parse_movement_direction(const char *name, } /** - * Get swayc in the direction of newly entered output. + * Get node in the direction of newly entered output. */ -static struct sway_container *get_swayc_in_output_direction( - struct sway_container *output, enum movement_direction dir, - struct sway_seat *seat) { - if (!output) { - return NULL; - } - - struct sway_container *ws = seat_get_focus_inactive(seat, output); - if (ws->type != C_WORKSPACE) { - ws = container_parent(ws, C_WORKSPACE); - } - - if (ws == NULL) { - wlr_log(WLR_ERROR, "got an output without a workspace"); - return NULL; +static struct sway_node *get_node_in_output_direction( + struct sway_output *output, enum movement_direction dir) { + struct sway_seat *seat = config->handler_context.seat; + struct sway_workspace *ws = output_get_active_workspace(output); + if (ws->fullscreen) { + return seat_get_focus_inactive(seat, &ws->fullscreen->node); } + struct sway_container *container = NULL; - if (ws->children->length > 0) { + if (ws->tiling->length > 0) { switch (dir) { case MOVE_LEFT: if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { // get most right child of new output - return ws->children->items[ws->children->length-1]; + container = ws->tiling->items[ws->tiling->length-1]; } else { - return seat_get_focus_inactive(seat, ws); + container = seat_get_focus_inactive_tiling(seat, ws); } + return &container->node; case MOVE_RIGHT: if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { // get most left child of new output - return ws->children->items[0]; + container = ws->tiling->items[0]; } else { - return seat_get_focus_inactive(seat, ws); + container = seat_get_focus_inactive_tiling(seat, ws); } + return &container->node; case MOVE_UP: + if (ws->layout == L_VERT || ws->layout == L_STACKED) { + // get most bottom child of new output + container = ws->tiling->items[ws->tiling->length-1]; + } else { + container = seat_get_focus_inactive_tiling(seat, ws); + } + return &container->node; case MOVE_DOWN: { - struct sway_container *focused = - seat_get_focus_inactive(seat, ws); - if (focused && focused->parent) { - struct sway_container *parent = focused->parent; - if (parent->layout == L_VERT) { - if (dir == MOVE_UP) { - // get child furthest down on new output - int idx = parent->children->length - 1; - return parent->children->items[idx]; - } else if (dir == MOVE_DOWN) { - // get child furthest up on new output - return parent->children->items[0]; - } - } - return focused; + if (ws->layout == L_VERT || ws->layout == L_STACKED) { + // get most top child of new output + container = ws->tiling->items[0]; + } else { + container = seat_get_focus_inactive_tiling(seat, ws); } - break; + return &container->node; } default: break; } } - return ws; + return &ws->node; } -static struct sway_container *container_get_in_direction( - struct sway_container *container, struct sway_seat *seat, - enum movement_direction dir) { - struct sway_container *parent = container->parent; - +static struct sway_node *node_get_in_direction(struct sway_container *container, + struct sway_seat *seat, enum movement_direction dir) { if (dir == MOVE_CHILD) { - return seat_get_focus_inactive(seat, container); + return seat_get_active_child(seat, &container->node); } if (container->is_fullscreen) { if (dir == MOVE_PARENT) { return NULL; } - container = container_parent(container, C_OUTPUT); - parent = container->parent; - } else { - if (dir == MOVE_PARENT) { - if (parent->type == C_OUTPUT || container_is_floating(container)) { - return NULL; - } else { - return parent; - } - } + // Fullscreen container with a direction - go straight to outputs + struct sway_output *output = container->workspace->output; + struct sway_output *new_output = output_get_in_direction(output, dir); + return get_node_in_output_direction(new_output, dir); + } + if (dir == MOVE_PARENT) { + return node_get_parent(&container->node); } struct sway_container *wrap_candidate = NULL; - while (true) { + struct sway_container *current = container; + while (current) { bool can_move = false; int desired; - int idx = list_find(container->parent->children, container); - if (idx == -1) { - return NULL; - } - if (parent->type == C_ROOT) { - 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 = container->x + container->width / 2; - int ly = container->y + container->height / 2; - struct wlr_output_layout *layout = - root_container.sway_root->output_layout; - struct wlr_output *wlr_adjacent = - wlr_output_layout_adjacent_output(layout, wlr_dir, - container->sway_output->wlr_output, lx, ly); - struct sway_container *adjacent = - output_from_wlr_output(wlr_adjacent); + int idx = container_sibling_index(current); + enum sway_container_layout parent_layout = + container_parent_layout(current); + list_t *siblings = container_get_siblings(current); - if (!adjacent || adjacent == container) { - if (!wrap_candidate) { - return NULL; - } - return seat_get_focus_inactive_view(seat, wrap_candidate); - } - struct sway_container *next = - get_swayc_in_output_direction(adjacent, dir, seat); - if (next == NULL) { - return NULL; - } - struct sway_container *next_workspace = next; - if (next_workspace->type != C_WORKSPACE) { - next_workspace = container_parent(next_workspace, C_WORKSPACE); - } - sway_assert(next_workspace, "Next container has no workspace"); - if (next_workspace->sway_workspace->fullscreen) { - return seat_get_focus_inactive(seat, - next_workspace->sway_workspace->fullscreen); - } - if (next->children && next->children->length) { - // TODO consider floating children as well - return seat_get_focus_inactive_view(seat, next); - } else { - return next; + 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 (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 (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) { + if (desired < 0 || desired >= siblings->length) { can_move = false; - int len = parent->children->length; + int len = siblings->length; if (config->focus_wrapping != WRAP_NO && !wrap_candidate && len > 1) { if (desired < 0) { - wrap_candidate = parent->children->items[len-1]; + wrap_candidate = siblings->items[len-1]; } else { - wrap_candidate = parent->children->items[0]; + wrap_candidate = siblings->items[0]; } if (config->focus_wrapping == WRAP_FORCE) { - return seat_get_focus_inactive_view(seat, - wrap_candidate); + struct sway_container *c = seat_get_focus_inactive_view( + seat, &wrap_candidate->node); + return &c->node; } } } else { - struct sway_container *desired_con = - parent->children->items[desired]; - wlr_log(WLR_DEBUG, - "cont %d-%p dir %i sibling %d: %p", idx, - container, dir, desired, desired_con); - return seat_get_focus_inactive_view(seat, desired_con); + struct sway_container *desired_con = siblings->items[desired]; + struct sway_container *c = seat_get_focus_inactive_view( + seat, &desired_con->node); + return &c->node; } } - if (!can_move) { - container = parent; - parent = parent->parent; - if (!parent) { - // wrapping is the last chance - if (!wrap_candidate) { - return NULL; - } - return seat_get_focus_inactive_view(seat, wrap_candidate); - } - } + current = current->parent; } -} -static struct cmd_results *focus_mode(struct sway_container *con, - struct sway_seat *seat, bool floating) { - struct sway_container *ws = con->type == C_WORKSPACE ? - con : container_parent(con, C_WORKSPACE); - - // If the container is in a floating split container, - // operate on the split container instead of the child. - if (container_is_floating_or_child(con)) { - while (con->parent->type != C_WORKSPACE) { - con = con->parent; - } + // Check a different output + struct sway_output *output = container->workspace->output; + struct sway_output *new_output = output_get_in_direction(output, dir); + if (new_output) { + return get_node_in_output_direction(new_output, dir); } + return NULL; +} +static struct cmd_results *focus_mode(struct sway_workspace *ws, + struct sway_seat *seat, bool floating) { struct sway_container *new_focus = NULL; if (floating) { new_focus = seat_get_focus_inactive_floating(seat, ws); @@ -246,7 +174,7 @@ static struct cmd_results *focus_mode(struct sway_container *con, new_focus = seat_get_focus_inactive_tiling(seat, ws); } if (new_focus) { - seat_set_focus(seat, new_focus); + seat_set_focus(seat, &new_focus->node); } else { return cmd_results_new(CMD_FAILURE, "focus", "Failed to find a %s container in workspace", @@ -255,14 +183,14 @@ static struct cmd_results *focus_mode(struct sway_container *con, return cmd_results_new(CMD_SUCCESS, NULL, NULL); } -static struct cmd_results *focus_output(struct sway_container *con, - struct sway_seat *seat, int argc, char **argv) { +static struct cmd_results *focus_output(struct sway_seat *seat, + int argc, char **argv) { if (!argc) { return cmd_results_new(CMD_INVALID, "focus", "Expected 'focus output <direction|name>'"); } char *identifier = join_args(argv, argc); - struct sway_container *output = output_by_name(identifier); + struct sway_output *output = output_by_name(identifier); if (!output) { enum movement_direction direction; @@ -272,14 +200,13 @@ static struct cmd_results *focus_output(struct sway_container *con, return cmd_results_new(CMD_INVALID, "focus", "There is no output with that name"); } - struct sway_container *focus = seat_get_focus(seat); - focus = container_parent(focus, C_OUTPUT); - output = container_get_in_direction(focus, seat, direction); + struct sway_workspace *ws = seat_get_focused_workspace(seat); + output = output_get_in_direction(ws->output, direction); } free(identifier); if (output) { - seat_set_focus(seat, seat_get_focus_inactive(seat, output)); + seat_set_focus(seat, seat_get_focus_inactive(seat, &output->node)); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); @@ -289,29 +216,32 @@ struct cmd_results *cmd_focus(int argc, char **argv) { if (config->reading || !config->active) { return cmd_results_new(CMD_DEFER, NULL, NULL); } - struct sway_container *con = config->handler_context.current_container; + struct sway_node *node = config->handler_context.node; + struct sway_container *container = config->handler_context.container; + struct sway_workspace *workspace = config->handler_context.workspace; struct sway_seat *seat = config->handler_context.seat; - if (con->type < C_WORKSPACE) { + if (node->type < N_WORKSPACE) { return cmd_results_new(CMD_FAILURE, "focus", "Command 'focus' cannot be used above the workspace level"); } if (argc == 0) { - seat_set_focus(seat, con); + seat_set_focus(seat, node); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } if (strcmp(argv[0], "floating") == 0) { - return focus_mode(con, seat, true); + return focus_mode(workspace, seat, true); } else if (strcmp(argv[0], "tiling") == 0) { - return focus_mode(con, seat, false); + return focus_mode(workspace, seat, false); } else if (strcmp(argv[0], "mode_toggle") == 0) { - return focus_mode(con, seat, !container_is_floating_or_child(con)); + bool floating = container && container_is_floating_or_child(container); + return focus_mode(workspace, seat, !floating); } if (strcmp(argv[0], "output") == 0) { argc--; argv++; - return focus_output(con, seat, argc, argv); + return focus_output(seat, argc, argv); } enum movement_direction direction = 0; @@ -321,8 +251,18 @@ struct cmd_results *cmd_focus(int argc, char **argv) { "or 'focus output <direction|name>'"); } - struct sway_container *next_focus = container_get_in_direction( - con, seat, direction); + if (node->type == N_WORKSPACE) { + // A workspace is focused, so just jump to the next output + struct sway_output *new_output = + output_get_in_direction(workspace->output, direction); + struct sway_node *node = + get_node_in_output_direction(new_output, direction); + seat_set_focus(seat, node); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + + struct sway_node *next_focus = + node_get_in_direction(container, seat, direction); if (next_focus) { seat_set_focus(seat, next_focus); } |