Skip to content
This repository has been archived by the owner on Apr 18, 2023. It is now read-only.

Commit

Permalink
Refactor tree_next
Browse files Browse the repository at this point in the history
- Makes `tree_next` not recursive.
- Adds `focus next|prev [sibling]` command. See (1.) and (2.) in
i3/i3#2587 (comment) (Issue also
requests move command, not implemented here).
- Directional focus command now supports command criteria.

Wrapping is not implemented inside a floating container. This was also
true before the refactor so I am not changing it here.
  • Loading branch information
orestisfl committed Oct 14, 2019
1 parent f402f45 commit bbc4c99
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 164 deletions.
7 changes: 7 additions & 0 deletions docs/userguide
Expand Up @@ -2053,6 +2053,12 @@ parent::
child::
The opposite of +focus parent+, sets the focus to the last focused
child container.
next|prev::
Automatically sets focus to the adjacent container. If +sibling+ is
specified, the command will focus the exact sibling container,
including non-leaf containers like split containers. Otherwise, it is
an automatic version of +focus left|right|up|down+ in the orientation
of the parent container.
floating::
Sets focus to the last focused floating container.
tiling::
Expand All @@ -2068,6 +2074,7 @@ output::
<criteria> focus
focus left|right|down|up
focus parent|child|floating|tiling|mode_toggle
focus next|prev [sibling]
focus output left|right|up|down|primary|<output>
----------------------------------------------

Expand Down
6 changes: 6 additions & 0 deletions include/commands.h
Expand Up @@ -182,6 +182,12 @@ void cmd_exec(I3_CMD, const char *nosn, const char *command);
*/
void cmd_focus_direction(I3_CMD, const char *direction);

/**
* Implementation of 'focus next|prev sibling'
*
*/
void cmd_focus_sibling(I3_CMD, const char *direction);

/**
* Implementation of 'focus tiling|floating|mode_toggle'.
*
Expand Down
11 changes: 8 additions & 3 deletions include/tree.h
Expand Up @@ -59,11 +59,16 @@ bool level_down(void);
void tree_render(void);

/**
* Changes focus in the given way (next/previous) and given orientation
* (horizontal/vertical).
* Changes focus in the given direction
*
*/
void tree_next(char way, orientation_t orientation);
void tree_next(Con *con, direction_t direction);

/**
* Get the previous / next sibling
*
*/
Con *get_tree_next_sibling(Con *con, position_t direction);

/**
* Closes the given container including all children.
Expand Down
8 changes: 8 additions & 0 deletions parser-specs/commands.spec
Expand Up @@ -146,6 +146,8 @@ state WORKSPACE_NUMBER:
state FOCUS:
direction = 'left', 'right', 'up', 'down'
-> call cmd_focus_direction($direction)
direction = 'prev', 'next'
-> FOCUS_AUTO
'output'
-> FOCUS_OUTPUT
window_mode = 'tiling', 'floating', 'mode_toggle'
Expand All @@ -155,6 +157,12 @@ state FOCUS:
end
-> call cmd_focus()

state FOCUS_AUTO:
'sibling'
-> call cmd_focus_sibling($direction)
end
-> call cmd_focus_direction($direction)

state FOCUS_OUTPUT:
output = string
-> call cmd_focus_output($output)
Expand Down
18 changes: 5 additions & 13 deletions src/click.c
Expand Up @@ -212,21 +212,13 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod
event->detail == XCB_BUTTON_SCROLL_LEFT ||
event->detail == XCB_BUTTON_SCROLL_RIGHT)) {
DLOG("Scrolling on a window decoration\n");
orientation_t orientation = con_orientation(con->parent);
/* Use the focused child of the tabbed / stacked container, not the
* container the user scrolled on. */
Con *focused = con->parent;
focused = TAILQ_FIRST(&(focused->focus_head));
con_activate(con_descend_focused(focused));
/* To prevent scrolling from going outside the container (see ticket
* #557), we first check if scrolling is possible at all. */
bool scroll_prev_possible = (TAILQ_PREV(focused, nodes_head, nodes) != NULL);
bool scroll_next_possible = (TAILQ_NEXT(focused, nodes) != NULL);
if ((event->detail == XCB_BUTTON_SCROLL_UP || event->detail == XCB_BUTTON_SCROLL_LEFT) && scroll_prev_possible) {
tree_next('p', orientation);
} else if ((event->detail == XCB_BUTTON_SCROLL_DOWN || event->detail == XCB_BUTTON_SCROLL_RIGHT) && scroll_next_possible) {
tree_next('n', orientation);
}
Con *current = TAILQ_FIRST(&(con->parent->focus_head));
const position_t direction =
(event->detail == XCB_BUTTON_SCROLL_UP || event->detail == XCB_BUTTON_SCROLL_LEFT) ? BEFORE : AFTER;
Con *next = get_tree_next_sibling(current, direction);
con_activate(con_descend_focused(next ? next : current));

goto done;
}
Expand Down
69 changes: 54 additions & 15 deletions src/commands.c
Expand Up @@ -1229,23 +1229,62 @@ void cmd_exec(I3_CMD, const char *nosn, const char *command) {
} while (0)

/*
* Implementation of 'focus left|right|up|down'.
* Implementation of 'focus left|right|up|down|next|prev'.
*
*/
void cmd_focus_direction(I3_CMD, const char *direction) {
switch (parse_direction(direction)) {
case D_LEFT:
tree_next('p', HORIZ);
break;
case D_RIGHT:
tree_next('n', HORIZ);
break;
case D_UP:
tree_next('p', VERT);
break;
case D_DOWN:
tree_next('n', VERT);
break;
void cmd_focus_direction(I3_CMD, const char *direction_str) {
HANDLE_EMPTY_MATCH;
CMD_FOCUS_WARN_CHILDREN;

direction_t direction;
position_t position;
bool auto_direction = true;
if (strcmp(direction_str, "prev") == 0) {
position = BEFORE;
} else if (strcmp(direction_str, "next") == 0) {
position = AFTER;
} else {
auto_direction = false;
direction = parse_direction(direction_str);
}

owindow *current;
TAILQ_FOREACH(current, &owindows, owindows) {
Con *ws = con_get_workspace(current->con);
if (!ws || con_is_internal(ws)) {
continue;
}
if (auto_direction) {
orientation_t o = con_orientation(current->con->parent);
direction = direction_from_orientation_position(o, position);
}
tree_next(current->con, direction);
}

cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
ysuccess(true);
}

/*
* Implementation of 'focus next|prev sibling'
*
*/
void cmd_focus_sibling(I3_CMD, const char *direction_str) {
HANDLE_EMPTY_MATCH;
CMD_FOCUS_WARN_CHILDREN;

const position_t direction = (STARTS_WITH(direction_str, "prev")) ? BEFORE : AFTER;
owindow *current;
TAILQ_FOREACH(current, &owindows, owindows) {
Con *ws = con_get_workspace(current->con);
if (!ws || con_is_internal(ws)) {
continue;
}
Con *next = get_tree_next_sibling(current->con, direction);
if (next) {
con_activate(next);
}
}

cmd_output->needs_tree_render = true;
Expand Down

0 comments on commit bbc4c99

Please sign in to comment.