]> git.sur5r.net Git - i3/i3/commitdiff
Implement wrapping left/right/up/down across screens
authorMichael Stapelberg <michael+x200@stapelberg.de>
Mon, 9 Mar 2009 06:39:19 +0000 (07:39 +0100)
committerMichael Stapelberg <michael+x200@stapelberg.de>
Mon, 9 Mar 2009 06:39:19 +0000 (07:39 +0100)
include/xinerama.h
src/commands.c
src/xinerama.c

index f0e2d403f17819db5ad965acc0ee3911b415166f..b8a591c13e141194e810cd4bb63b33c179b354a4 100644 (file)
@@ -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
index 77b3e58fd8c7a3920ef553e5538ba5ef3375cbdb..7539e6532f98dab0cc4e8ba9dac0f36c0e99fe2b 100644 (file)
@@ -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);
 }
index e5a87efebadb0183ddc0d8c90a47fa5f7beafad2..7b1df9a4afd84ae269c76978c34deb866bdf0204 100644 (file)
@@ -12,6 +12,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
+#include <assert.h>
 
 #include <xcb/xcb.h>
 #include <xcb/xinerama.h>
@@ -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.
  *