From: Michael Stapelberg Date: Mon, 9 Mar 2009 06:39:19 +0000 (+0100) Subject: Implement wrapping left/right/up/down across screens X-Git-Tag: 3.a~51 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=71993c9b48a20218d7199156bec21860c084385f;p=i3%2Fi3 Implement wrapping left/right/up/down across screens --- diff --git a/include/xinerama.h b/include/xinerama.h index f0e2d403..b8a591c1 100644 --- a/include/xinerama.h +++ b/include/xinerama.h @@ -20,5 +20,6 @@ void initialize_xinerama(xcb_connection_t *conn); void xinerama_requery_screens(xcb_connection_t *conn); i3Screen *get_screen_at(int x, int y, struct screens_head *screenlist); i3Screen *get_screen_containing(int x, int y); +i3Screen *get_screen_most(direction_t direction); #endif diff --git a/src/commands.c b/src/commands.c index 77b3e58f..7539e653 100644 --- a/src/commands.c +++ b/src/commands.c @@ -87,16 +87,12 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t i3Screen *screen; int destination_y = (direction == D_UP ? (container->y - 1) : (container->y + container->height + 1)); if ((screen = get_screen_containing(container->x, destination_y)) == NULL) { - LOG("Not possible, no screen found.\n"); - return; + LOG("Wrapping screen around vertically\n"); + /* No screen found? Then wrap */ + screen = get_screen_most((direction == D_UP ? D_DOWN : D_UP)); } t_ws = &(workspaces[screen->current_workspace]); new_row = (direction == D_UP ? (t_ws->rows - 1) : 0); - /* Bounds checking */ - if (new_col >= t_ws->cols) - new_col = (t_ws->cols - 1); - if (new_row >= t_ws->rows) - new_row = (t_ws->rows - 1); } } else if (direction == D_LEFT || direction == D_RIGHT) { if (direction == D_RIGHT && cell_exists(current_col+1, current_row)) @@ -109,22 +105,23 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t i3Screen *screen; int destination_x = (direction == D_LEFT ? (container->x - 1) : (container->x + container->width + 1)); if ((screen = get_screen_containing(destination_x, container->y)) == NULL) { - LOG("Not possible, no screen found.\n"); - return; + LOG("Wrapping screen around horizontally\n"); + screen = get_screen_most((direction == D_LEFT ? D_RIGHT : D_LEFT)); } t_ws = &(workspaces[screen->current_workspace]); new_col = (direction == D_LEFT ? (t_ws->cols - 1) : 0); - /* Bounds checking */ - if (new_col >= t_ws->cols) - new_col = (t_ws->cols - 1); - if (new_row >= t_ws->rows) - new_row = (t_ws->rows - 1); } } else { LOG("direction unhandled\n"); return; } + /* Bounds checking */ + if (new_col >= t_ws->cols) + new_col = (t_ws->cols - 1); + if (new_row >= t_ws->rows) + new_row = (t_ws->rows - 1); + if (t_ws->table[new_col][new_row]->currently_focused != NULL) set_focus(conn, t_ws->table[new_col][new_row]->currently_focused); } diff --git a/src/xinerama.c b/src/xinerama.c index e5a87efe..7b1df9a4 100644 --- a/src/xinerama.c +++ b/src/xinerama.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,43 @@ i3Screen *get_screen_containing(int x, int y) { return NULL; } +/* + * Gets the screen which is the last one in the given direction, for example the screen + * on the most bottom when direction == D_DOWN, the screen most right when direction == D_RIGHT + * and so on. + * + * This function always returns a screen. + * + */ +i3Screen *get_screen_most(direction_t direction) { + i3Screen *screen, *candidate = NULL; + int position = 0; + TAILQ_FOREACH(screen, virtual_screens, screens) { + /* Repeated calls of WIN determine the winner of the comparison */ + #define WIN(variable, condition) \ + if (variable condition) { \ + candidate = screen; \ + position = variable; \ + } \ + break; + + switch (direction) { + case D_UP: + WIN(screen->rect.y, <= position); + case D_DOWN: + WIN(screen->rect.y, >= position); + case D_LEFT: + WIN(screen->rect.x, <= position); + case D_RIGHT: + WIN(screen->rect.x, >= position); + } + } + + assert(candidate != NULL); + + return candidate; +} + /* * Fills virtual_screens with exactly one screen with width/height of the whole X server. *