diff --git a/sway/commands.c b/sway/commands.c index 322c9519e..12d382445 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -8,6 +8,7 @@ #include #include "stringop.h" #include "layout.h" +#include "movement.h" #include "log.h" #include "commands.h" @@ -97,6 +98,23 @@ int cmd_exit(struct sway_config *config, int argc, char **argv) { return 0; } +int cmd_focus(struct sway_config *config, int argc, char **argv) { + if (argc != 1) { + sway_log(L_ERROR, "Invalid focus command (expected 1 arguments, got %d)", argc); + return 1; + } + if (strcasecmp(argv[0], "left") == 0) { + move_focus(MOVE_LEFT); + } else if (strcasecmp(argv[0], "right") == 0) { + move_focus(MOVE_RIGHT); + } else if (strcasecmp(argv[0], "up") == 0) { + move_focus(MOVE_UP); + } else if (strcasecmp(argv[0], "down") == 0) { + move_focus(MOVE_DOWN); + } + return 0; +} + int cmd_focus_follows_mouse(struct sway_config *config, int argc, char **argv) { if (argc != 1) { sway_log(L_ERROR, "Invalid focus_follows_mouse command (expected 1 arguments, got %d)", argc); @@ -184,6 +202,7 @@ struct cmd_handler handlers[] = { { "bindsym", cmd_bindsym }, { "exec", cmd_exec }, { "exit", cmd_exit }, + { "focus", cmd_focus }, { "focus_follows_mouse", cmd_focus_follows_mouse }, { "layout", cmd_layout }, { "set", cmd_set }, diff --git a/sway/layout.c b/sway/layout.c index 6bb19d639..b320e8ad0 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -163,6 +163,7 @@ void add_view(wlc_handle view_handle) { view->type = C_VIEW; add_child(parent, view); + unfocus_all(&root_container); focus_view(view); arrange_windows(parent, -1, -1); @@ -209,6 +210,7 @@ void destroy_view(swayc_t *view) { parent->focused = NULL; } + unfocus_all(&root_container); if (parent->children->length != 0) { focus_view(parent->children->items[0]); } else { @@ -238,12 +240,17 @@ void unfocus_all(swayc_t *container) { } void focus_view(swayc_t *view) { - if (view->type == C_VIEW) { - unfocus_all(&root_container); - wlc_view_set_state(view->handle, WLC_BIT_ACTIVATED, true); - wlc_view_focus(view->handle); - } + sway_log(L_DEBUG, "Setting focus for %p", view); if (view == &root_container) { + // Propegate wayland focus down + swayc_t *child = view->focused; + while (child && child->type != C_VIEW) { + child = child->focused; + } + if (child) { + wlc_view_set_state(child->handle, WLC_BIT_ACTIVATED, true); + wlc_view_focus(child->handle); + } return; } view->parent->focused = view; @@ -285,6 +292,7 @@ void add_output(wlc_handle output) { add_child(container, workspace); if (root_container.focused == NULL) { + unfocus_all(&root_container); focus_view(workspace); } } diff --git a/sway/layout.h b/sway/layout.h index 08f3f78b5..b0aec42f0 100644 --- a/sway/layout.h +++ b/sway/layout.h @@ -49,6 +49,7 @@ void add_output(wlc_handle output); void destroy_output(wlc_handle output); void destroy_view(swayc_t *view); void add_view(wlc_handle view); +void unfocus_all(swayc_t *container); void focus_view(swayc_t *view); void arrange_windows(swayc_t *container, int width, int height); swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data); diff --git a/sway/list.c b/sway/list.c index 55052f859..52943efe3 100644 --- a/sway/list.c +++ b/sway/list.c @@ -28,6 +28,7 @@ void list_add(list_t *list, void *item) { } void list_insert(list_t *list, int index, void *item) { + // TODO: Implement this properly if (list->length == list->capacity) { list->capacity += 10; list->items = realloc(list->items, sizeof(void*) * list->capacity); diff --git a/sway/movement.c b/sway/movement.c new file mode 100644 index 000000000..197df7b2c --- /dev/null +++ b/sway/movement.c @@ -0,0 +1,58 @@ +#include +#include +#include "list.h" +#include "log.h" +#include "layout.h" +#include "movement.h" + +void move_focus(enum movement_direction direction) { + swayc_t *current = get_focused_container(&root_container); + swayc_t *parent = current->parent; + + while (true) { + sway_log(L_DEBUG, "Moving focus away from %p", current); + + // Test if we can even make a difference here + bool can_move = false; + int diff = 0; + if (direction == MOVE_LEFT || direction == MOVE_RIGHT) { + if (parent->layout == L_HORIZ) { + can_move = true; + diff = direction == MOVE_LEFT ? -1 : 1; + } + } else { + if (parent->layout == L_VERT) { + can_move = true; + diff = direction == MOVE_UP ? -1 : 1; + } + } + sway_log(L_DEBUG, "Can move? %s", can_move ? "yes" : "no"); + if (can_move) { + int i; + for (i = 0; i < parent->children->length; ++i) { + swayc_t *child = parent->children->items[i]; + if (child == current) { + break; + } + } + int desired = i + diff; + sway_log(L_DEBUG, "Moving from %d to %d", i, desired); + if (desired < 0 || desired >= parent->children->length) { + can_move = false; + } else { + unfocus_all(&root_container); + focus_view(parent->children->items[desired]); + return; + } + } + if (!can_move) { + sway_log(L_DEBUG, "Can't move at current level, moving up tree"); + current = parent; + parent = parent->parent; + if (parent->type == C_ROOT) { + // Nothing we can do + return; + } + } + } +} diff --git a/sway/movement.h b/sway/movement.h new file mode 100644 index 000000000..c88b44bde --- /dev/null +++ b/sway/movement.h @@ -0,0 +1,16 @@ +#ifndef _SWAY_MOVEMENT_H +#define _SWAY_MOVEMENT_H + +#include +#include "list.h" + +enum movement_direction{ + MOVE_LEFT, + MOVE_RIGHT, + MOVE_UP, + MOVE_DOWN +}; + +void move_focus(enum movement_direction direction); + +#endif