Implement switching focus across screens.

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).
This commit is contained in:
Peter Bui 2011-08-06 12:28:05 -04:00 committed by Michael Stapelberg
parent 865c193971
commit a547365a88
5 changed files with 136 additions and 2 deletions

View File

@ -177,6 +177,14 @@ Con *con_descend_focused(Con *con);
*/ */
Con *con_descend_tiling_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 * 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 * be added to the original Rect to get the final position (obviously the

View File

@ -91,4 +91,10 @@ Output *get_output_containing(int x, int y);
*/ */
Output *get_output_most(direction_t direction, Output *current); 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 #endif

View File

@ -773,6 +773,44 @@ Con *con_descend_tiling_focused(Con *con) {
return next; 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 * Returns a "relative" Rect which contains the amount of pixels that need to

View File

@ -143,6 +143,48 @@ Output *get_output_most(direction_t direction, Output *current) {
return candidate; 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 * Disables RandR support by creating exactly one output with the size of the
* X11 screen. * X11 screen.

View File

@ -376,9 +376,49 @@ void tree_render() {
* *
*/ */
static bool _tree_next(Con *con, char way, orientation_t orientation, bool wrap) { static bool _tree_next(Con *con, char way, orientation_t orientation, bool wrap) {
/* Stop recursing at workspaces */ /* Stop recursing at workspaces after attempting to switch to next
if (con->type == CT_WORKSPACE) * 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; return false;
}
if (con->type == CT_FLOATING_CON) { if (con->type == CT_FLOATING_CON) {
/* TODO: implement focus for floating windows */ /* TODO: implement focus for floating windows */