diff options
author | Alexander Orzechowski <alex@ozal.ski> | 2023-11-23 10:09:48 -0500 |
---|---|---|
committer | Kirill Primak <vyivel@eclair.cafe> | 2024-01-18 18:36:54 +0300 |
commit | 5b8b505af5d5925ae9e617ee8f3c7a0f9c43409d (patch) | |
tree | f420022ad3a48215f9182505c0060d91edcd848e /sway/tree/container.c | |
parent | Introduce sway_text_node (diff) | |
download | sway-5b8b505af5d5925ae9e617ee8f3c7a0f9c43409d.tar.gz sway-5b8b505af5d5925ae9e617ee8f3c7a0f9c43409d.tar.zst sway-5b8b505af5d5925ae9e617ee8f3c7a0f9c43409d.zip |
input: Query scene graph for relevant surface/node intersections
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r-- | sway/tree/container.c | 265 |
1 files changed, 6 insertions, 259 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c index 307bf963..8fca6a12 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include "sway/input/input-manager.h" | 16 | #include "sway/input/input-manager.h" |
17 | #include "sway/input/seat.h" | 17 | #include "sway/input/seat.h" |
18 | #include "sway/ipc-server.h" | 18 | #include "sway/ipc-server.h" |
19 | #include "sway/scene_descriptor.h" | ||
19 | #include "sway/output.h" | 20 | #include "sway/output.h" |
20 | #include "sway/server.h" | 21 | #include "sway/server.h" |
21 | #include "sway/surface.h" | 22 | #include "sway/surface.h" |
@@ -94,6 +95,11 @@ struct sway_container *container_create(struct sway_view *view) { | |||
94 | c->border.right = alloc_rect_node(c->border.tree, &failed); | 95 | c->border.right = alloc_rect_node(c->border.tree, &failed); |
95 | } | 96 | } |
96 | 97 | ||
98 | if (!failed && !scene_descriptor_assign(&c->scene_tree->node, | ||
99 | SWAY_SCENE_DESC_CONTAINER, c)) { | ||
100 | failed = true; | ||
101 | } | ||
102 | |||
97 | if (failed) { | 103 | if (failed) { |
98 | wlr_scene_node_destroy(&c->scene_tree->node); | 104 | wlr_scene_node_destroy(&c->scene_tree->node); |
99 | free(c); | 105 | free(c); |
@@ -239,265 +245,6 @@ struct sway_container *container_find_child(struct sway_container *container, | |||
239 | return NULL; | 245 | return NULL; |
240 | } | 246 | } |
241 | 247 | ||
242 | static struct sway_container *surface_at_view(struct sway_container *con, double lx, double ly, | ||
243 | struct wlr_surface **surface, double *sx, double *sy) { | ||
244 | if (!sway_assert(con->view, "Expected a view")) { | ||
245 | return NULL; | ||
246 | } | ||
247 | struct sway_view *view = con->view; | ||
248 | double view_sx = lx - con->surface_x + view->geometry.x; | ||
249 | double view_sy = ly - con->surface_y + view->geometry.y; | ||
250 | |||
251 | double _sx, _sy; | ||
252 | struct wlr_surface *_surface = NULL; | ||
253 | switch (view->type) { | ||
254 | #if HAVE_XWAYLAND | ||
255 | case SWAY_VIEW_XWAYLAND: | ||
256 | _surface = wlr_surface_surface_at(view->surface, | ||
257 | view_sx, view_sy, &_sx, &_sy); | ||
258 | break; | ||
259 | #endif | ||
260 | case SWAY_VIEW_XDG_SHELL: | ||
261 | _surface = wlr_xdg_surface_surface_at( | ||
262 | view->wlr_xdg_toplevel->base, | ||
263 | view_sx, view_sy, &_sx, &_sy); | ||
264 | break; | ||
265 | } | ||
266 | if (_surface) { | ||
267 | *sx = _sx; | ||
268 | *sy = _sy; | ||
269 | *surface = _surface; | ||
270 | return con; | ||
271 | } | ||
272 | return NULL; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * container_at for a container with layout L_TABBED. | ||
277 | */ | ||
278 | static struct sway_container *container_at_tabbed(struct sway_node *parent, | ||
279 | double lx, double ly, | ||
280 | struct wlr_surface **surface, double *sx, double *sy) { | ||
281 | struct wlr_box box; | ||
282 | node_get_box(parent, &box); | ||
283 | if (lx < box.x || lx > box.x + box.width || | ||
284 | ly < box.y || ly > box.y + box.height) { | ||
285 | return NULL; | ||
286 | } | ||
287 | struct sway_seat *seat = input_manager_current_seat(); | ||
288 | list_t *children = node_get_children(parent); | ||
289 | if (!children->length) { | ||
290 | return NULL; | ||
291 | } | ||
292 | |||
293 | // Tab titles | ||
294 | int title_height = container_titlebar_height(); | ||
295 | if (ly < box.y + title_height) { | ||
296 | int tab_width = box.width / children->length; | ||
297 | int child_index = (lx - box.x) / tab_width; | ||
298 | if (child_index >= children->length) { | ||
299 | child_index = children->length - 1; | ||
300 | } | ||
301 | struct sway_container *child = children->items[child_index]; | ||
302 | return child; | ||
303 | } | ||
304 | |||
305 | // Surfaces | ||
306 | struct sway_node *current = seat_get_active_tiling_child(seat, parent); | ||
307 | return current ? tiling_container_at(current, lx, ly, surface, sx, sy) : NULL; | ||
308 | } | ||
309 | |||
310 | /** | ||
311 | * container_at for a container with layout L_STACKED. | ||
312 | */ | ||
313 | static struct sway_container *container_at_stacked(struct sway_node *parent, | ||
314 | double lx, double ly, | ||
315 | struct wlr_surface **surface, double *sx, double *sy) { | ||
316 | struct wlr_box box; | ||
317 | node_get_box(parent, &box); | ||
318 | if (lx < box.x || lx > box.x + box.width || | ||
319 | ly < box.y || ly > box.y + box.height) { | ||
320 | return NULL; | ||
321 | } | ||
322 | struct sway_seat *seat = input_manager_current_seat(); | ||
323 | list_t *children = node_get_children(parent); | ||
324 | |||
325 | // Title bars | ||
326 | int title_height = container_titlebar_height(); | ||
327 | if (title_height > 0) { | ||
328 | int child_index = (ly - box.y) / title_height; | ||
329 | if (child_index < children->length) { | ||
330 | struct sway_container *child = children->items[child_index]; | ||
331 | return child; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | // Surfaces | ||
336 | struct sway_node *current = seat_get_active_tiling_child(seat, parent); | ||
337 | return current ? tiling_container_at(current, lx, ly, surface, sx, sy) : NULL; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * container_at for a container with layout L_HORIZ or L_VERT. | ||
342 | */ | ||
343 | static struct sway_container *container_at_linear(struct sway_node *parent, | ||
344 | double lx, double ly, | ||
345 | struct wlr_surface **surface, double *sx, double *sy) { | ||
346 | list_t *children = node_get_children(parent); | ||
347 | for (int i = 0; i < children->length; ++i) { | ||
348 | struct sway_container *child = children->items[i]; | ||
349 | struct sway_container *container = | ||
350 | tiling_container_at(&child->node, lx, ly, surface, sx, sy); | ||
351 | if (container) { | ||
352 | return container; | ||
353 | } | ||
354 | } | ||
355 | return NULL; | ||
356 | } | ||
357 | |||
358 | static struct sway_container *floating_container_at(double lx, double ly, | ||
359 | struct wlr_surface **surface, double *sx, double *sy) { | ||
360 | // For outputs with floating containers that overhang the output bounds, | ||
361 | // those at the end of the output list appear on top of floating | ||
362 | // containers from other outputs, so iterate the list in reverse. | ||
363 | for (int i = root->outputs->length - 1; i >= 0; --i) { | ||
364 | struct sway_output *output = root->outputs->items[i]; | ||
365 | for (int j = 0; j < output->workspaces->length; ++j) { | ||
366 | struct sway_workspace *ws = output->workspaces->items[j]; | ||
367 | if (!workspace_is_visible(ws)) { | ||
368 | continue; | ||
369 | } | ||
370 | // Items at the end of the list are on top, so iterate the list in | ||
371 | // reverse. | ||
372 | for (int k = ws->floating->length - 1; k >= 0; --k) { | ||
373 | struct sway_container *floater = ws->floating->items[k]; | ||
374 | struct sway_container *container = | ||
375 | tiling_container_at(&floater->node, lx, ly, surface, sx, sy); | ||
376 | if (container) { | ||
377 | return container; | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | } | ||
382 | return NULL; | ||
383 | } | ||
384 | |||
385 | static struct sway_container *view_container_content_at(struct sway_node *parent, | ||
386 | double lx, double ly, | ||
387 | struct wlr_surface **surface, double *sx, double *sy) { | ||
388 | if (!sway_assert(node_is_view(parent), "Expected a view")) { | ||
389 | return NULL; | ||
390 | } | ||
391 | |||
392 | struct sway_container *container = parent->sway_container; | ||
393 | struct wlr_box box = { | ||
394 | .x = container->pending.content_x, | ||
395 | .y = container->pending.content_y, | ||
396 | .width = container->pending.content_width, | ||
397 | .height = container->pending.content_height, | ||
398 | }; | ||
399 | |||
400 | if (wlr_box_contains_point(&box, lx, ly)) { | ||
401 | surface_at_view(parent->sway_container, lx, ly, surface, sx, sy); | ||
402 | return container; | ||
403 | } | ||
404 | |||
405 | return NULL; | ||
406 | } | ||
407 | |||
408 | static struct sway_container *view_container_at(struct sway_node *parent, | ||
409 | double lx, double ly, | ||
410 | struct wlr_surface **surface, double *sx, double *sy) { | ||
411 | if (!sway_assert(node_is_view(parent), "Expected a view")) { | ||
412 | return NULL; | ||
413 | } | ||
414 | |||
415 | struct sway_container *container = parent->sway_container; | ||
416 | struct wlr_box box = { | ||
417 | .x = container->pending.x, | ||
418 | .y = container->pending.y, | ||
419 | .width = container->pending.width, | ||
420 | .height = container->pending.height, | ||
421 | }; | ||
422 | |||
423 | if (wlr_box_contains_point(&box, lx, ly)) { | ||
424 | surface_at_view(parent->sway_container, lx, ly, surface, sx, sy); | ||
425 | return container; | ||
426 | } | ||
427 | |||
428 | return NULL; | ||
429 | } | ||
430 | |||
431 | struct sway_container *tiling_container_at(struct sway_node *parent, | ||
432 | double lx, double ly, | ||
433 | struct wlr_surface **surface, double *sx, double *sy) { | ||
434 | if (node_is_view(parent)) { | ||
435 | return view_container_at(parent, lx, ly, surface, sx, sy); | ||
436 | } | ||
437 | if (!node_get_children(parent)) { | ||
438 | return NULL; | ||
439 | } | ||
440 | switch (node_get_layout(parent)) { | ||
441 | case L_HORIZ: | ||
442 | case L_VERT: | ||
443 | return container_at_linear(parent, lx, ly, surface, sx, sy); | ||
444 | case L_TABBED: | ||
445 | return container_at_tabbed(parent, lx, ly, surface, sx, sy); | ||
446 | case L_STACKED: | ||
447 | return container_at_stacked(parent, lx, ly, surface, sx, sy); | ||
448 | case L_NONE: | ||
449 | return NULL; | ||
450 | } | ||
451 | return NULL; | ||
452 | } | ||
453 | |||
454 | static bool surface_is_popup(struct wlr_surface *surface) { | ||
455 | while (wlr_xdg_surface_try_from_wlr_surface(surface) == NULL) { | ||
456 | struct wlr_subsurface *subsurface = | ||
457 | wlr_subsurface_try_from_wlr_surface(surface); | ||
458 | if (subsurface == NULL) { | ||
459 | return false; | ||
460 | } | ||
461 | surface = subsurface->parent; | ||
462 | } | ||
463 | struct wlr_xdg_surface *xdg_surface = | ||
464 | wlr_xdg_surface_try_from_wlr_surface(surface); | ||
465 | return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP && xdg_surface->popup != NULL; | ||
466 | } | ||
467 | |||
468 | struct sway_container *container_at(struct sway_workspace *workspace, | ||
469 | double lx, double ly, | ||
470 | struct wlr_surface **surface, double *sx, double *sy) { | ||
471 | struct sway_container *c; | ||
472 | |||
473 | struct sway_seat *seat = input_manager_current_seat(); | ||
474 | struct sway_container *focus = seat_get_focused_container(seat); | ||
475 | bool is_floating = focus && container_is_floating_or_child(focus); | ||
476 | // Focused view's popups | ||
477 | if (focus && focus->view) { | ||
478 | c = surface_at_view(focus, lx, ly, surface, sx, sy); | ||
479 | if (c && surface_is_popup(*surface)) { | ||
480 | return c; | ||
481 | } | ||
482 | *surface = NULL; | ||
483 | } | ||
484 | // Floating | ||
485 | if ((c = floating_container_at(lx, ly, surface ,sx ,sy))) { | ||
486 | return c; | ||
487 | } | ||
488 | // Tiling (focused) | ||
489 | if (focus && focus->view && !is_floating) { | ||
490 | if ((c = view_container_content_at(&focus->node, lx, ly, surface, sx, sy))) { | ||
491 | return c; | ||
492 | } | ||
493 | } | ||
494 | // Tiling (non-focused) | ||
495 | if ((c = tiling_container_at(&workspace->node, lx, ly, surface, sx, sy))) { | ||
496 | return c; | ||
497 | } | ||
498 | return NULL; | ||
499 | } | ||
500 | |||
501 | void container_for_each_child(struct sway_container *container, | 248 | void container_for_each_child(struct sway_container *container, |
502 | void (*f)(struct sway_container *container, void *data), | 249 | void (*f)(struct sway_container *container, void *data), |
503 | void *data) { | 250 | void *data) { |