-static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t thing) {
- DLOG("focusing direction %d\n", direction);
-
- int new_row = current_row,
- new_col = current_col;
- Container *container = CUR_CELL;
- Workspace *t_ws = c_ws;
-
- /* Makes sure new_col and new_row are within bounds of the new workspace */
-#define CHECK_COLROW_BOUNDARIES \
- do { \
- if (new_col >= t_ws->cols) \
- new_col = (t_ws->cols - 1); \
- if (new_row >= t_ws->rows) \
- new_row = (t_ws->rows - 1); \
- } while (0)
-
- /* There always is a container. If not, current_col or current_row is wrong */
- assert(container != NULL);
-
- if (container->workspace->fullscreen_client != NULL) {
- LOG("You're in fullscreen mode. Forcing focus to operate on whole screens\n");
- thing = THING_SCREEN;
- }
-
- /* For focusing screens, situation is different: we get the rect
- * of the current screen, then get the screen which is on its
- * right/left/bottom/top and just switch to the workspace on
- * the target screen. */
- if (thing == THING_SCREEN) {
- Output *cs = c_ws->output;
- assert(cs != NULL);
- Rect bounds = cs->rect;
-
- if (direction == D_RIGHT)
- bounds.x += bounds.width;
- else if (direction == D_LEFT)
- bounds.x -= bounds.width;
- else if (direction == D_UP)
- bounds.y -= bounds.height;
- else bounds.y += bounds.height;
-
- Output *target = get_output_containing(bounds.x, bounds.y);
- if (target == NULL) {
- DLOG("Target output NULL\n");
- /* Wrap around if the target screen is out of bounds */
- if (direction == D_RIGHT)
- target = get_output_most(D_LEFT, cs);
- else if (direction == D_LEFT)
- target = get_output_most(D_RIGHT, cs);
- else if (direction == D_UP)
- target = get_output_most(D_DOWN, cs);
- else target = get_output_most(D_UP, cs);
- }
-
- DLOG("Switching to ws %d\n", target->current_workspace + 1);
- workspace_show(conn, target->current_workspace->num + 1);
- return;
- }
-
- /* TODO: for horizontal default layout, this has to be expanded to LEFT/RIGHT */
- if (direction == D_UP || direction == D_DOWN) {
- if (thing == THING_WINDOW)
- /* Let’s see if we can perform up/down focus in the current container */
- if (focus_window_in_container(conn, container, direction))
- return;
-
- if (direction == D_DOWN && cell_exists(t_ws, current_col, current_row+1))
- new_row = current_row + t_ws->table[current_col][current_row]->rowspan;
- else if (direction == D_UP && cell_exists(c_ws, current_col, current_row-1)) {
- /* Set new_row as a sane default, but it may get overwritten in a second */
- new_row--;
-
- /* Search from the top to correctly handle rowspanned containers */
- for (int rows = 0; rows < current_row; rows += t_ws->table[current_col][rows]->rowspan) {
- if (new_row > (rows + (t_ws->table[current_col][rows]->rowspan - 1)))
- continue;
-
- new_row = rows;
- break;
- }
- } else {
- /* Let’s see if there is a screen down/up there to which we can switch */
- DLOG("container is at %d with height %d\n", container->y, container->height);
- Output *output;
- int destination_y = (direction == D_UP ? (container->y - 1) : (container->y + container->height + 1));
- if ((output = get_output_containing(container->x, destination_y)) == NULL) {
- DLOG("Wrapping screen around vertically\n");
- /* No screen found? Then wrap */
- output = get_output_most((direction == D_UP ? D_DOWN : D_UP), container->workspace->output);
- }
- t_ws = output->current_workspace;
- new_row = (direction == D_UP ? (t_ws->rows - 1) : 0);
- }
-
- CHECK_COLROW_BOUNDARIES;
-
- DLOG("new_col = %d, new_row = %d\n", new_col, new_row);
- if (t_ws->table[new_col][new_row]->currently_focused == NULL) {
- DLOG("Cell empty, checking for colspanned client above...\n");
- for (int cols = 0; cols < new_col; cols += t_ws->table[cols][new_row]->colspan) {
- if (new_col > (cols + (t_ws->table[cols][new_row]->colspan - 1)))
- continue;
-
- new_col = cols;
- DLOG("Fixed it to new col %d\n", new_col);
- break;
- }
- }
-
- if (t_ws->table[new_col][new_row]->currently_focused == NULL) {
- DLOG("Cell still empty, checking for full cols above spanned width...\n");
- DLOG("new_col = %d\n", new_col);
- DLOG("colspan = %d\n", container->colspan);
- for (int cols = new_col;
- cols < container->col + container->colspan;
- cols += t_ws->table[cols][new_row]->colspan) {
- DLOG("candidate: new_row = %d, cols = %d\n", new_row, cols);
- if (t_ws->table[cols][new_row]->currently_focused == NULL)
- continue;
-
- new_col = cols;
- DLOG("Fixed it to new col %d\n", new_col);
- break;
- }
- }
- } else if (direction == D_LEFT || direction == D_RIGHT) {
- if (direction == D_RIGHT && cell_exists(t_ws, current_col+1, current_row))
- new_col = current_col + t_ws->table[current_col][current_row]->colspan;
- else if (direction == D_LEFT && cell_exists(t_ws, current_col-1, current_row)) {
- /* Set new_col as a sane default, but it may get overwritten in a second */
- new_col--;
-
- /* Search from the left to correctly handle colspanned containers */
- for (int cols = 0; cols < current_col; cols += t_ws->table[cols][current_row]->colspan) {
- if (new_col > (cols + (t_ws->table[cols][current_row]->colspan - 1)))
- continue;
-
- new_col = cols;
- break;
- }
- } else {
- /* Let’s see if there is a screen left/right here to which we can switch */
- DLOG("container is at %d with width %d\n", container->x, container->width);
- Output *output;
- int destination_x = (direction == D_LEFT ? (container->x - 1) : (container->x + container->width + 1));
- if ((output = get_output_containing(destination_x, container->y)) == NULL) {
- DLOG("Wrapping screen around horizontally\n");
- output = get_output_most((direction == D_LEFT ? D_RIGHT : D_LEFT), container->workspace->output);
- }
- t_ws = output->current_workspace;
- new_col = (direction == D_LEFT ? (t_ws->cols - 1) : 0);
- }
-
- CHECK_COLROW_BOUNDARIES;
-
- DLOG("new_col = %d, new_row = %d\n", new_col, new_row);
- if (t_ws->table[new_col][new_row]->currently_focused == NULL) {
- DLOG("Cell empty, checking for rowspanned client above...\n");
- for (int rows = 0; rows < new_row; rows += t_ws->table[new_col][rows]->rowspan) {
- if (new_row > (rows + (t_ws->table[new_col][rows]->rowspan - 1)))
- continue;
-
- new_row = rows;
- DLOG("Fixed it to new row %d\n", new_row);
- break;
- }
- }
-
- if (t_ws->table[new_col][new_row]->currently_focused == NULL) {
- DLOG("Cell still empty, checking for full cols near full spanned height...\n");
- DLOG("new_row = %d\n", new_row);
- DLOG("rowspan = %d\n", container->rowspan);
- for (int rows = new_row;
- rows < container->row + container->rowspan;
- rows += t_ws->table[new_col][rows]->rowspan) {
- DLOG("candidate: new_col = %d, rows = %d\n", new_col, rows);
- if (t_ws->table[new_col][rows]->currently_focused == NULL)
- continue;
-
- new_row = rows;
- DLOG("Fixed it to new col %d\n", new_row);
- break;
- }
- }
-
- } else {
- ELOG("direction unhandled\n");
- return;
- }
-
- CHECK_COLROW_BOUNDARIES;
-
- if (t_ws->table[new_col][new_row]->currently_focused != NULL)
- set_focus(conn, t_ws->table[new_col][new_row]->currently_focused, true);