diff options
Diffstat (limited to 'sway/input/seat.c')
-rw-r--r-- | sway/input/seat.c | 183 |
1 files changed, 152 insertions, 31 deletions
diff --git a/sway/input/seat.c b/sway/input/seat.c index 5e87986d..648e7914 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -32,6 +32,81 @@ void sway_seat_destroy(struct sway_seat *seat) { | |||
32 | wlr_seat_destroy(seat->wlr_seat); | 32 | wlr_seat_destroy(seat->wlr_seat); |
33 | } | 33 | } |
34 | 34 | ||
35 | static void handle_seat_container_destroy(struct wl_listener *listener, | ||
36 | void *data) { | ||
37 | struct sway_seat_container *seat_con = | ||
38 | wl_container_of(listener, seat_con, destroy); | ||
39 | struct sway_seat *seat = seat_con->seat; | ||
40 | swayc_t *con = seat_con->container; | ||
41 | |||
42 | bool is_focus = (sway_seat_get_focus(seat) == con); | ||
43 | |||
44 | wl_list_remove(&seat_con->link); | ||
45 | |||
46 | if (is_focus) { | ||
47 | // pick next focus | ||
48 | sway_seat_set_focus(seat, NULL); | ||
49 | swayc_t *next = sway_seat_get_focus_inactive(seat, con->parent); | ||
50 | if (next == NULL) { | ||
51 | next = con->parent; | ||
52 | } | ||
53 | sway_seat_set_focus(seat, next); | ||
54 | } | ||
55 | |||
56 | wl_list_remove(&seat_con->destroy.link); | ||
57 | |||
58 | free(seat_con); | ||
59 | } | ||
60 | |||
61 | static struct sway_seat_container *seat_container_from_container( | ||
62 | struct sway_seat *seat, swayc_t *con) { | ||
63 | if (con->type < C_WORKSPACE) { | ||
64 | // these don't get seat containers ever | ||
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | struct sway_seat_container *seat_con = NULL; | ||
69 | wl_list_for_each(seat_con, &seat->focus_stack, link) { | ||
70 | if (seat_con->container == con) { | ||
71 | return seat_con; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | seat_con = calloc(1, sizeof(struct sway_seat_container)); | ||
76 | if (seat_con == NULL) { | ||
77 | wlr_log(L_ERROR, "could not allocate seat container"); | ||
78 | return NULL; | ||
79 | } | ||
80 | |||
81 | seat_con->container = con; | ||
82 | seat_con->seat = seat; | ||
83 | wl_list_insert(seat->focus_stack.prev, &seat_con->link); | ||
84 | wl_signal_add(&con->events.destroy, &seat_con->destroy); | ||
85 | seat_con->destroy.notify = handle_seat_container_destroy; | ||
86 | |||
87 | return seat_con; | ||
88 | } | ||
89 | |||
90 | static void handle_new_container(struct wl_listener *listener, void *data) { | ||
91 | struct sway_seat *seat = wl_container_of(listener, seat, new_container); | ||
92 | swayc_t *con = data; | ||
93 | seat_container_from_container(seat, con); | ||
94 | } | ||
95 | |||
96 | static void collect_focus_iter(swayc_t *con, void *data) { | ||
97 | struct sway_seat *seat = data; | ||
98 | if (con->type > C_WORKSPACE) { | ||
99 | return; | ||
100 | } | ||
101 | struct sway_seat_container *seat_con = | ||
102 | seat_container_from_container(seat, con); | ||
103 | if (!seat_con) { | ||
104 | return; | ||
105 | } | ||
106 | wl_list_remove(&seat_con->link); | ||
107 | wl_list_insert(&seat->focus_stack, &seat_con->link); | ||
108 | } | ||
109 | |||
35 | struct sway_seat *sway_seat_create(struct sway_input_manager *input, | 110 | struct sway_seat *sway_seat_create(struct sway_input_manager *input, |
36 | const char *seat_name) { | 111 | const char *seat_name) { |
37 | struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); | 112 | struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); |
@@ -52,6 +127,15 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input, | |||
52 | return NULL; | 127 | return NULL; |
53 | } | 128 | } |
54 | 129 | ||
130 | // init the focus stack | ||
131 | wl_list_init(&seat->focus_stack); | ||
132 | |||
133 | container_for_each_bfs(&root_container, collect_focus_iter, seat); | ||
134 | |||
135 | wl_signal_add(&root_container.sway_root->events.new_container, | ||
136 | &seat->new_container); | ||
137 | seat->new_container.notify = handle_new_container; | ||
138 | |||
55 | seat->input = input; | 139 | seat->input = input; |
56 | wl_list_init(&seat->devices); | 140 | wl_list_init(&seat->devices); |
57 | 141 | ||
@@ -81,13 +165,14 @@ static void seat_configure_keyboard(struct sway_seat *seat, | |||
81 | struct wlr_keyboard *wlr_keyboard = seat_device->input_device->wlr_device->keyboard; | 165 | struct wlr_keyboard *wlr_keyboard = seat_device->input_device->wlr_device->keyboard; |
82 | sway_keyboard_configure(seat_device->keyboard); | 166 | sway_keyboard_configure(seat_device->keyboard); |
83 | wlr_seat_set_keyboard(seat->wlr_seat, | 167 | wlr_seat_set_keyboard(seat->wlr_seat, |
84 | seat_device->input_device->wlr_device); | 168 | seat_device->input_device->wlr_device); |
85 | if (seat->focus && seat->focus->type == C_VIEW) { | 169 | swayc_t *focus = sway_seat_get_focus(seat); |
170 | if (focus && focus->type == C_VIEW) { | ||
86 | // force notify reenter to pick up the new configuration | 171 | // force notify reenter to pick up the new configuration |
87 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); | 172 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); |
88 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | 173 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, |
89 | seat->focus->sway_view->surface, wlr_keyboard->keycodes, | 174 | focus->sway_view->surface, wlr_keyboard->keycodes, |
90 | wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); | 175 | wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); |
91 | } | 176 | } |
92 | } | 177 | } |
93 | 178 | ||
@@ -204,47 +289,83 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) { | |||
204 | seat->cursor->cursor->y); | 289 | seat->cursor->cursor->y); |
205 | } | 290 | } |
206 | 291 | ||
207 | static void handle_focus_destroy(struct wl_listener *listener, void *data) { | ||
208 | struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy); | ||
209 | swayc_t *container = data; | ||
210 | sway_seat_set_focus(seat, container->parent); | ||
211 | } | ||
212 | |||
213 | void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { | 292 | void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { |
214 | swayc_t *last_focus = seat->focus; | 293 | swayc_t *last_focus = sway_seat_get_focus(seat); |
215 | 294 | ||
216 | if (last_focus == container) { | 295 | if (container && last_focus == container) { |
217 | return; | 296 | return; |
218 | } | 297 | } |
219 | 298 | ||
220 | if (last_focus && last_focus->type == C_VIEW) { | 299 | if (container) { |
221 | wl_list_remove(&seat->focus_destroy.link); | 300 | struct sway_seat_container *seat_con = |
222 | } | 301 | seat_container_from_container(seat, container); |
302 | if (!seat_con) { | ||
303 | return; | ||
304 | } | ||
223 | 305 | ||
224 | if (container && container->type == C_VIEW) { | 306 | wl_list_remove(&seat_con->link); |
225 | struct sway_view *view = container->sway_view; | 307 | wl_list_insert(&seat->focus_stack, &seat_con->link); |
226 | view_set_activated(view, true); | 308 | |
227 | wl_signal_add(&container->events.destroy, &seat->focus_destroy); | 309 | if (container->type == C_VIEW) { |
228 | seat->focus_destroy.notify = handle_focus_destroy; | 310 | struct sway_view *view = container->sway_view; |
229 | 311 | view_set_activated(view, true); | |
230 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); | 312 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); |
231 | if (keyboard) { | 313 | if (keyboard) { |
232 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, | 314 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, |
233 | keyboard->keycodes, keyboard->num_keycodes, | 315 | keyboard->keycodes, keyboard->num_keycodes, |
234 | &keyboard->modifiers); | 316 | &keyboard->modifiers); |
235 | } else { | 317 | } else { |
236 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, | 318 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, |
237 | NULL, 0, NULL); | 319 | NULL, 0, NULL); |
320 | } | ||
238 | } | 321 | } |
239 | } | 322 | } |
240 | 323 | ||
241 | seat->focus = container; | ||
242 | |||
243 | if (last_focus && last_focus->type == C_VIEW && | 324 | if (last_focus && last_focus->type == C_VIEW && |
244 | !sway_input_manager_has_focus(seat->input, last_focus)) { | 325 | !sway_input_manager_has_focus(seat->input, last_focus)) { |
245 | struct sway_view *view = last_focus->sway_view; | 326 | struct sway_view *view = last_focus->sway_view; |
246 | view_set_activated(view, false); | 327 | view_set_activated(view, false); |
247 | } | 328 | } |
329 | |||
330 | seat->has_focus = (container != NULL); | ||
331 | } | ||
332 | |||
333 | swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container) { | ||
334 | struct sway_seat_container *current = NULL; | ||
335 | swayc_t *parent = NULL; | ||
336 | wl_list_for_each(current, &seat->focus_stack, link) { | ||
337 | parent = current->container->parent; | ||
338 | |||
339 | if (current->container == container) { | ||
340 | return current->container; | ||
341 | } | ||
342 | |||
343 | while (parent) { | ||
344 | if (parent == container) { | ||
345 | return current->container; | ||
346 | } | ||
347 | parent = parent->parent; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | return NULL; | ||
352 | } | ||
353 | |||
354 | swayc_t *sway_seat_get_focus(struct sway_seat *seat) { | ||
355 | if (!seat->has_focus) { | ||
356 | return NULL; | ||
357 | } | ||
358 | return sway_seat_get_focus_inactive(seat, &root_container); | ||
359 | } | ||
360 | |||
361 | swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat, | ||
362 | enum swayc_types type) { | ||
363 | swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container); | ||
364 | if (focus->type == type) { | ||
365 | return focus; | ||
366 | } | ||
367 | |||
368 | return swayc_parent_by_type(focus, type); | ||
248 | } | 369 | } |
249 | 370 | ||
250 | void sway_seat_set_config(struct sway_seat *seat, | 371 | void sway_seat_set_config(struct sway_seat *seat, |