labwc/src/ssd/ssd.c

467 lines
12 KiB
C
Raw Normal View History

2022-02-21 03:18:38 +01:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Helpers for view server side decorations
*
* Copyright (C) Johan Malm 2020-2021
*/
#include <assert.h>
2024-04-20 06:29:51 +02:00
#include <strings.h>
#include <wlr/types/wlr_scene.h>
#include "common/mem.h"
#include "common/scene-helpers.h"
2025-08-17 16:01:50 -04:00
#include "config/rcxml.h"
#include "labwc.h"
#include "ssd-internal.h"
#include "theme.h"
#include "view.h"
2022-02-21 03:18:38 +01:00
struct border
ssd_thickness(struct view *view)
{
assert(view);
/*
* Check preconditions for displaying SSD. Note that this
* needs to work even before ssd_create() has been called.
*
* For that reason we are not using the .enabled state of
* the titlebar node here but rather check for the view
* boolean. If we were to use the .enabled state this would
* cause issues on Reconfigure events with views which were
* in border-only deco mode as view->ssd would only be set
* after ssd_create() returns.
*/
if (!view->ssd_mode || view->fullscreen) {
return (struct border){ 0 };
}
2022-02-21 03:18:38 +01:00
struct theme *theme = view->server->theme;
if (view->maximized == VIEW_AXIS_BOTH) {
struct border thickness = { 0 };
if (view_titlebar_visible(view)) {
thickness.top += theme->titlebar_height;
}
return thickness;
}
struct border thickness = {
.top = theme->titlebar_height + theme->border_width,
.right = theme->border_width,
2022-02-21 03:18:38 +01:00
.bottom = theme->border_width,
.left = theme->border_width,
};
if (!view_titlebar_visible(view)) {
thickness.top -= theme->titlebar_height;
}
return thickness;
2022-02-21 03:18:38 +01:00
}
struct wlr_box
ssd_max_extents(struct view *view)
{
assert(view);
2022-02-21 03:18:38 +01:00
struct border border = ssd_thickness(view);
int eff_width = view->current.width;
int eff_height = view_effective_height(view, /* use_pending */ false);
return (struct wlr_box){
.x = view->current.x - border.left,
.y = view->current.y - border.top,
.width = eff_width + border.left + border.right,
.height = eff_height + border.top + border.bottom,
2022-02-21 03:18:38 +01:00
};
}
/*
* Resizing and mouse contexts like 'Left', 'TLCorner', etc. in the vicinity of
* SSD borders, titlebars and extents can have effective "corner regions" that
* behave differently from single-edge contexts.
*
* Corner regions are active whenever the cursor is within a prescribed size
* (generally rc.resize_corner_range, but clipped to view size) of the view
* bounds, so check the cursor against the view here.
*/
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`.
2025-08-13 21:00:11 +09:00
enum ssd_part_type
ssd_get_resizing_type(const struct ssd *ssd, struct wlr_cursor *cursor)
{
struct view *view = ssd ? ssd->view : NULL;
if (!view || !cursor || !view->ssd_mode || view->fullscreen) {
return LAB_SSD_NONE;
}
struct wlr_box view_box = view->current;
view_box.height = view_effective_height(view, /* use_pending */ false);
if (view_titlebar_visible(view)) {
/* If the titlebar is visible, consider it part of the view */
int titlebar_height = view->server->theme->titlebar_height;
view_box.y -= titlebar_height;
view_box.height += titlebar_height;
}
if (wlr_box_contains_point(&view_box, cursor->x, cursor->y)) {
/* A cursor in bounds of the view is never in an SSD context */
return LAB_SSD_NONE;
}
int corner_height = MAX(0, MIN(rc.resize_corner_range, view_box.height / 2));
int corner_width = MAX(0, MIN(rc.resize_corner_range, view_box.width / 2));
bool left = cursor->x < view_box.x + corner_width;
bool right = cursor->x > view_box.x + view_box.width - corner_width;
bool top = cursor->y < view_box.y + corner_height;
bool bottom = cursor->y > view_box.y + view_box.height - corner_height;
if (top && left) {
return LAB_SSD_PART_CORNER_TOP_LEFT;
} else if (top && right) {
return LAB_SSD_PART_CORNER_TOP_RIGHT;
} else if (bottom && left) {
return LAB_SSD_PART_CORNER_BOTTOM_LEFT;
} else if (bottom && right) {
return LAB_SSD_PART_CORNER_BOTTOM_RIGHT;
} else if (top) {
return LAB_SSD_PART_TOP;
} else if (bottom) {
return LAB_SSD_PART_BOTTOM;
} else if (left) {
return LAB_SSD_PART_LEFT;
} else if (right) {
return LAB_SSD_PART_RIGHT;
}
return LAB_SSD_NONE;
}
enum lab_edge
2022-02-21 03:18:38 +01:00
ssd_resize_edges(enum ssd_part_type type)
{
switch (type) {
case LAB_SSD_PART_TOP:
return LAB_EDGE_TOP;
2022-02-21 03:18:38 +01:00
case LAB_SSD_PART_RIGHT:
return LAB_EDGE_RIGHT;
2022-02-21 03:18:38 +01:00
case LAB_SSD_PART_BOTTOM:
return LAB_EDGE_BOTTOM;
2022-02-21 03:18:38 +01:00
case LAB_SSD_PART_LEFT:
return LAB_EDGE_LEFT;
2022-02-21 03:18:38 +01:00
case LAB_SSD_PART_CORNER_TOP_LEFT:
return LAB_EDGES_TOP_LEFT;
2022-02-21 03:18:38 +01:00
case LAB_SSD_PART_CORNER_TOP_RIGHT:
return LAB_EDGES_TOP_RIGHT;
2022-02-21 03:18:38 +01:00
case LAB_SSD_PART_CORNER_BOTTOM_RIGHT:
return LAB_EDGES_BOTTOM_RIGHT;
2022-02-21 03:18:38 +01:00
case LAB_SSD_PART_CORNER_BOTTOM_LEFT:
return LAB_EDGES_BOTTOM_LEFT;
2022-02-21 03:18:38 +01:00
default:
return LAB_EDGE_NONE;
2022-02-21 03:18:38 +01:00
}
}
struct ssd *
ssd_create(struct view *view, bool active)
2022-02-21 03:18:38 +01:00
{
assert(view);
struct ssd *ssd = znew(*ssd);
2022-02-21 03:18:38 +01:00
ssd->view = view;
ssd->tree = wlr_scene_tree_create(view->scene_tree);
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`.
2025-08-13 21:00:11 +09:00
attach_ssd_part(LAB_SSD_NONE, view, &ssd->tree->node);
wlr_scene_node_lower_to_bottom(&ssd->tree->node);
ssd->titlebar.height = view->server->theme->titlebar_height;
ssd_shadow_create(ssd);
ssd_extents_create(ssd);
/*
* We need to create the borders after the titlebar because it sets
* ssd->state.squared which ssd_border_create() reacts to.
* TODO: Set the state here instead so the order does not matter
* anymore.
*/
ssd_titlebar_create(ssd);
ssd_border_create(ssd);
if (!view_titlebar_visible(view)) {
/* Ensure we keep the old state on Reconfigure or when exiting fullscreen */
ssd_set_titlebar(ssd, false);
}
ssd->margin = ssd_thickness(view);
ssd_set_active(ssd, active);
2023-03-05 10:35:56 +01:00
ssd_enable_keybind_inhibit_indicator(ssd, view->inhibits_keybinds);
ssd->state.geometry = view->current;
return ssd;
}
struct border
ssd_get_margin(const struct ssd *ssd)
{
return ssd ? ssd->margin : (struct border){ 0 };
2022-02-21 03:18:38 +01:00
}
int
ssd_get_corner_width(void)
{
/* ensure a minimum corner width */
return MAX(rc.corner_radius, 5);
}
void
ssd_update_margin(struct ssd *ssd)
{
if (!ssd) {
return;
}
ssd->margin = ssd_thickness(ssd->view);
}
2022-02-21 03:18:38 +01:00
void
ssd_update_geometry(struct ssd *ssd)
2022-02-21 03:18:38 +01:00
{
if (!ssd) {
2022-02-21 03:18:38 +01:00
return;
}
2024-08-23 12:45:14 -04:00
struct view *view = ssd->view;
assert(view);
struct wlr_box cached = ssd->state.geometry;
2024-08-23 12:45:14 -04:00
struct wlr_box current = view->current;
int eff_width = current.width;
2024-08-23 12:45:14 -04:00
int eff_height = view_effective_height(view, /* use_pending */ false);
2024-08-23 12:45:14 -04:00
bool update_area = eff_width != cached.width || eff_height != cached.height;
bool update_extents = update_area
|| current.x != cached.x || current.y != cached.y;
bool maximized = view->maximized == VIEW_AXIS_BOTH;
bool squared = ssd_should_be_squared(ssd);
2024-08-23 12:45:14 -04:00
bool state_changed = ssd->state.was_maximized != maximized
|| ssd->state.was_shaded != view->shaded
|| ssd->state.was_squared != squared
2024-08-23 12:45:14 -04:00
|| ssd->state.was_omnipresent != view->visible_on_all_workspaces;
/*
* (Un)maximization updates titlebar visibility with
* maximizedDecoration=none
*/
ssd_set_titlebar(ssd, view_titlebar_visible(view));
2024-08-23 12:45:14 -04:00
if (update_extents) {
ssd_extents_update(ssd);
}
if (update_area || state_changed) {
ssd_titlebar_update(ssd);
ssd_border_update(ssd);
ssd_shadow_update(ssd);
}
if (update_extents) {
ssd->state.geometry = current;
2022-02-21 03:18:38 +01:00
}
}
void
ssd_set_titlebar(struct ssd *ssd, bool enabled)
{
if (!ssd || ssd->titlebar.tree->node.enabled == enabled) {
return;
}
wlr_scene_node_set_enabled(&ssd->titlebar.tree->node, enabled);
ssd->titlebar.height = enabled ? ssd->view->server->theme->titlebar_height : 0;
ssd_border_update(ssd);
ssd_extents_update(ssd);
ssd_shadow_update(ssd);
ssd->margin = ssd_thickness(ssd->view);
}
2022-02-21 03:18:38 +01:00
void
ssd_destroy(struct ssd *ssd)
2022-02-21 03:18:38 +01:00
{
if (!ssd) {
2022-02-21 03:18:38 +01:00
return;
}
/* Maybe reset hover view */
struct view *view = ssd->view;
2022-02-21 03:18:38 +01:00
struct ssd_hover_state *hover_state;
hover_state = view->server->ssd_hover_state;
2022-02-21 03:18:38 +01:00
if (hover_state->view == view) {
hover_state->view = NULL;
hover_state->button = NULL;
2022-02-21 03:18:38 +01:00
}
/* Destroy subcomponents */
ssd_titlebar_destroy(ssd);
ssd_border_destroy(ssd);
ssd_extents_destroy(ssd);
ssd_shadow_destroy(ssd);
wlr_scene_node_destroy(&ssd->tree->node);
free(ssd);
2022-02-21 03:18:38 +01:00
}
bool
ssd_part_contains(enum ssd_part_type whole, enum ssd_part_type candidate)
{
2024-05-01 07:28:17 +01:00
if (whole == candidate || whole == LAB_SSD_ALL) {
2022-02-21 03:18:38 +01:00
return true;
}
if (whole == LAB_SSD_BUTTON) {
return candidate >= LAB_SSD_BUTTON_CLOSE
&& candidate <= LAB_SSD_BUTTON_OMNIPRESENT;
}
2022-02-21 03:18:38 +01:00
if (whole == LAB_SSD_PART_TITLEBAR) {
return candidate >= LAB_SSD_BUTTON_CLOSE
&& candidate <= LAB_SSD_PART_TITLE;
}
if (whole == LAB_SSD_PART_TITLE) {
/* "Title" includes blank areas of "Titlebar" as well */
return candidate >= LAB_SSD_PART_TITLEBAR
&& candidate <= LAB_SSD_PART_TITLE;
}
2022-02-21 03:18:38 +01:00
if (whole == LAB_SSD_FRAME) {
return candidate >= LAB_SSD_BUTTON_CLOSE
&& candidate <= LAB_SSD_CLIENT;
}
if (whole == LAB_SSD_PART_TOP) {
return candidate == LAB_SSD_PART_CORNER_TOP_LEFT
|| candidate == LAB_SSD_PART_CORNER_TOP_RIGHT;
2022-02-21 03:18:38 +01:00
}
if (whole == LAB_SSD_PART_RIGHT) {
return candidate == LAB_SSD_PART_CORNER_TOP_RIGHT
|| candidate == LAB_SSD_PART_CORNER_BOTTOM_RIGHT;
}
if (whole == LAB_SSD_PART_BOTTOM) {
return candidate == LAB_SSD_PART_CORNER_BOTTOM_RIGHT
|| candidate == LAB_SSD_PART_CORNER_BOTTOM_LEFT;
}
if (whole == LAB_SSD_PART_LEFT) {
return candidate == LAB_SSD_PART_CORNER_TOP_LEFT
|| candidate == LAB_SSD_PART_CORNER_BOTTOM_LEFT;
}
return false;
}
2025-08-17 16:01:50 -04:00
enum lab_ssd_mode
2024-04-20 06:29:51 +02:00
ssd_mode_parse(const char *mode)
{
if (!mode) {
return LAB_SSD_MODE_INVALID;
2024-04-20 06:29:51 +02:00
}
if (!strcasecmp(mode, "none")) {
return LAB_SSD_MODE_NONE;
} else if (!strcasecmp(mode, "border")) {
return LAB_SSD_MODE_BORDER;
} else if (!strcasecmp(mode, "full")) {
2024-04-20 06:29:51 +02:00
return LAB_SSD_MODE_FULL;
} else {
return LAB_SSD_MODE_INVALID;
2024-04-20 06:29:51 +02:00
}
}
2022-02-21 03:18:38 +01:00
void
ssd_set_active(struct ssd *ssd, bool active)
2022-02-21 03:18:38 +01:00
{
if (!ssd) {
2022-02-21 03:18:38 +01:00
return;
}
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`.
2025-08-13 21:00:11 +09:00
enum ssd_active_state active_state;
FOR_EACH_ACTIVE_STATE(active_state) {
wlr_scene_node_set_enabled(
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`.
2025-08-13 21:00:11 +09:00
&ssd->border.subtrees[active_state].tree->node,
active == active_state);
wlr_scene_node_set_enabled(
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`.
2025-08-13 21:00:11 +09:00
&ssd->titlebar.subtrees[active_state].tree->node,
active == active_state);
if (ssd->shadow.subtrees[active_state].tree) {
wlr_scene_node_set_enabled(
&ssd->shadow.subtrees[active_state].tree->node,
active == active_state);
}
}
2022-02-21 03:18:38 +01:00
}
2022-11-26 16:13:09 -05:00
void
ssd_enable_shade(struct ssd *ssd, bool enable)
{
if (!ssd) {
return;
}
2024-08-22 16:27:24 -04:00
ssd_titlebar_update(ssd);
ssd_border_update(ssd);
wlr_scene_node_set_enabled(&ssd->extents.tree->node, !enable);
ssd_shadow_update(ssd);
}
2023-03-05 10:35:56 +01:00
void
ssd_enable_keybind_inhibit_indicator(struct ssd *ssd, bool enable)
{
if (!ssd) {
return;
}
float *color = enable
? rc.theme->window_toggled_keybinds_color
: rc.theme->window[THEME_ACTIVE].border_color;
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`.
2025-08-13 21:00:11 +09:00
wlr_scene_rect_set_color(ssd->border.subtrees[SSD_ACTIVE].top, color);
2023-03-05 10:35:56 +01:00
}
struct ssd_hover_state *
ssd_hover_state_new(void)
{
return znew(struct ssd_hover_state);
}
enum ssd_part_type
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`.
2025-08-13 21:00:11 +09:00
ssd_part_get_type(const struct ssd_part *part)
{
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`.
2025-08-13 21:00:11 +09:00
return part ? part->type : LAB_SSD_NONE;
}
struct view *
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`.
2025-08-13 21:00:11 +09:00
ssd_part_get_view(const struct ssd_part *part)
{
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`.
2025-08-13 21:00:11 +09:00
return part ? part->view : NULL;
}
2022-11-26 16:13:09 -05:00
bool
ssd_debug_is_root_node(const struct ssd *ssd, struct wlr_scene_node *node)
{
if (!ssd || !node) {
2022-11-26 16:13:09 -05:00
return false;
}
return node == &ssd->tree->node;
}
const char *
ssd_debug_get_node_name(const struct ssd *ssd, struct wlr_scene_node *node)
{
if (!ssd || !node) {
2022-11-26 16:13:09 -05:00
return NULL;
}
if (node == &ssd->tree->node) {
return "view->ssd";
}
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`.
2025-08-13 21:00:11 +09:00
if (node == &ssd->titlebar.subtrees[SSD_ACTIVE].tree->node) {
2022-11-26 16:13:09 -05:00
return "titlebar.active";
}
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`.
2025-08-13 21:00:11 +09:00
if (node == &ssd->titlebar.subtrees[SSD_INACTIVE].tree->node) {
2022-11-26 16:13:09 -05:00
return "titlebar.inactive";
}
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`.
2025-08-13 21:00:11 +09:00
if (node == &ssd->border.subtrees[SSD_ACTIVE].tree->node) {
2022-11-26 16:13:09 -05:00
return "border.active";
}
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`.
2025-08-13 21:00:11 +09:00
if (node == &ssd->border.subtrees[SSD_INACTIVE].tree->node) {
2022-11-26 16:13:09 -05:00
return "border.inactive";
}
if (node == &ssd->extents.tree->node) {
return "extents";
}
return NULL;
}