ssd: clean up scene management

Our codebase for ssd scenes has grown with a lot of technical debts:
- We needed to call `ssd_get_part()` everywhere to get the scene node of a
  ssd part. We then needed to cast it to `wlr_scene_rect` and
  `wlr_scene_buffer`. This bloated our codebase and even blocked
  duplicated button types in `<titlebar><layout>`.
- `ssd_get_part_type()` was a dirty hack. It compared parent, grandparent
  and grandgrandparent of a node with each subtree in the ssd to get the
  part type of the node.

To resolve this issues, this commit changes how ssd scenes are managed:
- Access scene rects and scene buffers just as a member of `struct ssd`.
- `ssd_part` is now a attachment to a scene node that can be accessed via
  node_descriptor->data, with a new node-descriptor type
  `LAB_NODE_DESC_SSD_PART`. `LAB_NODE_DESC_SSD_BUTTON` is unified into it.

Now the scene graph under ssd->tree looks like below. The parentheses
indicate the type of ssd_part attached to the node:

ssd->tree (LAB_SSD_NONE)
+--titlebar (LAB_SSD_PART_TITLEBAR)
|  +--inactive
|  |  +--background bar
|  |  +--left corner
|  |  +--right corner
|  |  +--title (LAB_SSD_PART_TITLE)
|  |  +--iconify button (LAB_SSD_BUTTON_ICONIFY)
|  |  |  +--normal close icon image
|  |  |  +--hovered close icon image
|  |  |  +--...
|  |  +--window icon (LAB_SSD_BUTTON_WINDOW_ICON)
|  |  |  +--window icon image
|  |  +--...
|  +--active
|     +--...
+--border
|  +--inactive
|  |  +--top
|  |  +--...
|  +--active
|     +--top
|     +--...
+--shadow
|  +--inactive
|  |  +--top
|  |  +--...
|  +--active
|     +--top
|     +--...
+--extents
   +--top
   +--...

When hovering on SSD, `get_cursor_context()` traverses this scene node
from the leaf. If it finds a `ssd_part` attached to the node, it returns
`ssd_part_type` that represents the resizing direction, button types or
`Title`/`Titlebar`.
This commit is contained in:
tokyo4j 2025-08-13 21:00:11 +09:00 committed by Johan Malm
parent aa3dbb4f85
commit f347a818e3
13 changed files with 516 additions and 726 deletions

View file

@ -11,22 +11,11 @@
#include "theme.h"
#include "view.h"
static struct ssd_part *
add_extent(struct wl_list *part_list, enum ssd_part_type type,
struct wlr_scene_tree *parent)
{
float invisible[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
struct ssd_part *part = add_scene_part(part_list, type);
part->node = &wlr_scene_rect_create(parent, 0, 0, invisible)->node;
return part;
}
void
ssd_extents_create(struct ssd *ssd)
{
struct view *view = ssd->view;
struct theme *theme = view->server->theme;
struct wl_list *part_list = &ssd->extents.parts;
int border_width = MAX(0, MAX(rc.resize_minimum_area, theme->border_width));
@ -35,14 +24,14 @@ ssd_extents_create(struct ssd *ssd)
if (view->fullscreen || view->maximized == VIEW_AXIS_BOTH) {
wlr_scene_node_set_enabled(&parent->node, false);
}
wl_list_init(&ssd->extents.parts);
wlr_scene_node_set_position(&parent->node,
-border_width, -(ssd->titlebar.height + border_width));
add_extent(part_list, LAB_SSD_PART_TOP, parent);
add_extent(part_list, LAB_SSD_PART_LEFT, parent);
add_extent(part_list, LAB_SSD_PART_RIGHT, parent);
add_extent(part_list, LAB_SSD_PART_BOTTOM, parent);
float invisible[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
ssd->extents.top = wlr_scene_rect_create(parent, 0, 0, invisible);
ssd->extents.left = wlr_scene_rect_create(parent, 0, 0, invisible);
ssd->extents.right = wlr_scene_rect_create(parent, 0, 0, invisible);
ssd->extents.bottom = wlr_scene_rect_create(parent, 0, 0, invisible);
/* Initial manual update to keep X11 applications happy */
ssd_extents_update(ssd);
@ -121,10 +110,6 @@ ssd_extents_update(struct ssd *ssd)
int border_width = MAX(rc.resize_minimum_area, theme->border_width);
int extended_area = MAX(0, rc.resize_minimum_area - theme->border_width);
struct ssd_part *part;
struct wlr_scene_rect *rect;
struct wlr_box target;
/* Make sure we update the y offset based on titlebar shown / hidden */
wlr_scene_node_set_position(&ssd->extents.tree->node,
-border_width, -(ssd->titlebar.height + border_width));
@ -151,43 +136,19 @@ ssd_extents_update(struct ssd *ssd)
wlr_scene_node_coords(&ssd->extents.tree->node, &base_x, &base_y);
pixman_region32_translate(&usable, -base_x, -base_y);
wl_list_for_each(part, &ssd->extents.parts, link) {
rect = wlr_scene_rect_from_node(part->node);
switch (part->type) {
case LAB_SSD_PART_TOP:
target.x = 0;
target.y = 0;
target.width = full_width + extended_area * 2;
target.height = extended_area;
break;
case LAB_SSD_PART_LEFT:
target.x = 0;
target.y = extended_area;
target.width = extended_area;
target.height = full_height;
break;
case LAB_SSD_PART_RIGHT:
target.x = extended_area + full_width;
target.y = extended_area;
target.width = extended_area;
target.height = full_height;
break;
case LAB_SSD_PART_BOTTOM:
target.x = 0;
target.y = extended_area + full_height;
target.width = full_width + extended_area * 2;
target.height = extended_area;
break;
default:
/* not reached */
assert(false);
/* suppress warnings with NDEBUG */
target = (struct wlr_box){0};
}
resize_extent_within_usable(ssd->extents.top, &usable,
0, 0,
full_width + extended_area * 2, extended_area);
resize_extent_within_usable(ssd->extents.left, &usable,
0, extended_area,
extended_area, full_height);
resize_extent_within_usable(ssd->extents.right, &usable,
extended_area + full_width, extended_area,
extended_area, full_height);
resize_extent_within_usable(ssd->extents.bottom, &usable,
0, extended_area + full_height,
full_width + extended_area * 2, extended_area);
resize_extent_within_usable(rect, &usable,
target.x, target.y, target.width, target.height);
}
pixman_region32_fini(&usable);
}
@ -198,7 +159,6 @@ ssd_extents_destroy(struct ssd *ssd)
return;
}
ssd_destroy_parts(&ssd->extents.parts);
wlr_scene_node_destroy(&ssd->extents.tree->node);
ssd->extents.tree = NULL;
ssd->extents = (struct ssd_extents_scene){0};
}