*/
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
*/
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
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
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.
*
*/
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 */