aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands/focus.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands/focus.c')
-rw-r--r--sway/commands/focus.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index 6659a683..a9fa9a0f 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -31,6 +31,199 @@ static bool parse_movement_direction(const char *name,
31 return true; 31 return true;
32} 32}
33 33
34/**
35 * Get swayc in the direction of newly entered output.
36 */
37static struct sway_container *get_swayc_in_output_direction(
38 struct sway_container *output, enum movement_direction dir,
39 struct sway_seat *seat) {
40 if (!output) {
41 return NULL;
42 }
43
44 struct sway_container *ws = seat_get_focus_inactive(seat, output);
45 if (ws->type != C_WORKSPACE) {
46 ws = container_parent(ws, C_WORKSPACE);
47 }
48
49 if (ws == NULL) {
50 wlr_log(WLR_ERROR, "got an output without a workspace");
51 return NULL;
52 }
53
54 if (ws->children->length > 0) {
55 switch (dir) {
56 case MOVE_LEFT:
57 if (ws->layout == L_HORIZ || ws->layout == L_TABBED) {
58 // get most right child of new output
59 return ws->children->items[ws->children->length-1];
60 } else {
61 return seat_get_focus_inactive(seat, ws);
62 }
63 case MOVE_RIGHT:
64 if (ws->layout == L_HORIZ || ws->layout == L_TABBED) {
65 // get most left child of new output
66 return ws->children->items[0];
67 } else {
68 return seat_get_focus_inactive(seat, ws);
69 }
70 case MOVE_UP:
71 case MOVE_DOWN: {
72 struct sway_container *focused =
73 seat_get_focus_inactive(seat, ws);
74 if (focused && focused->parent) {
75 struct sway_container *parent = focused->parent;
76 if (parent->layout == L_VERT) {
77 if (dir == MOVE_UP) {
78 // get child furthest down on new output
79 int idx = parent->children->length - 1;
80 return parent->children->items[idx];
81 } else if (dir == MOVE_DOWN) {
82 // get child furthest up on new output
83 return parent->children->items[0];
84 }
85 }
86 return focused;
87 }
88 break;
89 }
90 default:
91 break;
92 }
93 }
94
95 return ws;
96}
97
98static struct sway_container *container_get_in_direction(
99 struct sway_container *container, struct sway_seat *seat,
100 enum movement_direction dir) {
101 struct sway_container *parent = container->parent;
102
103 if (dir == MOVE_CHILD) {
104 return seat_get_focus_inactive(seat, container);
105 }
106 if (container->is_fullscreen) {
107 if (dir == MOVE_PARENT) {
108 return NULL;
109 }
110 container = container_parent(container, C_OUTPUT);
111 parent = container->parent;
112 } else {
113 if (dir == MOVE_PARENT) {
114 if (parent->type == C_OUTPUT || container_is_floating(container)) {
115 return NULL;
116 } else {
117 return parent;
118 }
119 }
120 }
121
122 struct sway_container *wrap_candidate = NULL;
123 while (true) {
124 bool can_move = false;
125 int desired;
126 int idx = list_find(container->parent->children, container);
127 if (idx == -1) {
128 return NULL;
129 }
130 if (parent->type == C_ROOT) {
131 enum wlr_direction wlr_dir = 0;
132 if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir),
133 "got invalid direction: %d", dir)) {
134 return NULL;
135 }
136 int lx = container->x + container->width / 2;
137 int ly = container->y + container->height / 2;
138 struct wlr_output_layout *layout =
139 root_container.sway_root->output_layout;
140 struct wlr_output *wlr_adjacent =
141 wlr_output_layout_adjacent_output(layout, wlr_dir,
142 container->sway_output->wlr_output, lx, ly);
143 struct sway_container *adjacent =
144 output_from_wlr_output(wlr_adjacent);
145
146 if (!adjacent || adjacent == container) {
147 if (!wrap_candidate) {
148 return NULL;
149 }
150 return seat_get_focus_inactive_view(seat, wrap_candidate);
151 }
152 struct sway_container *next =
153 get_swayc_in_output_direction(adjacent, dir, seat);
154 if (next == NULL) {
155 return NULL;
156 }
157 struct sway_container *next_workspace = next;
158 if (next_workspace->type != C_WORKSPACE) {
159 next_workspace = container_parent(next_workspace, C_WORKSPACE);
160 }
161 sway_assert(next_workspace, "Next container has no workspace");
162 if (next_workspace->sway_workspace->fullscreen) {
163 return seat_get_focus_inactive(seat,
164 next_workspace->sway_workspace->fullscreen);
165 }
166 if (next->children && next->children->length) {
167 // TODO consider floating children as well
168 return seat_get_focus_inactive_view(seat, next);
169 } else {
170 return next;
171 }
172 } else {
173 if (dir == MOVE_LEFT || dir == MOVE_RIGHT) {
174 if (parent->layout == L_HORIZ || parent->layout == L_TABBED) {
175 can_move = true;
176 desired = idx + (dir == MOVE_LEFT ? -1 : 1);
177 }
178 } else {
179 if (parent->layout == L_VERT || parent->layout == L_STACKED) {
180 can_move = true;
181 desired = idx + (dir == MOVE_UP ? -1 : 1);
182 }
183 }
184 }
185
186 if (can_move) {
187 // TODO handle floating
188 if (desired < 0 || desired >= parent->children->length) {
189 can_move = false;
190 int len = parent->children->length;
191 if (config->focus_wrapping != WRAP_NO && !wrap_candidate
192 && len > 1) {
193 if (desired < 0) {
194 wrap_candidate = parent->children->items[len-1];
195 } else {
196 wrap_candidate = parent->children->items[0];
197 }
198 if (config->focus_wrapping == WRAP_FORCE) {
199 return seat_get_focus_inactive_view(seat,
200 wrap_candidate);
201 }
202 }
203 } else {
204 struct sway_container *desired_con =
205 parent->children->items[desired];
206 wlr_log(WLR_DEBUG,
207 "cont %d-%p dir %i sibling %d: %p", idx,
208 container, dir, desired, desired_con);
209 return seat_get_focus_inactive_view(seat, desired_con);
210 }
211 }
212
213 if (!can_move) {
214 container = parent;
215 parent = parent->parent;
216 if (!parent) {
217 // wrapping is the last chance
218 if (!wrap_candidate) {
219 return NULL;
220 }
221 return seat_get_focus_inactive_view(seat, wrap_candidate);
222 }
223 }
224 }
225}
226
34static struct cmd_results *focus_mode(struct sway_container *con, 227static struct cmd_results *focus_mode(struct sway_container *con,
35 struct sway_seat *seat, bool floating) { 228 struct sway_seat *seat, bool floating) {
36 struct sway_container *ws = con->type == C_WORKSPACE ? 229 struct sway_container *ws = con->type == C_WORKSPACE ?