]> git.sur5r.net Git - i3/i3/commitdiff
Implement switching focus across screens.
authorPeter Bui <pnutzh4x0r@gmail.com>
Sat, 6 Aug 2011 16:28:05 +0000 (12:28 -0400)
committerMichael Stapelberg <michael@stapelberg.de>
Sun, 7 Aug 2011 12:33:07 +0000 (14:33 +0200)
Modify _tree_next() so that when we reach the workspace container:

1. Find the next corresponding output (screen) using the added
get_output_next().

2. If there is another output, find the visible workspace.

3. Call workspace_show on found workspace.

4. Find the appropriate window to focus (leftmost/rightmost, etc.) using
con_descend_direction, and then focus it.

I've only tested on horizontal monitors (left/right).

include/con.h
include/randr.h
src/con.c
src/randr.c
src/tree.c

index 6ce7bf840c975a8e2641c85908609e30e409cf72..7d828408a4dd166948c75d35edcc01b6a21bf30a 100644 (file)
@@ -177,6 +177,14 @@ Con *con_descend_focused(Con *con);
  */
 Con *con_descend_tiling_focused(Con *con);
 
+/*
+ * Returns the leftmost, rightmost, etc. container in sub-tree. For example, if
+ * direction is D_LEFT, then we return the rightmost container and if direction
+ * is D_RIGHT, we return the leftmost container.  This is because if we are
+ * moving D_LEFT, and thus want the rightmost container.
+ */
+Con *con_descend_direction(Con *con, direction_t direction);
+
 /**
  * Returns a "relative" Rect which contains the amount of pixels that need to
  * be added to the original Rect to get the final position (obviously the
index d14d04788aeb7ea283b66ff085f9af0b1a2ff6dd..9c09f2b1276b11f55e6fc306170bd9467cb34586 100644 (file)
@@ -91,4 +91,10 @@ Output *get_output_containing(int x, int y);
  */
 Output *get_output_most(direction_t direction, Output *current);
 
+/**
+ * Gets the output which is the next one in the given direction.
+ *
+ */
+Output *get_output_next(direction_t direction, Output *current);
+
 #endif
index 1cf1779e7f63d302ed943353121921a70eef250e..e42e8c77501536b31b91e883d2cb1cc71f2dea72 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -773,6 +773,44 @@ Con *con_descend_tiling_focused(Con *con) {
     return next;
 }
 
+/*
+ * Recursively walk tree of nodes and check all nodes for condition.  Returns
+ * container that matches condition (i.e. leftmost, rightmost, etc.).
+ *
+ */
+Con *_con_descend_direction(Con *con, Con *next, direction_t direction) {
+    #define DESCEND_DIRECTION(condition) \
+        if (TAILQ_EMPTY(&(con->nodes_head))) \
+            if (!next || condition) \
+                next = con; \
+        NODES_FOREACH(con) \
+            next = _con_descend_direction(child, next, direction); \
+        break;
+
+    switch (direction) {
+        case D_LEFT:
+            DESCEND_DIRECTION(next->rect.x < con->rect.x)
+        case D_RIGHT:
+            DESCEND_DIRECTION(next->rect.x > con->rect.x)
+        case D_UP:
+            DESCEND_DIRECTION(next->rect.y > con->rect.y)
+        case D_DOWN:
+            DESCEND_DIRECTION(next->rect.y < con->rect.y)
+    }
+
+    return next;
+}
+
+/*
+ * Returns the leftmost, rightmost, etc. container in sub-tree. For example, if
+ * direction is D_LEFT, then we return the rightmost container and if direction
+ * is D_RIGHT, we return the leftmost container.  This is because if we are
+ * moving D_LEFT, and thus want the rightmost container.
+ *
+ */
+Con *con_descend_direction(Con *con, direction_t direction) {
+    return _con_descend_direction(con, NULL, direction);
+}
 
 /*
  * Returns a "relative" Rect which contains the amount of pixels that need to
index e48e2065d8e0cb14696de89f9db964a77f677ea7..bd887630e5c124d6f31b055060ca8f49d7a7a46c 100644 (file)
@@ -143,6 +143,48 @@ Output *get_output_most(direction_t direction, Output *current) {
     return candidate;
 }
 
+/*
+ * Gets the output which is the next one in the given direction.
+ *
+ */
+Output *get_output_next(direction_t direction, Output *current) {
+    Output *output, *candidate = NULL;
+
+    TAILQ_FOREACH(output, &outputs, outputs) {
+        if (!output->active)
+            continue;
+
+        if (((direction == D_UP) || (direction == D_DOWN)) &&
+            (current->rect.x != output->rect.x))
+            continue;
+
+        if (((direction == D_LEFT) || (direction == D_RIGHT)) &&
+            (current->rect.y != output->rect.y))
+            continue;
+
+        switch (direction) {
+            case D_UP:
+                if (current->rect.y < output->rect.y && (!candidate || output->rect.y < candidate->rect.y))
+                    candidate = output;
+                break;
+            case D_DOWN:
+                if (current->rect.y > output->rect.y && (!candidate || output->rect.y > candidate->rect.y))
+                    candidate = output;
+                break;
+            case D_LEFT:
+                if (current->rect.x > output->rect.x && (!candidate || output->rect.x > candidate->rect.x))
+                    candidate = output;
+                break;
+            case D_RIGHT:
+                if (current->rect.x < output->rect.x && (!candidate || output->rect.x < candidate->rect.x))
+                    candidate = output;
+                break;
+        }
+    }
+
+    return candidate;
+}
+
 /*
  * Disables RandR support by creating exactly one output with the size of the
  * X11 screen.
index 272276f467bd3a84b4fc8baa829e6eddc22dc2e3..fb6d6cc7ee5b44c5149f6e5799f8ec0639ac961c 100644 (file)
@@ -376,9 +376,49 @@ void tree_render() {
  *
  */
 static bool _tree_next(Con *con, char way, orientation_t orientation, bool wrap) {
-    /* Stop recursing at workspaces */
-    if (con->type == CT_WORKSPACE)
+    /* Stop recursing at workspaces after attempting to switch to next
+     * workspace if possible. */
+    if (con->type == CT_WORKSPACE) {
+        Output *current_output = get_output_containing(con->rect.x, con->rect.y);
+        Output *next_output;
+
+        if (!current_output)
+            return false;
+        DLOG("Current output is %s\n", current_output->name);
+
+        /* Try to find next output */
+        direction_t direction;
+        if (way == 'n' && orientation == HORIZ)
+            direction = D_RIGHT;
+        else if (way == 'p' && orientation == HORIZ)
+            direction = D_LEFT;
+        else if (way == 'n' && orientation == VERT)
+            direction = D_UP;
+        else if (way == 'p' && orientation == VERT)
+            direction = D_DOWN;
+        else
+            return false;
+
+        next_output = get_output_next(direction, current_output);
+        if (!next_output)
+            return false;
+        DLOG("Next output is %s\n", next_output->name);
+
+        /* Find visible workspace on next output */
+        Con* workspace = NULL;
+        GREP_FIRST(workspace, output_get_content(next_output->con), workspace_is_visible(child));
+
+        /* Show next workspace and focus appropriate container if possible. */
+        if (workspace) {
+            workspace_show(workspace->name);
+            Con* focus = con_descend_direction(workspace, direction);
+            if (focus)
+                con_focus(focus);
+            return true;
+        }
+
         return false;
+    }
 
     if (con->type == CT_FLOATING_CON) {
         /* TODO: implement focus for floating windows */